Looping through all objects/sprites in a scene - swift

Is it possible to loop through all the objects contained in a scene when the override function "didMoveToView" is called? In context, I'm trying to check all the objects to see if one of them has the name "planet1" then make it orbit around a given point.

if you need to loop through all the nodes just use
enumerateChildNodesWithName("//*", usingBlock:
{ (node, stop) -> Void in
if node.name=="planet1" {
//make it orbit
}
})
in the name string // means search the entire node tree, not just this node's children.
* is wildcard and matches any name, you can use "xxx*" to match any name starting with xxx and the same for "*xxx" to match any name ending in xxx
EDIT: you can just do:
planet1=self.childNodeWithName("//planet1")!

Just loop through all of the parent view's subviews.
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
for sibling in view.subviews {
// check sibling view
}
}
Note that at least one of the objects in the loop will be equal to self. Also note that they'll all have a type of AnyObject. So you'll have to downcast. If your view named "planet1" is a particular class though:
for sibling in view.subviews {
if let planet = sibling as? PlanetSprite {
if planet.name == "planet1" {
// do stuff
}
}
}
This might be about what you're looking for.

Related

Specify Z-order of lines

I plot an unknown number of series. For sake of explanation, assume that there are three; a, b and c.
This leads the issue with the first serie a to be "hidden" behind the other series. This is most noticeable when then each have different colors assigned. I could plot them in the reverse order (beginning with c), but then the legend would be in reverse as well.
Is there a way to specify that a should be on top of b and b on top of c?
I'm not sure what exactly chart you are using. But for example for LineChartView you can define your custom renderer as a descendant of LineChartRenderer class and override some functions e.g. drawData. In fact, you can just copy this function to your class and change only the drawing order of data sets.
class MyCustomRenderer: LineChartRenderer {
// I define my custom initializer for convenience
init(for chart: LineChartView) {
super.init(dataProvider: chart, animator: chart.chartAnimator, viewPortHandler: chart.viewPortHandler)
}
init(view: LineChartView) {
super.init(dataProvider: view, animator: view.chartAnimator, viewPortHandler: view.viewPortHandler)
}
override func drawData(context: CGContext)
{
guard let lineData = dataProvider?.lineData else { return }
// Here you can change the drawing order !
for i in 0 ..< lineData.dataSetCount
{
guard let set = lineData.getDataSetByIndex(i) else { continue }
if set.isVisible
{
if !(set is ILineChartDataSet)
{
fatalError("Datasets for LineChartRenderer must conform to ILineChartDataSet")
}
drawDataSet(context: context, dataSet: set as! ILineChartDataSet)
}
}
}
}
And setup you render for your chart using renderer property.
myLineChartView.renderer = MyCustomRenderer(for: myLineChartView)

How to make child node follow parent node in Swift 4.2 SpriteKit

I want to make it so that a child sprite follows its corresponding parent sprite. The child sprite has a physics body which should not mess with the parent's physics body. I have tried to in the parent sprite's subclass to override these functions like this:
public override func run(_ action: SKAction) {
super.run(action)
physicsSprite.run(action)
}
public override func run(_ action: SKAction, withKey key: String) {
super.run(action, withKey: key)
physicsSprite.run(action, withKey: key)
}
public override func removeAllActions() {
super.removeAllActions()
physicsSprite.removeAllActions()
}
with no success however :(
I'am exclusively moving the parent sprite with SKActions.
The result is that the sprites don't stick together.
physicsSprite.zPosition = 10
physicsSprite.physicsBody = SKPhysicsBody(circleOfRadius: playerInfo.width+2)
physicsSprite.physicsBody?.affectedByGravity = false
physicsSprite.physicsBody?.isDynamic = false
physicsSprite.physicsBody?.restitution = 0
physicsSprite.physicsBody?.collisionBitMask = 0
addChild(physicsSprite)
In this case physicsSprite is the childNode in a SKSpriteNode subclass. Thanks in advance
You could try to use an SKConstraint object, that describes a mathematical constraint on a node's position or orientation.
From the docs:
Keep a node within a specified distance of another node or a point in the scene.
See https://developer.apple.com/documentation/spritekit/skconstraint
Try this:
parentSprite.physicsBody?.categoryBitMask = 0
parentSprite.physicsBody?.collisionBitMask = 0
physicsSprite.physicsBody?.collisionBitMask = 1
physicsSprite.physicsBody?.categoryBitMask = 1
For more information check documentation

How to Remove an Entity form a SKScene

Components of entities can be removed with:
entity.removeComponentForClass(SpriteComponent.self);
entity.removeComponentForClass(PhysicsComponent.self);
How are Entities removed from a SKScene?
There are plenty of tutorials about removing components, but I can't find anything explicit about removing entities. Is there something like removing a node?
node.removeFromParent();
I adapted this from Apple's DemoBots which contains samples for the RenderComponent and LayerConfiguration.
Array was extended using Swift solution here >> Array extension to remove object by value
var entities = [GKEntity]()
/// Stores a reference to the root nodes for each world layer in the scene.
var layerNodes = [LayerConfiguration:SKNode]()
func addEntity(entity: GKEntity)
{
self.entities.append(entity)
for componentSystem in self.componentSystems
{
componentSystem.addComponent(foundIn: entity)
}
// If the entity has a `RenderComponent`, add its node to the scene.
if let renderNode = entity.component(ofType: RenderComponent.self)?.node
{
self.addNode(node: renderNode, toLayer: .actors)
}
}
func removeEntity(entity:GKEntity)
{
for componentSystem in self.componentSystems
{
componentSystem.removeComponent(foundIn: entity)
}
if let renderNode = entity.component(ofType: RenderComponent.self)?.node
{
renderNode.removeFromParent()
}
self.entities.remove(entity)
}
func addNode(node: SKNode, toLayer layer: LayerConfiguration)
{
//
let layerNode = self.layerNodes[layer]!
layerNode.addChild(node)
}

Wait until property is true before continuing loop

Trying to do something I feel like should be simple but nothing I've tried so far works. I'm trying to prevent this loop from continuing until a property on my enemy is set to true.
My enemy node figures out a path to the player during the walk state. I don't want to iterate to the next enemy until the path has been calculated. My enemy node has a pathComplete node I set to true during the walk state.
This is executed on touch.
for node:AnyObject in self.children {
if node is EnemyNode {
let enemy = node as! EnemyNode
enemy.destination = coordinate
enemy.stateMachine.enterState(WalkingState)
}
}
If I understand what you want to do, then you should use the recursion instead the loop.
First you need to create some enemyNodeArray that will be contains objects you need.
Then you can make two functions like this:
func actionForObjectWithIndex(index: Int, completion block: (nextIndex: Int) -> Void) {
guard index >= 0 && index < enemyNodeArray.count else {
return
}
// do what you need with object in array like enemyNodeArray[index]...
...
// Then call completion
block(nextIndex: index + 1)
}
func makeActionWithIndex(index: Int) {
actionForObjectWithIndex(index, completion: {(nextIndex: Int) -> Void in
self.makeActionWithIndex(nextIndex)
})
}
and start use it like this:
if !enemyNodeArray.isEmpty {
makeActionWithIndex(0)
}
This algorithm will be take every object in an array, and perform certain actions with them, and it will move to the next item only after it has finished with the previous.

Subclass of GKGraphNode costToNode method never getting called

I am trying to subclass GKGraphNode2D to also include different penalties for different terrains (in the costToNode method). When I create a new GKGraph with an array of my new subclass and call findPathFromNode on the GKGraph, it ignores my costToNode method entirely.
The code looks like:
public class PenaltyGraphNode: GKGraphNode2D {
public let penalty: Float
init(position: CGPoint, penalty: Float) {
self.penalty = penalty
let point = vector_float2(Float(position.x), Float(position.y))
super.init(point: point)
}
override public func costToNode(node: GKGraphNode) -> Float {
guard let penaltyNode = node as? PenaltyGraphNode else { return super.costToNode(node) }
return super.costToNode(node) * (1 + penaltyNode.penalty)
}
}
And where I am trying to use the GKGraph (node creation removed for brevity sake):
let penaltyNodes: [PenaltyGraphNode] = [penaltyNode1, penaltyNode2, ...]
let graph = GKGraph(nodes: penaltyNodes)
let path = graph.findPathFromNode(startNode, toNode: endNode) as? [PenaltyGraphNode]
The costToNode in my subclass is never getting called, I made sure that all of the nodes that I create in the graph and add to it later are all PenaltyGraphNodes, but it still won't call costToNode. When I print the graph's nodes property, it shows them as GKGraphNode2D objects only, not my subclass.
Am I missing something obvious here?