Games have been a huge part of the App Store since its inception. From Words With Friends to Clash of Clans to Flappy Bird, iOS has proven to be a viable gaming platform with market penetration that traditional handheld consoles could only dream of. Apple has taken notice and provided developers with frameworks that make working with their technologies even more appealing, including SpriteKit and SceneKit. The information at this year’s WWDC was no different, including the announcement of two more game development technologies, GameplayKit and ReplayKit.
Whereas previous game-centered frameworks were focused on graphics rendering, Apple has set out to solve some of the more abstract problems commonly facing game developers with GameplayKit. The most high level of these is the introduction of GKComponent, a class meant to facilitate an entity-component architecture. This concept a bit difficult to explain, so I’m going to digress a bit.
In most “normal” apps, developers can generally share needed logic between objects with inheritance. For instance, if I have a Vehicle class, I can have my Truck and Car classes inherit the steering logic from the same place even if there are other differences. This approach tends to get out of hand in the realm of games, though. Let’s say I have a player character, a tree, and a monster in my game world. All three of these will share some characteristics (graphics rendering, collision detection, etc.), but even in this dramatically scaled down example we run into some issues that make code organization a nightmare. Players and monsters move around and attack, but it’d be silly for our tree have that code laying around. The monster and player could inherit from their own class governing these things, but it’s almost inevitable that the code devolves into a mess of if-else statements spanning hundreds of lines as more varieties of monsters and players are added, generating an ever increasing list of exceptions to whatever rules you started with. By the time that you’re anywhere near a complete game, any seemingly simple change could cause hours of lost time to regressions.
Enter the entity-component architecture. The best analogy I’ve heard is to think of it as a restaurant menu, wherein a game entity can order whatever combination of components it needs. The tree can simply pick up its DisplayComponent and PhysicsComponent. Both the player and monster also get a MoveComponent and AttackComponent. The player gets a ControllerInputComponent and the monster has an AIComponent. If in a few months you decide to allow the player to have a pet monster, you know the only code you need to touch will be in that AIComponent and you won’t have to make changes in line 14374 of Monster.m when QA tells you that the pet keeps attacking the innkeeper. For anybody who would like to deeper explanation on the subject, http://gameprogrammingpatterns.com/component.html is a great read.
So, what has GameplayKit given us here? A GKEntity can add any number of objects that subclass GKComponent and easily access them with componentForClass. GKComponentSystem provides a convenient means of accessing a group of components of a given class across different entities. Honestly, none of this is groundbreaking, but an out-of-the-box framework that ensures clean code organization and familiarizes new developers with the concepts is very much appreciated.
The next introduction is something that is hardly a new concept in computer science, the state machine. At a high level, this is simply a system in which an entity has a set of discrete states and can only be in one at a given time. Let’s say that your monster from the previous example is set to start attacking the player if they get close enough. We’ll need to put a check in place, though, to make sure that this doesn’t happen if the monster is dead. Similar to the aforementioned entity-component architecture, this sounds relatively simple in that it could be managed with a system of if-else statements. However, it tends to get convoluted as more edge cases and conditions are introduced. GKStateMachine is a class that ensures that the monster has a discrete GKState representing, in this case, the conditions of Idle, Attacking, and Dead. The isValidNextState method ensures that nothing happens from the Dead state and there are appropriate callbacks for leaving or entering a given state (e.g. making a threatening sound when starting to attack). Again, there is an excellent post at http://gameprogrammingpatterns.com/state.html if you would like a more in-depth explanation.
While the previously mentioned aspects of GameplayKit deal primarily with code organization, the other new additions focus on common problems where an AI is needed. Going back to our increasingly complicated game, our monster has some nice animations, but is just standing around waiting for the player to get close. We want our monster to have some personality, maybe it’s a brooding loner type that has a tendency to move away from other monsters. To accomplish this, we would instantiate a GKGoal using the goalToSeparateFromAgents:maxDistance:maxAngle: method. We can add as many of these goals as we like. Maybe it has a tendency to patrol a certain path or runs away from squirrels. Once we’ve established the goals that we’d like, we create a GKBehavior that weights the various goals and assign it to a GKAgent, which is itself a component. The game entity assigned this component will refer to these weighted goals when making its real-time decisions, hopefully resulting in compelling emergent behavior. It should be noted, however, that the currently available goals that the agent can handle are limited to determining movement. This may be expanded on in the future, but any additional actions that the AI should take would need to be addressed elsewhere.
So our monster is no longer standing around but is now leading a fulfilling monsterish life roaming the wilderness thanks to our system of goals. The player character draws near, causing it to enter its Attacking state and roar loudly before running headlong into the tree that stands between them. The immersion has been ruined. To rectify this, we’re going to need to give our monster a model of the game terrain so that it can figure out how to best terrorize the player. GameplayKit provides us with two such models, GKGridGraph for games made up of discrete squares that can be occupied (think original Legend of Zelda for NES), or the more flexible GKObstacleGraph. In this case, we would create a GKObstacleGraph with a GKPolygonObstacle representing the shape of the tree. Providing the GKObstacleGraph with GKGraphNodes representing the monster and player positions, we can generate an array of GKGraphNodes representing all of the points along which our monster should walk to most quickly devour the player. One caveat is that this approach would quickly fall apart if there’s a z-axis involved (e.g. the monster and player are flying in spaceships), but this could prove to be a boon for many 2D games.
We’re going to take a break from our adventure game for a while and look at something a little more classic: Chess. Computers have been playing Chess at a high level for decades now, but quickly coming up with a decent program for it would give most developers that don’t already have experience in that niche a lot of trouble. GKMinMaxStrategist is Apple’s solution. Given a GKGameModel that represents the players, their scores, and their possible moves, the strategist object generates a decision tree of all the possible outcomes over the next few turns and picks the best one, which can be used to either suggest moves to new players or for the AI that they’re playing against. The strategist is configurable based on how many moves it should look ahead and adding variance to ensure that it doesn’t always make the optimal play. This approach won’t work in a fast-paced fighting game or a poker simulator where the AI needs to make educated guesses with imperfect information, but when it comes to most turn-based games, this is a common need that would usually require the developer to make something from scratch every time. Still, I have to think that it will prove difficult to distill the concept of a game to a GKGameModel that the GKMinMaxStrategist can understand. Time will tell whether using GameplayKit’s tools or writing AI from scratch for every game proves to be the lesser evil.
ReplayKit is a little different in that it doesn’t address a developer need, but is rather a recognition of the burgeoning market around gameplay videos. The existence of people making millions of dollars by playing games on YouTube and the more recent Twitch would have been inconceivable years ago. Yet, here we are. ReplayKit is actually remarkably simple. There is a startRecordingWithMicrophoneEnabled: method followed by stopRecordingWithHandler:. After stopping, all that’s left is to present the view controller governing trimming and sharing of the video with the standard UIActivityViewController. Device permissions are required similar to camera roll access and push notifications. One note of interest is that there’s nothing here that requires the captured content to be that of a game, although using ReplayKit in a non-game context may be something frowned upon during the review process after submission to the store.
There are a few minor bits that I glossed over, but these are what jumped out at me as the most interesting announcements. What’s most curious about all this, though, is how much Apple continues to invest in game technologies when the vast majority of high-grossing games are unwilling to forego the cross-platform market (safe to say that Flappy Bird was an exception to just about every game development trend in existence). Apple continues to improve SpriteKit and SceneKit with every passing year, but so far it hasn’t been enough to move people away from Unity and Unreal when it so directly impacts their bottom line. One possibility is that they are all-in on adopting a “If you build it, they will come” mindset with the long-term goal of winning developers over and pushing the other players out of the market. This strikes me as a little idealistic, but Apple is certainly refining their tools at an impressive rate. In a few years, perhaps development cycles will be that much faster when focusing on the one platform. Another possibility is that Apple is laying the foundation for a push to market the Apple TV as a console in its own right. Rumors were swirling before WWDC about major Apple TV announcements, and there may still be big news later in the year. All we can do is speculate. In the meantime, any game devs targeting iOS exclusively have a lot of new toys to play with.