Chapter 5. GameplayKit

For many years, video game development has relied on the tenets of object-oriented design (OOD). Of the core features in OOD, the concepts of inheritance and polymorphism have been the most useful in this branch of software engineering. It makes sense to think of entities in our games as homogenous groups of objects; objects that we then write rules for in how they interact with each other. For example, thanks to inheritance, all objects in our game can be given the class name of GameObject; they have functions we'll use throughout the game and then we can branch them off into child classes, such as Player or Enemy. We can then continue that thought process as we come up with more specific types of entities, be they objects such as Player, different enemies, non-player characters (NPCs), or whatever makes sense for the game we are making. Calling a function on those objects, such as Shoot() or Health(), could be unique for each child of the parent class and thus we make use of polymorphism in OOD.

However, as mentioned in the previous chapter, although inheritance-based structuring is great for most software applications (including simple games), the unique needs and pairings of video game rules and entities cause inheritance-based structuring to break one of the rules of OOP. That rule is the reusability of our code. The solution to that problem is to separate the game objects and the game's rules into what's known as component-based structuring. Building games with this mentality can allow us to build unique objects, actions, and rules with the ability to not only shift them around throughout our single game project, but also to use them in other projects, cutting the overly customized structuring in which building a game via inheritance-based structuring can cause.

Apple's solution to this issue is the GameplayKit framework. GameplayKit is a completely independent framework that can be used with both SpriteKit or SceneKit games, as well as games written in low-level APIs, such as OpenGL and Metal. First announced for iOS 9 and Xcode 7 at WWDC15, GameplayKit takes the common methodologies and concepts used in game development for years and allows us to work on those aspects independently of what is being drawn on the screen. This framework doesn't handle what's drawn on the screen and is, thus, made specifically for the Model portion of MVC.

There are several game development concepts handled by GameplayKit, which we shall review in this chapter. These concepts are entities and components, state machines, agents, goals, behaviors, pathfinding, MinMaxAI, random sources, and rule systems.

Entities and components

We can think of entities as the objects in our game. They can be the player, an enemy character, an NPC, level decorations and backgrounds, or even the UI used to inform the player of their lives, power, and other stats. The entity is thought of as a container of components. Components are behaviors that dictate the appearance and actions of an entity. One might ask, "how is this any different from objects and functions?" The short answer is that objects and functions in inheritance-based design describe more of what our game objects are, while working with component-based structuring focuses more on what they do. As we deal with the classes and functionality of the GameplayKit framework, we will be able to get a better handle on this. In this framework, we'll see that entities and components are handled with the GKEntity and GKComponent classes, respectively.

Note

If you are still a bit confused about component-based structuring, check back in our previous chapter where we went into this in a bit more detail. You can also visit the developer page about this design methodology here: https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayKit_Guide/EntityComponent.html.

Using GKEntity and GKComponent objects in our games

Anyone familiar with Java or C# will understand the concept of an abstract class. The GKComponent class is essentially an abstract class. Quoting from the speakers at WWDC: think of components as "little black boxes of functionality." Objects of the class GKEntity are like our generic GameObject class mentioned before. However, unlike the objects we've dealt with before, we typically don't add too much in the way of custom functionality to them (otherwise, we'd be leaning towards inheritance-based structuring).

We first create a game object and subclass it as a member of the GKEntity type. For this example, let's just call our object class GameEntity. Also, don't forget to import the GameplayKit API:

import GameplayKit
class GameEntity : GKEntity

Again, our goal with an object of the type GKEntity is to use it as a container for GKComponent objects. Objects of the GKEntity class inherit the following functions:

  • components: This is a property that returns an array of the GKComponents in our GKEntity object
  • addComponent(_:): This is a function that we use to add GKComponents to our GKEntity
  • removeComponentForClass(_:): This removes a component for a class of GKEntity objects
  • updateWithDeltaTime(_:): This updates with the render/game loop for each component in the entity; this is what's known as per-entity updating

The last function in the GKEntity class, updateWithDeltaTime(_:), is one of the two mechanisms used by GameplayKit when dispatching updates to our game object's components. The update mechanisms are as follows:

  • Per-entity: This is good for updating smaller game structures without causing lag. The updateWithDeltaTime(_:) function of GKEntity calls all of the entity objects' updateWithDeltaTime(_:) functions and then dispatches that to all of the component's updateWithDeltaTime(_:) functions.
  • Per-component: This is made for larger projects and more complex game logic. When updating via the per-component mechanism, we use the class type GKComponentSystem to categorize groups of components and then call its updateWithDeltaTime(_:) function to fire off updates specific to the class of component instances it manages. GKComponentSystem doesn't make note of your game's entity/component hierarchy, so they can be used to efficiently update more complex games.

For example, if we have a specific way we want to update player and enemy attacks, then we create an object of the GKComponentSystem class, initiate it with the initWithComponentClass(_:) function, and pass that class of components (in this case, Attack components) to that system. It's in that GKComponentSystem object's updateWithDeltaTime(_:) function that we specify the unique update logic for that group of components, independently of the entity updates. This can come in handy when dealing with enemy/NPC AI in more complex games.

Here's a visual look at these classes:

Using GKEntity and GKComponent objects in our games

Don't worry if this is still somewhat confusing. Those of you who may be more familiar with the game engine Unity will have seen how components, such as rigid bodies, materials, and scripts, can be added to objects placed in a game scene. The concept here with iOS components and entities is not that much different. Each component in Unity and other engines can be its own independently working functionality.

Let's take a look at the code snippet provided during the WWDC15 conference, in both Objective-C and Swift, showing how we'd create entities, components, and component systems in our projects:

//Objective-C
/* Make our archer */
GKEntity *archer = [GKEntity entity];
/* Archers can move, shoot, be targeted */
[archer addComponent: [MoveComponent component]];
[archer addComponent: [ShootComponent component]];
[archer addComponent: [TargetComponent component]];
/* Create MoveComponentSystem */
GKComponentSystem *moveSystem =
          [GKComponentSystem systemWithComponentClass:MoveComponent.class];
/* Add archer's MoveComponent to the system */
[moveSystem addComponent: [archer componentForClass:MoveComponent.class]];

//Swift
/* Make our archer */
let archer = GKEntity()
/* Archers can move, shoot, be targeted */
let moveComponent = MoveComponent()
let shootComponent = ShootComponent()
let targetComponent = TargetComponent()

archer.addComponent(moveComponent)
archer.addComponent(shootComponent)
archer.addComponent(targetComponent)

/* Create MoveComponentSystem */
let moveComponentSystem = GKComponentSystem(componentClass: MoveComponent.self)

/* Add archer's MoveComponent to the system */   moveComponentSystem.addComponent(archer.componentForClass(MoveComponent.self)!)

What this code does is create our GKEntity objects; in this case, the tower game example's archer character. Next it adds predefined GKComponent objects via the addComponent(_:) function. We also create a GKComponentSystem object named moveComponentSystem that will be used to update only movement type components. The archer's own moveComponent class is added to this system with moveComponentSystem.addComponent(_:). Make a note of how the parameters passed through this object in addition to its initialization are class types of the component types denoted by the .class or .self properties, depending on which language we are writing our code in.

Note

As of this publication, the componentForClass() function might not be fully functional for the Swift programming language. So if the Swift implementation isn't working as expected for this and other GameplayKit object initializations, the Objective-C version of this code will need to be used and linked to your project via an Objective-C–Swift bridging file. This will more than likely be ironed out in future updates to Swift as Apple continues to move away from Objective-C as the main language of the platform. For more information on how to make this bridging file, check out this link: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html.

Apple provides us with a project named Maze that uses these classes as well as some other concepts we'll be going over shortly.

Here's a link to the project that could help to give you an even better idea of entities and components:

https://developer.apple.com/sample-code/wwdc/2015/downloads/Maze.zip

Before we go over more specific code use related to GKEntity and GKComponent objects, we'll look into a game development concept that is best coupled with these objects, which is the concept of state machines.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.98.148