CoderNinja
CoderNinja

Reputation: 571

How to control the speed of nodes in SpriteKit

I have a bunch of objects (SKNode) starting from the top of the screen 'falling' to the bottom via SKAction.move(to:duration:) and node.run(moveAction). In addition I have node in the center of the screen with its own physics body that can be dragged side to side with touch input. I can detect collisions fine, but I was wondering if there was a paradigm for 'pausing' all the objects while the center node is contact with any of the objects. Additionally, I want to able to move the center node while the other objects are 'paused' so I can move it out of the way and then let the objects resume their motion. I figured I could probably iterate through all the existing objects and set their isPaused property, but I am unsure how the app would know when the center node is no longer 'colliding' so I can toggle the property back.

Upvotes: 1

Views: 1092

Answers (2)

Knight0fDragon
Knight0fDragon

Reputation: 16827

Oh boy, things sure do get complicated. Every thing that Whirlwind says is correct, but to iterate through every node on the scene can become burdensome.

Instead, I recommend creating a special subclass for SKNode. Now this special class is needed due to a bug caused by apples framework

class UserPausableNode : SKNode
{
    public var userPaused = false
    {
        didSet
        {
            super.isPaused = userPaused
        }
    }
    override var isPaused : Bool
        {
        get
        {
            return userPaused
        }
        set
        {
            //Yes, do nothing here
        }
    }
}

The reason why we need to do this is because whenever isPaused is called, it iterates to all children and sets the child isPaused property.

This becomes a problem when scene pauses and unpauses, as it will change the pause state of the children, which we do not want to be doing.

This class prevents the isPaused variable from changing.

Now that this class exists, what we want to do is add it to the scene, and add all moving nodes to this new node.

Since all of the nodes are on this new node, all we need to do is set the userPaused to true, and this will stop all nodes.

Now make sure the node you are moving is not a part of this branch, it should be outside so that you could move it.

Example

class GameScene : SKScene
{
    var userBranch = UserPausableNode()

    func didMove(to view:SKView)
    { 
        self.addChild(userBranch)
        //generetedChildren are nodes that you create that you plan on pausing as a group 
        for generatedChild in generatedChildren
        {
            userBranch.addChild(node)
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
       //this will pause and unpause based on opposite of previous state
        userBranch.userPaused = !userBranch.userPaused
    }

}

Upvotes: 1

Whirlwind
Whirlwind

Reputation: 13665

To pause things, you will have to detect the contact in didBegin() , tofill some array with nodes that should be paused and finally to pause the nodes. Actual pausing could be done in didSimulatePhysics() for example. To pause all the nodes you could use

 self.enumerateChildNodesWithName("aName") {
    node, stop in 
    // do something with node or stop
}

or use children property of a node and loop through it (eg. to loop through the container of your nodes that should be paused).

Also you can pause certain action with:

if let action = square.actionForKey("aKey") {

        action.speed = 0       
}

and unpause it with action.speed = 1, or make it slow-mo with action.speed = 0.5

To slow down physics simulation, there is a property called physicsWorld.speed (determines the rate at which the simulation runs).

Upvotes: 2

Related Questions