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

In this GameplayKit tutorial, you will learn how to create flexible and scalable games by using the Entity-Component system with Agents, Goals and Behaviors. By Ryan Ackermann.

Leave a rating/review
Save for later
Share

Update 03/17/17: This tutorial has been updated for Xcode 8.2.1 and Swift 3. Original tutorial by Ray Wenderlich.

GameplayKit is an awesome framework introduced in iOS 9 that makes implementing many common tasks in your game much easier.

GameplayKit is a collection of tools that can help you with features like pathfinding, randomization, state machines, rule systems, and more.

In this GameplayKit tutorial, you’re going to focus on two parts of GameplayKit: its Entity-Component system, and Agents, Goals, and Behaviors.

These parts of GameplayKit help you organize your code in a different way that allows for more clean organization and code reuse, especially as your games become larger and more complex.

Let’s dive in!

Getting Started

In this GameplayKit tutorial, you will be working on a simple game called MonsterWars. Download the starter project, open it in Xcode, and build and run to check it out. You’ll see something like the following:

000_Starter

Right now, this game is just a shell with the UI elements added, but no gameplay. Here’s how the game will work:

  • You’ll get money every so often, which you can see in the upper left. You can use it to buy units by tapping the buttons at the bottom.
  • There are three enemy types: Quirk (fast and cheap), Zap (ranged attackers), and Munch (slow but has AOE chomp).
  • If your units destroy the enemy’s castle, you win!

Take a look at the code to see what’s there. Once you feel comfortable, read on to learn more about the main subject of this GameplayKit tutorial: its Entity-Component system.

What is an Entity-Component System?

Quite simply, an entity-component system is an architectural approach that enables your games to grow in size and complexity without increasing the interdependencies in your code.

This works by having 2 types of modular pieces:

  • Entities: An entity is a representation of an object in your game. The player, an enemy or a castle are good examples of entities. Since an entity is basically an object, you make this object perform interesting actions by applying components to it.
  • Components: A component contains the logic that performs a specific job on one entity, such as modifying its appearance or shooting a rocket. You make small components for each type of action your entities can do. For example, you might make a movement component, a health component, a melee attack component, and so on.

One of the best benefits of this system is that you can reuse components on as many entities as you want, allowing you to keep your code clean and organized.

Note: If you’re still itching for more on the theory side, check out this old tutorial Ray wrote several years ago where he rolled an entity-component system from scratch and compared it to a few other approaches.

Your First Component

To get started, let’s create a component to represent a sprite on the screen. In GameplayKit you create components by subclassing GKComponent.

To do this, select your MonsterWars group in the project navigator, right-click, select New Group, and name the group Components.

Then right-click the Components group, select New File.., select the iOS/Source/Swift File template, and click Next. Name the new file SpriteComponent and click Create.

At this point, your project navigator should look like this:

001_First_Component

Open SpriteComponent.swift and replace the contents with the following:

// 1
import SpriteKit
import GameplayKit

// 2
class SpriteComponent: GKComponent {

  // 3
  let node: SKSpriteNode

  // 4
  init(texture: SKTexture) {
    node = SKSpriteNode(texture: texture, color: .white, size: texture.size())
    super.init()
  }
  
  // 5
  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
}

In this code you:

  1. Imported SpriteKit along with GameplayKit so you could access these frameworks.
  2. Created a component class named SpriteComponent by subclassing GKComponent.
  3. Declared a property named node to hold the sprite on this component.
  4. Implemented a basic initializer that creates a sprite node from a texture passed in and assigns it to the node property.
  5. Added this required method to achieve compliance with the GKComponent class. For now, don’t worry about the fact that it’s not being implemented.

Your First Entity

In GameplayKit, GKEntity is the class that represents an entity. You make entities do stuff by adding components to it, like the one you just created.

It’s often helpful to create a subclass of GKEntity for each type of object that you add to the game. In this game for example, there are five types of objects: castles, quirk monsters, zap monsters, munch monsters, and lasers.

Your GKEntity subclass should be very simple. Usually it’s just an initializer that adds the components you need for that type of object.

Let’s create an entity for the castles. To do this, right-click the MonsterWars group in the project navigator, click New Group and name the group Entities.

Then right-click the Entities group, select New File.., select the iOS/Source/Swift File template, and click Next. Name the new file Castle and click Create.

At this point, your project navigator should look like this:

002_First_Entity

Open Castle.swift and replace the contents with the following:

import SpriteKit
import GameplayKit

// 1
class Castle: GKEntity {

  init(imageName: String) {
    super.init()

    // 2
    let spriteComponent = SpriteComponent(texture: SKTexture(imageNamed: imageName))
    addComponent(spriteComponent)
  }
  
  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
}

There are just two things to point out here:

  1. As I mentioned earlier, it’s often convenient to subclass GKEntity for each type of object in your game. The alternative is to create a base GKEntity and dynamically add the types of components you need; but often you want to have a “cookie cutter” for a particular type of object. That is what this is!
  2. At this point, you add just one component to the entity – the sprite component you created earlier.

Now that you’ve created a component and an entity, you’re almost ready to add it into the game.

The Entity Manager

In this section, you’re going to create a helper class to manage the entities you add to your game. It will keep a list of all the entities in the game, and have some helper methods for things like adding and removing entities.

Right-click your Entities group, select New File.., select the iOS/Source/Swift File template, and click Next. Name the new file EntityManager and click Create.

Open EntityManager.swift and replace the contents with the following:

import Foundation
import SpriteKit
import GameplayKit

class EntityManager {

  // 1
  var entities = Set<GKEntity>()
  let scene: SKScene

  // 2
  init(scene: SKScene) {
    self.scene = scene
  }

  // 3
  func add(_ entity: GKEntity) {
    entities.insert(entity)

    if let spriteNode = entity.component(ofType: SpriteComponent.self)?.node {
      scene.addChild(spriteNode)
    }
  }

  // 4
  func remove(_ entity: GKEntity) {
    if let spriteNode = entity.component(ofType: SpriteComponent.self)?.node {
      spriteNode.removeFromParent()
    }

    entities.remove(entity)
  }
}

Let’s review this section by section:

  1. This class will keep a reference to all entities in the game, along with the scene.
  2. This is a simple initializer that stores the scene in the scene property.
  3. This helper function handles adding entities to your game. It adds them to the list of entities, then checks to see if the entity has a SpriteComponent. If it does, it adds the sprite’s node to the scene.
  4. This helper function that you will call when you want to remove an entity from your game. This does the opposite of the add(_:) method; if the entity has a SpriteComponent, it removes the node from the scene, and it also removes the entity from the list of entities.

You’ll be adding more methods to this helper class in the future, but this is a good start for now. First let’s get something showing up on the screen!

Contributors

Jairo A. Cepeda

Tech Editor

Michael Briscoe

Final Pass Editor

Tammy Coron

Team Lead

Over 300 content creators. Join our team.