Youssef Sami Youssef Sami - 4 months ago 16
iOS Question

Updating SKNodes outside update() of scene

I was quite surprised that the update method in the SKScene class isn't actually inherited from SKNode. To me, it seems logical for all SKNodes to be able to update themselves (for instance to remove itself from the scene when it's no longer on display, among other things). I think this would help in making the instances separate independent entities (no dependencies, no unexpected behavior) If there is other logic behind keeping the updates in the scenes only, please explain.

So I'm wondering if it's worth using a timer (repeating with a 1/60 time interval) to add a custom update to my custom SKNodes (perhaps even an extension that will add this to all SKNodes). However, I imagine this will be quite memory intensive. So I would like to ask if there is some 'best practice' regarding this. Perhaps the timer would work if it fired at each frame rather forcing it to fire 60 times a second.

Answer

Absolutely DO NOT use a timer.

SpriteKit has a well defined update cycle and every kind of update (logic, physics, graphics) should happen into a well defined time frame.

If you really want to write the update logic inside your nodes then the best solution is creating your own update method and then manually invoking it from the GameScene.

Let's see a (possible) structured approach

The protocol

protocol Updatable: class {
    func update(currentTime: NSTimeInterval)
}

Making your sprite/node updatable

class Player: SKSpriteNode, Updatable {

    func update(currentTime: NSTimeInterval) {
        // your logic goes here
    }
}

Forwarding the updates from the scene to the nodes

class GameScene: SKScene {

    private var updatables = [Updatable]()

    override func didMoveToView(view: SKView) {
        let player = Player()
        updatables.append(player)
        self.addChild(player)
    }

    override func update(currentTime: NSTimeInterval) {
        updatables.forEach { $0.update(currentTime) }
    }
}

As you can see I am using an Array of Updatables. You should also take care of adding (or removing) new Updatables to the Array when they are added (or removed) to the scene graph.

While it's definitely possible searching the whole scene graph every frame it would be very bad by a performance point of view.

Is this the right way to go?

Personally I don't like writing this kind of code inside my subclasses of SKNode or SKSpriteNode.

I usually create a Logic class. This class is the ones that receives the update events from GameScene. It also receives other "logic events" like:

  1. gameStarted
  2. touchesBegan
  3. touchesEnded

This class contains the pure game logic of the game.

It is something like the Instruction Manual you can find into a board game and it is totally agnostic about the graphics representation of the game entities.

In an ideal scenario I would be able to extract the Logic class from my SpriteKit game and use it with another framework or even with a (non electronic) board game version of the same game.