Search code examples
iossprite-kitgameplay-kit

GKComponentSystem has no components on update cycle


I’m playing around with SpriteKit and GameplayKit. But when I run my code, the sprite I’m expecting to wander around, does nothing.

I used lldb to print out some values, this is the print out:

(lldb) po agentSystem.components
▿ 1 elements
  - [0] : <GKAgent2D: 0x7fc1b8e55ff0>

(lldb) po agentSystem.components
0 elements

The first is printed just after addComponentWithEntity: is called. The second is printed in the update: method.

Of course this must be the reason the sprite does not wander, but what could be causing the problem?

I’ve even looked at and used code from Apple’s sample code for Agents but that still doesn’t seem to fix the issue.

Here is my scene’s code:

import SpriteKit
import GameplayKit

class GameScene: SKScene
{
    //  MARK: - Properties

    let agentSystem = GKComponentSystem(componentClass: GKAgent2D.self)

    var lastUpdateTimeInterval: CFTimeInterval = 0.0


    //  MARK: - Scene Lifecycle

    override func didMoveToView(view: SKView)
    {
        //  Wave enemy
        let agent = GKAgent2D()
        agent.behavior = GKBehavior(goal: GKGoal(toWander: 10), weight: 100)

        let waveEnemy = WaveEnemy()
        waveEnemy.addComponent(agent)

        agentSystem.addComponentWithEntity(waveEnemy)

        let waveSprite = waveEnemy.componentForClass(VisualComponent)!.spriteNode
        waveSprite.position = CGPoint(x: frame.size.width * 0.5, y: frame.size.height * 0.5)

        addChild(waveSprite)
    }

    override func update(currentTime: CFTimeInterval)
    {
        if lastUpdateTimeInterval == 0
        {
            lastUpdateTimeInterval = currentTime
        }

        let deltaTime: CFTimeInterval = currentTime - lastUpdateTimeInterval
        lastUpdateTimeInterval = currentTime

        //  Update component system
        agentSystem.updateWithDeltaTime(deltaTime)
    }
}

Solution

  • I had a similar issue. Turns out my GKEntity had a weak reference to it which caused it to automatically get removed from the GKComponentSystem.

    In your case you're creating waveEnemy which needs to be held on to. You can store it in an array on the scene.

    class GameScene: SKScene {
    
        ...
    
        var enemies = [GKEntity]()
    
        override func didMoveToView(view: SKView) {
            ...
            let waveEnemy = WaveEnemy()
            waveEnemy.addComponent(agent)
            enemies.append(waveEnemy) // Creates a strong reference for waveEnemy
            ...
        }
    
        ...
    
    }