You may have learned about the various GameplayKit classes and perhaps seen some demos. But from a high-level perspective I find the documentation somewhat lacking. So let’s see what GameplayKit offers and makes possible.
But also I want to illustrate how GameplayKit components can be used and how they can interoperate. I leave it to you to imagine how well this plays into making tilemap (grid-based) games.
What’s in GameplayKit?
I classified the GameplayKit classes into the following high-level components with Wikipedia links for further reading.
Entity Component System (ECS) models the behavior, aspects and visuals of an entity (game object) through modular, reusable components. Components are typically small classes that may contain both data and logic to complete a given task, such as:
- animating the entity’s sprite
- allowing the entity to pickup items
- enabling the entity to hold a weapon
- to enable a weapon entity to shoot a configurable number of projectiles at a configurable interval until it runs out of ammo and needs to reload
- or simply to categorise the entity (eg “cavalry unit owned by AI player #2”)
Note that this is not the derivative of ECS specifically found in AAA desktop and console video game development. That is not an ECS, it’s an EDPS = Entity Data-Processing System – a term I made up just to establish the distinction once and for all. A component with just data and no logic isn’t a component anymore, it is a data chunk or database record.
The ECS in Apple’s and it’s original form as presented by Scott Bilas in 2002 both derive from component-based software engineering principles in which a component is a self-contained piece of code that contains both data and logic.
GameplayKit supports both updating each entity and its components in sequence and alternatively updating all components of the same type in sequence using a component system. The component system updates the components regardless of their location within entity components lists, the component doesn’t even need to be assigned to an entity to begin with. Meaning you could combine both update strategies.
I’m most excited that well-engineered components will soon be shared by developers as ready-to-use components. Add them to your project, assign them to an entity, and they should do their job.
Finite-State Machines (FSM) model application state. That’s right, not just functional states of an entity but the entire state of the application, which screen it is in, which game mode is active, whether the game is paused, whether to attack or defend, which animation to play – those can all be modelled using state machines. Basically everywhere you would normally be using if/else logic with boolean conditions.
State machines are a generic tool to both clearly define the currently active state as well as putting restrictions on which other state can be entered from this state. Moreover only the code in the currently active state is processed, so there’s an inherent processing benefit.
Also, state machines are less prone to bugs due to incorrectly nested if/else blocks. And if you do notice a bug in a state machine, you know you only have to look (or begin looking) in the code of the current state, not the entire state machine.
Goal-Based Agents accelerate and rotate in order to satisfy one or more movement goals, such as following a path, staying in formation or moving around obstacles. Agents incorporate some physical behavior since their acceleration is affected by their mass. They can also have speed and rotation speed limits imposed upon them.
Complex autonomous behavior can be modelled by adding multiple, weighted goals. For instance while following another entity the agent will have a priority goal to avoid obstacles.
While flocking behavior is possible, movement in (strict) formation is not supported. But this may not be necessary if the formation is meant to show only when the group is idle. In that case, one could take the relative distances of units at the start of movement, and apply these distances as a final movement goal upon arrival.
Shortest Path Algorithm, most likely A*. The algorithm uses a Node Graph collection with either bidirectional connected nodes (grid nodes) or freely-placed nodes (obstacle nodes) which both define a Navigation Mesh in 2D space.
The path finding algorithm enables agents to move across complex levels at ease, or to find out whether a given location can be reached by a certain agent to begin with. Pathfinding can even be used in rule systems, for instance to calculate the distance to a given destination or whether any of the path nodes is close to a dangerous structure.
The rule engine allows to make decisions based on either discrete (true/false) or fuzzy logic (confidence levels expressed along a range from 0.0 to 1.0) by asserting facts. Rule engines are suitable for realtime and turn-based games.
The decisions made based on the asserted (or retracted) facts can be used to change the state of an AI state machine, for instance. This could further influence agent behavior.
The AI may remain in a given AI state for a given time, which means the rule system also only needs to evaluate at low intervals, perhaps once every two seconds might suffice.
For instance a realtime strategy AI could be in a state that prefers to harvest resources. To enter the “under attack” state, it asserts whether the attacker is one or several units or whether they are close to a crucial structure. If threatened enough, the AI mobilizes all nearby offensive units (agents) to approach the location of combat.
Min(i)Max Strategizer is used to find the best-case results of all possible next moves in a turn-based game.
The MinMax strategist class does so by simulating all possible game states in the future for a given number of moves to look ahead. A higher look-ahead takes exponentially longer to calculate but results in a stronger AI opponent.
This kind of strategist is most suitable for turn-based (board) games with little to no “truly random” events and discrete rules. It is not suitable, for instance, for combat AI in a realtime strategy game.
It is also not a plug-in solution. You still need to provide the data, the players and the move logic in a way specified by the MinMax Strategizer protocols. The strategizer is, more or less, a prebuilt rule system that determines the best outcome given game data, active and other players, and how moves change the game state.
Random Sources are used by the MinMax Strategizer but have general application for AI and even beyond GameplayKit.
Apple specifically added functions to simulate rolling a 6, 20 or n-sided dice. Combined with the gaussian distribution you can also simulate the statistical probabilities of rolling multiple dice whose value sequences, over time, are more likely to produce values close to the middle of the value range.
The shuffle random source behaves like a shuffle bag aka Fisher-Yates or Knuth shuffle by default. This means that any number in the range is picked exactly once, at random, until all values in the range have been picked once. Then the sequence starts over.
The shuffle distribution randomizer is very useful for a set of cards, where cards are removed from the stack one at a time. You wouldn’t want the same card to appear more than once. And specifically useful in the card scenario is the ability to randomize an array’s elements.
Before I finish, I wanted to state a fact some may not be aware of: the Apple prerelease framework documentation is public information, accessible by anyone.
Therefore, I conclude we can discuss the information disclosed in the prerelease software documentation, since the Developer Agreement states in section 4 that “information that is generally made available to the public by Apple” is not considered confidential (oh, really?).
However, there’s one caveat: the prerelease software itself (Xcode, iOS, OS X) is still confidential information. So don’t post anything about Xcode 7 beta for instance. This also makes writing tutorials a tad difficult as you likely want to explain steps with screenshots.
And about the paragraph regarding WWDC also in section 4: I think that is meant to prevent you from sharing the session videos, for instance. But I see no reason why we couldn’t post code fragments that requires prerelease software to run, such as modifications to Apple’s (permissively licensed) sample code.
Note that the above is not legal advice. IANAL (I am not a Lawyer). This is merely me drawing conclusions. I am posting the above at my own risk, which based upon my own rulesystem I asserted with very high confidence as a low-risk strategy.