3

Whats the best way to pause a GKAgent?

My game uses a few agents in some levels and I need to pause them when my game is paused/gameOver.

I dont pause the whole SKScene in my game but rather a worldNode because it gives me more flexibility showing spriteKit stuff even when the game is paused.

I am using the

 updateWithDeltaTime...

methods to update my agents behaviour and move them accordingly.

I thought about stopping the update method but the agents will still move to their last known GKGoal.

The best solution I found so far is setting the agent speed/maxSpeed to 0 when my game is paused. The problem I have here is that upon resume its a bit of a pain to reset the speed to the agents previous speed especially when using multiple agents with their own behaviour. They also seem to disappear and than reappear upon resume.

There is no agent.paused method or something similar as far as I understand.

Whats a good way to pause an agent without pausing the SKScene itself?

Thanks for any help and suggestions.

crashoverride777
  • 10,581
  • 2
  • 32
  • 56
  • Have you tried to set someting inside agentDidUpdate? Something like if gameIsPaused jump and don't update node position? – Simone Pistecchia Feb 23 '16 at 17:03
  • Iwill give this a try. I have looked at apples demo bot sample and they stop all the updateWithDelta methods of the agents. I actually managed to do this too now but upon resume they make a massive jump, so the agents are still not paused properly. Thanks again – crashoverride777 Feb 24 '16 at 13:00
  • I've added a DeadState in my game, and I've the same problem, I tried to set agent.delegate = nil and self.removeComponentForClass but agentWillUpdate and updateWithDeltaTime (in my class MoveWanderAgent : GKAgent2D) still call. The only way i found is to check the state in updateWithDeltaTime: if stateMachine.currentState is DeadState { behavior = StopBehavoir() return }. I've increased your question – Simone Pistecchia Feb 27 '16 at 10:41
  • Yeah, exactly my problem. I'm still trying to reverse engineer DemoBots to see how Apple does it. There should be an agent.paused method. – crashoverride777 Feb 27 '16 at 12:24
  • There surely must be a better way than setting the the behaviour to not move – crashoverride777 Feb 27 '16 at 12:24

2 Answers2

1

I think I found a solution now that seems to work.

Firstly I am stoping the udapteDeltaMethods when the game is paused.

I than look through all my entities and set the agent delegate to nil

  for entity in baseScene.entityManager.entities {
        if let soldier = entity as? BossWorld3Soldiers {
            soldier.agentComponent.delegate = nil
        }
    }

Than when I resume my game I call this

  for entity in baseScene.entityManager.entities {
        if let soldier = entity as? BossWorld3Soldiers {
            let action1 = SKAction.waitForDuration(0.5)
            let action2 = SKAction.runBlock({ soldier.resetAgentDelegate() })
            baseScene.runAction(SKAction.sequence([action1, action2]))
        }
    }

The resetAgentDelegate() method is just a convenience method in my entities classes to reset the agent delegate

 func resetAgentDelegate() {
    self.agentComponent.delegate = self
 }

I am using a slight delay upon resume before resetting the agent delegate because without the delay the enties/agents seem to make a massive jump/dissappear for a few seconds before resuming their GKGoals.

crashoverride777
  • 10,581
  • 2
  • 32
  • 56
0

Do you have put the line if worldNode.paused { return } in update of your GameScene?

This works for me

GameScene:

override func update(currentTime: CFTimeInterval) {

        super.update(currentTime)

        // Don't perform any updates if the scene isn't in a view.
        guard view != nil else { return }

        let deltaTime = currentTime - lastUpdateTimeInterval
        lastUpdateTimeInterval = currentTime

        /*
        Don't evaluate any updates if the `worldNode` is paused.
        Pausing a subsection of the node tree allows the `camera`
        and `overlay` nodes to remain interactive.
        */
        if worldNode.paused { return }

        // Don't perform any updates if the scene isn't in a view.
        guard entityManagerGame != nil else { return }

        entityManagerGame.update(deltaTime)

    }
Simone Pistecchia
  • 2,746
  • 3
  • 18
  • 30
  • Yeah you can if you want, you just need to make sure to only call it when you want the game paused. I think setting the delegate to 0 might work. I'll let you know. Thanks – crashoverride777 Feb 27 '16 at 12:21
  • This is actually what Apple does in the update method in DemoBots. What's confusing me is even if you stop update the agent still will finish their last GKGoal. So I'm not sure what Apple does to pause it all – crashoverride777 Feb 27 '16 at 12:26
  • and if you put all your agent that you want to pause in a SKNode like AgentNode:SKNode and add this in your worldNode, you can pause only the AgentNode.paused. what do you think? – Simone Pistecchia Feb 27 '16 at 12:29
  • I don't know to be honest, I give it a try. My entities are already getting added to character Nodes which are added to the world node, which is why I thought agents should pause as well, but reading the documentation agents just do their own thing. I will check it out, and report back, thanks – crashoverride777 Feb 27 '16 at 12:36
  • I just found a way that seems to work, I just posted an answer. Hope this helps you too – crashoverride777 Feb 27 '16 at 12:54