0

So im currently working on a game with spriteKit and gameplayKit. I've created a custom GKComponent class that I'm giving to certain SKSpriteNode via the scene inspector in Xcode (image). Now, when I want to re-create random SKSpritenodes with the same GKComponent, it doesn't seems to work because the overridden update method of my custom GKComponent is not working. Any clues?

I've tried to give the node a new entity object (since it was returning nil) and I gave that entity my custom GKComponent but nothing is working

// In scene                
let node = SKSpriteNode(texture: "coin", color: UIColor.clear, size: CGSize(width: 60, height: 60))
let entities: GKEntity! = GKEntity()
let component: CollectableComponent = CollectableComponent()
component.itemType = 1

node.anchorPoint = CGPoint(x: 0.5, y: 0.5)
node.zPosition = 6
node.setScale(0.5)
node.size = CGSize(width: 60, height: 60)
node.position = CGPoint(x: 90, y: 90)
entities.addComponent(component)
node.entity = entities
self.scene?.addChild(node)


// GKComponent

class CustomComponent: GKComponent {
    var node: SKSpriteNode?

    @GKInspectable var itemType: Int = 0
    @GKInspectable var isStatic: Bool = false

    override init() {
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func update(deltaTime seconds: TimeInterval) {
        if node == nil {
            if let nodeComponent = self.entity?.component(ofType: GKSKNodeComponent.self){
                node = nodeComponent.node as? SKSpriteNode
            }
        }
    }
}

Desired behaviour: if the nodeComponent variable in CustomComponent is not nil, I would like to make it run an animation like this:

node = nodeComponent.node as? SKSpriteNode; node.run(SKAction.moveBy(x: 0, y: 15, duration: 0.3));

but with the code, the action would not be running

Marwen Doukh
  • 1,946
  • 17
  • 26
Sash
  • 28
  • 1
  • 6
  • What do yuo mean by "but nothing is working". What is the expected behavious? – Olympiloutre Jul 16 '19 at 01:06
  • Well let say that normally if the nodeComponent variable in CustomComponent is not nil, I would like to make it run an animation like this: node = nodeComponent.node as? SKSpriteNode; node.run(SKAction.moveBy(x: 0, y: 15, duration: 0.3)); // With the code, the action would not be running – Sash Jul 16 '19 at 01:10
  • Nothing is mapped..... You create a component, and you create a node, but at no point do you ever link the two together (You probably just want to create a copy of the node on the scene instead of creating new instances of things) – Knight0fDragon Jul 16 '19 at 13:46
  • I created a node, a gkentity and a component instance since the node has no entity that can receive my component. I then add the component to the entity I created and after that give that entity to my node. This is how they are all linked together. The custom component is here even when I print the attributes of my node but yet the init() method is called but not the update one – Sash Jul 16 '19 at 17:58
  • `node.entity` is a weak reference, so it is vanishing on you once you leave set up. No map ever happens – Knight0fDragon Jul 16 '19 at 19:57
  • btw, using update to set your node is a terrible idea. You do not want to constantly be doing that check. Make node a lazy variable, and the first time you go to access it, it will grab the node from the GKSKNodeComponent. Also, `GKSKNodeComponent` is not given to you for free either unless you are using the builder. – Knight0fDragon Jul 16 '19 at 20:02

1 Answers1

2

This is the way you want to be doing this.

Take note that you need to retain your entities, so a global variable is needed.

Also, when you add a node to GKSKNodeComponent, the node.entity variable is set automatically.

class GameScene : SKScene{
    var entities: [GKEntity] = [GKEntity]()

    func doSomething(){


        let node = SKSpriteNode(texture: "coin", color: UIColor.clear, size: CGSize(width: 60, height: 60))
        node.anchorPoint = CGPoint(x: 0.5, y: 0.5)
node.zPosition = 6
        node.setScale(0.5) //<--- YUCK!!!!!
        node.size = CGSize(width: 60, height: 60)
        node.position = CGPoint(x: 90, y: 90)
        self.scene?.addChild(node)

        let entity = GKEntity()
        let nodeComponent : GKSKNodeComponent = GKSKNodeComponent(node:node)
        let component: CollectableComponent = CollectableComponent()
        component.itemType = 1
        entity.addComponent(nodeComponent)
        entity.addComponent(component)
        entities.append(entity)

    }
}

// GKComponent

class CustomComponent: GKComponent {
    //We want this line to crash if node is empty, so do not use ?
    lazy var node: SKSpriteNode! = {return self.entity!.component(ofType: GKSKNodeComponent.self).node as? SKSpriteNode! }

    @GKInspectable var itemType: Int = 0
    @GKInspectable var isStatic: Bool = false

    override init() {
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func update(deltaTime seconds: TimeInterval) {

    }
}
Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • Thank you for your answer! I just started using the components so there was things that I wasn't aware of. You solved my issue, im really thankful! Thanks for the advices – Sash Jul 16 '19 at 22:17