Kodeco Forums

GameplayKit Tutorial: Entity-Component System, Agents, Goals, and Behaviors

In this GameplayKit tutorial, you'll learn how to implement a clean architecture for your game with GameplayKit's powerful Entity-Component system.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/1511-gameplaykit-tutorial-entity-component-system-agents-goals-and-behaviors

Great tutorial, thanks!

Excellent tutorial I ran into an issue which I thought I post here incase anyone else encounters:

This is in AiComponent when choosing a random monster:

Int(arc4random()) % MonsterType.allValues.count <== Thread 1: EXC_BREAKPOINT (code=EXC_ARM_BREAKPOINT,subcode=0xe7ffdefe)

Think its due to arc4random returning a -ve number on occasion, causing the game to crash.
I was able to fix it by using arc4random_uniform.

Int(arc4random_uniform(3)) % MonsterType.allValues.count

Working with GKAgent and GKBehavior, is it possible to stop the object at a distance? in this example agent will move to the center of the target.

Can someone please convert this line to objC, i’m having a hard time with it

guard let spriteComponent = entity?.componentForClass(SpriteComponent.self) else {
return
}

Just a matter of getting opinions on some points!

If you want to add/remove components at runtime, not only at the entity’s creation, how do you suggest to deal with that? Add helper methods to EntityManager and deal with the ComponentSystems from there?

Also is it possible to combine GKAgent2D for movement and physics body to detect contacts between sprites? maybe by creating a PhysicsBodyComponent and a ContactDelegateComponent or something


Anyway, any thought is welcome here :slight_smile:

thanks!

Cn you remove the following line from your tutorial


“If you want to learn more about GameplayKit, you should check out our book”

I bought the latest version book this week to try out GameplayKit based tutorials - but they have been removed
 to be added at some undisclosed location at an undisclosed time! Luckily it’s still a great book but I was really disappointed that the original reason for buying the book is no longer true.

I’m ready for a swift 3, Xcode 8 update! when’s it coming? :smiley:

There are definitely some problems here. Perhaps it’s iOS10?

I am running Xcode 8.2.1, downloaded yesterday. Thought it was time.

  1. Downloaded and opened the project. Got 10 errors, and the thing said it all needed to be updated to the latest Swift syntax. I have tried doing it manually, letting it go auto, and somewhere in between.

  2. By the time I get to the end of “Adding Your Castles,” I have 8 fatal errors:

Castle.swift:20:46: Incorrect argument label in call (have ‘texture:’, expected ‘coder:’)

    let spriteComponent = SpriteComponent(texture: SKTexture(imageNamed: imageName))

Castle.swift:23:1: ‘required’ initializer ‘init(coder:)’ must be provided by subclass of ‘GKEntity’
.
.
.
GameScene.swift:96:30: Value of type ‘Castle’ has no member ‘componentForClass’

if let spriteComponent = humanCastle.componentForClass(SpriteComponent.self) {

GameScene.swift:99:23: Missing argument label ‘entity:’ in call

entityManager.add(humanCastle)

GameScene.swift:103:30: Value of type ‘Castle’ has no member ‘componentForClass’

if let spriteComponent = aiCastle.componentForClass(SpriteComponent.self) {

GameScene.swift:106:23: Missing argument label ‘entity:’ in call

entityManager.add(aiCastle)

.
.
.
EntityManager.swift:28:29: Value of type ‘GKEntity’ has no member ‘componentForClass’

    if let spriteNode = entity.componentForClass(SpriteComponent.self)?.node {

EntityManager.swift:35:29: Value of type ‘GKEntity’ has no member ‘componentForClass’

    if let spriteNode = entity.componentForClass(SpriteComponent.self)?.node {

.
.
What do you suggest?

A few thing need changing in order to get this code up to date. I had the same fatal errors and found looking at the Apple documentation for GameplayKit Entities particularly helpful, most notably the Boxes demo

You will need to update the SpriteComponent init like so:

init(texture: SKTexture) {

    node = SKSpriteNode(texture: texture, color: SKColor.white, size: texture.size())
    
    super.init()
    
}

super.init() is required and it needs to follow our update to note else it complains.
Xcode should have already prompted you to add the missing required init, if it does simply double cluck the error popup and it will add it in automatically, if not after the closing curly brace of the init you added super.init() to add

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

The other thing that you will need to update is any call to entity.componentForClass( 
 )
this should now be written as entity.component(ofType: 
) e.g.

func add(entity: GKEntity) {
    entities.insert(entity)
    
    if let spriteNode = entity.component(ofType:   SpriteComponent.self)?.node {
        scene.addChild(spriteNode)
    }
}

Also in GameScene when calling entityManager.add(humanCastle) you will need to include entity: in the functions parameters like so:

entityManager.add(entity: humanCastle)

Hopefully that should get you to the first build stage, I’ve not gotten any further through the tutorial myself but I successfully built and ran the tutorial with these amendments. Hope that helps, Good luck.