Session 608WWDC 2016

GameplayKit provides developers a collection of essential tools and techniques used to implement modern gameplay algorithms. Learn what's new in GameplayKit and check out advances in pathfinding, autonomous agents, and game AI, as well as many enhancements supporting GameplayKit in Xcode. Tap into new capabilities for 2D and 3D spatial partitioning, and explore noise-based procedural data generation useful for height maps, natural textures, and more.

[ Music ]

[ Applause ]

Good morning, everyone.

My name's Bruno Sommer.

I'm a game technologies engineer here at Apple,and this is What's New in GameplayKit.

So last year, we introduced GameplayKit,Apple's high-level gameplay framework,and what GameplayKit is is a collectionof common architectural patterns, data structures,and algorithms that enables our developers to make really greatand compelling gameplay in their games.

We want you guys to think about GameplayKit as your toolboxfor great gameplay, so regardless of the typeof game you're making, whether it's a platformer or an RPGor a city builder, there's something you can findin GameplayKit to make your life a little easierand to make your gameplay a little stronger.

So last year when we introduced GameplayKit,it was made up of seven major systemsthings like entities and components, state machines,and our game quality random sources.

This year, we're making improvements to pathfinding,agents, and game AI, and we're also introducing three new majorsystems to GameplayKit.

We have a really powerful spatial partitioning systemthat's going to let you get really great performanceout of runtime queries in your games.

You must have a really rich procedural generation systemthat's going to let you make really compellingruntime content.

And this year, we've also integrated GameplayKitinto our Xcode Game Editor, so now a lotof the workflows previously that you could only do in code,now you can do right in the Editor data side,no recompile necessary.

So we have a lot to talk about today.

I'm going to jump right in with what's new in pathfinding.

So last year, we introduced our obstacle graphs.

These are our graph type that deals with a setof impassable obstacles in your game world.

And under the hood, we use a line of sight algorithmto map the passable area between those obstacles.

Now, this method is very powerful.

It results in really good quality paths, but especiallyfor larger game worlds and game worlds that have a large numberof obstacles, these can be really computationallyintensively to calculateand really memory intensive to store.

So this year, we're providing you with an alternative.

We're introducing GKMeshGraph.

Now, this is very similar to our obstacle graphs.

Again, we're dealing with a setof impassable obstacles in our game world.

But now instead of using line of sightto calculate the passable areas between those obstacles,we're actually going to triangulate that space.

We're going to make a triangle mesh out of itsuch that every passable pointin your game world is represented on oneand only one triangle.

So this new triangulation method results, still resultsin really good quality paths but has the added benefitof being really fast to calculateand really low overhead to store,especially for really large game worlds.

In addition, you have a lot of flexibilitywith where nodes get placed on these mesh graphs.

You can place them at triangle centers, triangle vertices,and on triangle edges and all the combinations thereof.

Let's look at a quick code exampleof what using a mesh graph looks like in GameplayKit,and this is going to look very familiar to those of youthat have used our obstacle graphs.

They're solving the same problem, just different ways.

So here at the top, I'm going to go ahead and make my mesh graph.

I'm going to pass in a buffer radius of 10.

Recall that this buffer radius is related to the sizeof your agents that are actually doing the pathfindingin your world.

We're going to artificially increase the sizeof your obstacles under the hoodto compensate for that agent size.

Here we're also going to pass in two points(0, 0) and (1000, 1000).

This is the span of my game worldthat this mesh graph is going to represent.

Next, I'm going to set the triangulation modeon my mesh graph.

This is that flexibility with where nodes get placedthat I was talking about earlier.

Here we're going to specify that I'd like nodes to be placedat triangle vertices and on triangle centers.

And lastly, we're going to add our setof obstacles into the mesh graph.

We have a set of obstacles associated with our game world.

Then we're going to call triangulate.

This actually commits those obstacles to the graph,run the underlying triangulation algorithm,and then we're good to go.

Now at initialization time,you can optionally specify a custom node class for themto instantiate instead.

And this is really useful if you need to attach any custom dataor logic to your nodes, which is sometimes useful dependingon the game you're trying to make.

We call the appropriate init()when we would've generated our original node type.

And all these graph classes now support Objective-Cand Swift generics, so no casting is requiredwhen you query your custom nodes.

So that's what's new in pathfinding this year.

Let's go ahead and move on on what's new in agents.

A little bit of a refresher on what agents are in GameplayKit.

They are autonomously moving entities controlled by a setof goals and behaviors, and they're under a numberof realistic physical constraintsthings like velocity, mass,obstacle avoidance, and path following.

On the right here, you see you have a number of goalsat your disposal to achieve the behavior you're lookingfor in your game.

And this is things like seeking and avoidingor wandering and fleeing.

So previously, agents were purely in 2D.

This year, we're excited to announcethat we're bringing them fully into 3D.

The class is GKAgent3D and the interface is extremely similarto its 2D variant.

The key differences are that position is of course a float 3and rotation is of course a flow 3 by 3 matrix.

And all the same goals and behaviors are supported.

So a couple things to note here with this transition.

GKPath has been changed to support both 2D and 3D pointswith regards to our path following goals.

And with regards to obstacles in our obstacle avoidance goals,those, if you're going to use those obstacles in 3D,they still live on a single plane,so you need to pick a plane that makes sense for your game.

So in addition to bringing our agents into 3D,this year we're introducing behavior composition.

We have a new class GKCompositeBehavior that's asubclass of GKBehavior, and this is a collectionof weighted behaviors.

This is really similar to the relationshipbetween behaviors and goals previously.

Behaviors are a weighted set of goals.

So these are fully nestable,so now you can do really interesting nested behavior,behaviors in your game, and this also makes them much easierto maintain, especially if you're workingwith a large number of behaviors in your game.

Let's take a look at a quick code exampleof these composite behaviors in action.

At the top here, I'm going to make a flocking behaviorby combine an align, a cohere, and a separate goal.

Next, I have some obstacles and enemies in my game worldthat I'd like my agents to avoid, so we're goingto make an avoidance behavior by combining an avoidObstaclesand an avoidEnemies goal.

Then I'm going to combine those two behaviorsinto our new composite behavior,effectively combining them into one.

And lastly, I'm going to make my agent,I'm going to set my composite behavioras the agent's behavior, and now we're good to go.

The next time we update this agent,it's going to correctly simultaneously attemptto achieve both of those sub-goals or sub-behaviors.

So that's what's new in agents this year.

Let's move on and talk about our new spatial partitioning system.

So a little bit of backgroundon why spatial partitioning might be important to your game.

A lot of times when we're going high-level gameplay programming,we ask a lot of spatial questions about our game world,things like, how many enemies are near the player?

Or where are all the items in my world?

Or what projectiles will hit the player this frame?

Now, especially for larger game worlds or game worldswith a large number of game objects, answering these typesof questions can be expensive.

In gameplay programming, we often speed up these sortsof spatial queries using a formof caching called spatial partitioning.

So a little bit of an overview of what we're providingwith our spatial partitioning system.

This is a set of tree-like data structures that allows youto cache your game objects spatially.

You add objects to these tree-like data structuresand they get grouped into hierarchiesand buckets under the hood.

And then future queries on these objects are madeimplicitly faster.

This year, we're introducing three such data structuresfor you spatial partitioning needs.

We have R-trees, quadtrees, and octrees.

Let's dive a little deeper into these data structures.

Let's talk about R-trees.

Now, what an R-tree is, it's a tree data structurethat has a number of hierarchical buckets.

Whenever you add an object to an R-tree, it gets fittedinto one of those buckets.

Now, all these buckets have a bounding box associatedwith them that is the sum of the bounding box of allof the children that are in that bucket.

Now, R-trees have a special rulethat when these buckets grow too large, they need to split,and this is a user-configurable parameterof just how large these buckets can grow.

And we have a number of strategies at our disposalto decide how these buckets should split.

We can simply have them or we can try and optimize for linearand quadratic distance or try and reduce overlapof the resulting buckets.

I'm going to give you a quick visual exampleof what building a simple R-tree looks like.

Let's say I have a space gamewith some spaceships and some asteroids.

I'm going to add a spaceship to my R-tree.

It gets fitted to a bucketand it's just simply the bounding box of that spaceship.

And then I'm going to add a couple asteroids to that bucket,and you notice it grows larger to encapsulate those objects.

I've specified a rule in this particular R-treethat these buckets need to split when they grow largerthan three objects, so I'm going to go aheadand add a fourth object to that bucket.

We've grown too larger.

Now we need to split.

And we're just going to do a simple linear distance split,and we end up with two resulting buckets.

Again, I'll add a couple objects to the bucket on the right.

We've grown too large.

We need to split.

And again, we'll do a linear split and endup with two resulting buckets.

That's the gist of how R-trees work under the hood.

So let's move on and talk about quadtrees and octrees.

I'm going to address these singularlybecause they're solving the same problem, just quadtrees livein 2D and octrees live in 3D.

The interface is identical.

These are tree-like data structures that have a numberof levels and hierarchies, and at each level,space is subdivided evenly.

Here on the right, I have an example of a quadtree.

And you see in the upper left, I've subdividedthat quadrant once, and thenin that new subdivided quadrant's upper left,I've subdivided again.

So quadtrees and octrees have a max cell size associatedwith them, and that controls just how deep these trees cangrow and just how small those cells can get.

Now, when you add an object to a quadtree and octtree,it gets placed into the smallest cell that it fits in entirely.

And a small note on this maximum cell size,this is really related, this value is particular importantto the performance gains you're going to seeout of these data structures, so you should pick a cell size,or a max cell size that makes sense for your game.

Typically, this is on the order of someof the smaller game objects in your game world.

Again, I'll give you a visual example of building a quadtree.

Same examples, spaceship and asteroids.

I'll insert a spaceship into our quadtree.

Gets placed into the lower left quadrant two levels down.

I'll add some bigger objects, and they get,they live one level up.

Take special note of that asteroid on the left.

You see it sort of straddles the quadrant boundaries.

It's actually going to live one levelup because it doesn't fit neatly into either of those cells.

And lastly, I'll add some smaller objects,and you see that they live three levels down.

So that's the gist of what's going on under the hoodwhen you use a quadtree or an octtree.

Let's look at a code example of a quadtree in action.

So at the top here, I'm going to make my quadtree.

I'm going to pass in a quad, which is the areain my game world that I want this quad tree to represent.

Here we're going to cover the span between (0, 0) and (1000,1000) in my game world.

I'm mostly going to specify a minimum cell size of 100.

No cell in this quadtree's going to be smaller than 100 units.

So I also have some enemies in my game world.

I'm going to go ahead and add them to my quadtree.

Notice here that all these enemies are associatedwith a quad of their own.

This is where that enemy is in our game worldand where it's going to end up in our quadtree.

And lastly, I'm going to run a query on our quadtree.

I'm going to ask my quadtree to give me back all the objectsthat are between (0, 0) and (1000, 1000) in that quadtreeand therefore in my game world.

And it just so happens that all three of these enemies are,and I'm going to get all three of them back in my query.

So that's spatial partitioning in GameplayKit.

Let's move on and talk about our procedural generation system.

So a little bit of backgroundon why procedural generation might be important to you.

I'm sure we're all familiar with premade content in games.

This is things that we make before the game is runor before the game even ships, and this is thingslike artist design, or designer designed levelsor artist developed textures and characters.

And these are great assets.

They really work for a lot of games.

But for other types of games and particular genres,you run into problems because these sort of assets are static.

They don't change at runtime very much.

So especially if I'm looking for a random feel,every time I play my game, it feels new,I can't really use these kinds of static assets.

So what I'm looking for is procedural content,and this is things like randomly generated worlds,procedurally generated textures or height maps.

So we're looking to make this procedural content in games.

What we're really looking for is a source of coherent randomness.

A lot of these random elements I'm trying to make are spatialin nature, things like worlds and textures and height maps.

So we need a source of randomnessthat makes sense spatially,that actually has an underlying spatial pattern to it.

Now, you might say to yourself, well,I can just use a random number generator, right?

I can pull some values from my RNG,make my random content, and I'm good to go.

Anyone that's ever tried to dothat very quickly runs into some hurdles.

Outputs of RNGs tend to fluctuate very wildly.

It's difficult to have meaningful spatial relationshipsbetween subsequent callsand it's also very challenging to have determinism.

Every time I randomly generate my content,I want it to appear the same way if I'm given the same seed.

So we're looking for this source of coherent randomness.

One such source of this is called noise.

Now, what noise is, it's a function that takes inputsand gives output values,but there's some rules to that relationship.

For small changes in input, I get small changes in output,and for large changes in input, I get randombut still spatially meaningful changes in output.

There's some underlying pattern to this noise source.

And noise functions are also infinitefor the whole range of inputs.

It continues infinitely, and they're deterministic.

Given the same input, I always get the same output.

So once we have this noise function, we can then sample itat intervals that are relevant for my game and for the typeof content I'm trying to make.

So if I'm trying to randomly generate a world,this might be coordinates or tile indexes or biome indexes.

Or if I'm trying to randomly generate a texture,this might be texels or pixels and so on.

So a little overview of what we're providingwith our procedural generation systemand our noise system in general.

You have a number of noise sources at your disposalto sample and make meaningful content in your game,and this is things like random-ish noise,things like Perlin noise and Voronoi noise,and also geometric noise sources, things like billowsand spheres, ridges and cylinders, and also some sourcesof constant noise like the checkerboard patternor the constant noise function.

So you can then combine noise sources in a noise objectand perform a number of transformations on them.

And these are things like combining noise sourcesor translating, scaling, rotating noise sources.

So once we've combined them in some meaningful wayinto a noise object, we can then sample a regionof that underlying noise map, that noise function,in a noise map, get our samples, and then make our game content.

So let's dig a little deeper.

Let's talk about our noise sources.

Now, all of our noise sources output valuesbetween negative 1 and 1.

We'll talk a little bit more about this later.

And they all have parametersto tweak their various noise outputs,that underlying noise function, so for our more randomand coherent noises like Perlin and Voronoi, these can be seededwith a GKRandomSource and they also have a number of parameterson them to tweak their underlying pattern.

And for our more geometric noise sources, there's parametersto alter their shapes, so the size of spheres and cylindersor the frequency of ridges and billows.

So once we have some noise sources we like,we can then combine them into a GKNoiseObject.

Now, this has all the functions necessary to transform, combine,and modify our noise sources, and a lot of common mathematicaland logical operations are supported.

So if I'm trying to combine noise sources, I can add,multiply, min or max, but if I'm tryingto transform a single noise map, I can scale, rotate, translate,or I can modify it by taking the absolute value,clamping, inverting.

So once we have our noise the way we like,we can them sample a region of that noise,that underlying noise function, using a GKNoiseMap.

You specify an origin and a size.

This is the region of that underlying noise mapthat we're sampling.

And you also specify a sample count.

How many times do we sample that noise function in this region?

What's my fidelity at which I'm sampling?

So then once we have our region sampled,we can then get the value at any given positionon that noise map, and again, the range is in negative 1 to 1like I mentioned before.

And at runtime, you can optionally overwrite valuesas needed if your game world changes.

So I realize that this is a lot to take in.

I think the best way to illustrate this iswith a visual example.

Let's say I wanted to randomly generate a world for my game,and I want to model it after Earth's biomes.

I want it to have a realistic feel.

Deserts, forests, arctic zones, things like that.

One, this is one method you might use to accomplish that.

Here I've generated two Perlin noise maps,and the one on the left I'm going to call a moisture map.

At any point in my game world, I can look into this mapand determine how wet or how dry my game world is.

And on the right, I have what I'm calling a temperature map.

At any point in my game world, I can look up into this mapand decide how hot or cold my game world is.

So some things to note here, and we'll come back to this.

On the moisture map, you see I have a very dry spoton the right.

That's that black smudge.

And a very wet area on the left.

And again, these colors correspondto that output I was talking about.

Here black is my negative 1'sand white is more of my positive 1's.

And on the right, notice I have an extremely cold spotat the top.

That's that black smudge again.

And a very warm sort of right side of my noise map.

So I'm going to specify some ruleson how I actually combine thesein some meaningful way for my game.

Here I just have a simple 2D graph.

On the vertical axis, I have moisture,and on the horizontal axis, I have temperature.

So I can use these rules to decide the intersectionof those two maps, so if I have a spotthat has a really high temperaturebut really low moisture, I'm going to endup with something like a desert.

Or if I have something with really high temperatureand really high moisture, I'm going to endup with something like a rainforest.

And so there, and sort of on the colder end of things,I have tundras and arctic zones.

And then in the middle, I have thingslike the more temperate biomes, things like forests,savannahs, and grasslands.

So using those two maps I madeand combining them using these rules,I get something like this.

You see it has a nice, realistic feel to it,and some things to note.

On the right, you see we have a really big desert that sortof bleeds into some grasslandsand then bleeds into a forest area.

That corresponds with that dry spot on our moisture mapand that really warm spot on our temperature map.

And sort of on the upper left,you see we have a really big tundra with some arctic spots.

Then on the upper right and the lower left,we have some small rainforests correspondingwith really high temperatures and really high moisture.

So this is just a really basic example of someof the cool stuff you can do with procedural generation.

Here we just used two simple noise maps, combined themwith some really simple rules,and got some pretty decent output.

Now, I'd like to call my colleague Michael Brennanup to tell you about what's new in game AI.

Michael?

[ Applause ]

Thank you, Bruno.

Hey, everyone.

I'm Michael Brennan.

I'm a game technologies engineer here at Apple,and I'm really excited to sharewith you today what we're bringingto GameplayKit this year for game AI.

Last year with GameplayKit,we introduced the Minmax strategist.

This is a great AI solution for all kinds of gamesthat guarantees an optimal search for your game state.

It guarantees this by having an exhaustive searchof that state space combinedwith the scoring function you provide for every given statein the game to give you the best possible move for your entityto make at a certain point.

The exhaustive natureof the Minmax strategist does make it a little bit prohibitiveto use for games with larger state spaces, however.

Games like Go or chess, for example.

That's why this year I'm excited to bringwith you the Monte Carlo strategist.

Monte Carlo strategist is a best first searchof the state space combined with the random samplingof that state space to give a great movefor you opponent to make.

It does this by first selecting a player move using explorationversus exploitation to choose that move, then simulatingout new games from that moveuntil it reaches an end conditioneither a win or a loss or a drawwhich then propagates back up the tree.

It doesn't guarantee the optimal move quite like Minmax does,but it does converge on that optimal move.

Monte Carlo strategist is fast.

It guarantees a good performance for even gameswith incredibly large state spaces like Go, for example.

And given that it only needs that end condition,something your games probably already provide,it's very simple to implement in your game.

And it is approximately optimal, so while it may missthat optimal move Minmax would find, it is approximate to itand it will converge on that move given the time.

Let's go over some of the elements you need to useto incorporate this into your game.

With GKMonteCarloStrategist, you need to provide a budget.

This is the amount of times it'll dothat four steps we mentioned earlier.

And you need to provide an exploration parameter.

Now, this is a value between 0 and 1 that states whether or noton selecting a move you want to explore unvisited nodesor whether you want it to exploit nodes it's visitedand found to be very winning.

And you need to provide the game model of course.

This is something you're familiarwith if you've used GKMinmaxStrategist in the past.

We're first going to set the Monte Carlo strategist gamemodel to point to our game model, and next,we're going to give it a budget.

We're going to say around 100.

This means it'll do that four stepsthe simulating [inaudible] propagating 100 times.

And then we're going to set the exploration parameter to 1.

This means we want it to be very explorative.

And then we're just simply going to call for the best movefor our active player in that game state, find that best move,and apply it back to our game model.

It's just that easy.

This year, I'm excited to tell you that we're also allowing youto make your own custom strategist.

We implemented a new protocol called GKStrategist,and you simply conform to it, giving the game model,game model update, game model players,and implementing find best move for player, and you can use thislike you would any other strategist we provide for you.

So that was what we were bringing to strategist.

Now let's talk about something else decision-making.

There are many ways to model logic in your game,many of which GameplayKit already provides support for.

Your enemies need to be ableto make decisions considering the vast amounts of state,and they need to be able to make these decisions quickly.

As you can see here, we have this little button jumping game.

Just in this simple game, your opponent would need to considerwhere you are, where every other enemy is, where the buttons are,who owns the buttons at the current point in time,whether they're jumping, whether the enemies are jumping,where they are in the level.

It's quite a lot of state to consider.

Decision trees are a simple method for making decisions.

They're a tree-like data structure which makes them easyto visualize and debug, and they can be either handmadeor learned.

GKDecisionTree gives you a low overheadfor determining your action.

It's completely serializable and it's very flexible, allowing youto make nodes that will make decisions that randomwith certain weights for branches or by valueif a certain branch is a value like true or falseor by satisfying predicates even.

It's extremely flexible, allowing you to do a lot.

Let's go over a brief code example.

So as you can see here, we've got our tree.

We're going to initialize it with a root attribute,asking if we're near the button.

And then we're going to grab a referenceto that root node for later.

After that, we're simply going to create branches offof that root node one for if we are near that root,that button, in which case we're going to jump,and one if we're not near that button,in which case we're going to want to wander.

And we're going to grab a referenceto that wander node as well.

With that wander node,we're going to create a few branchesone with a weight of 9 we're going to move left at that pointand one with a weight of 1 we're going to move right.

Now, this is additive,which means that for the left branch we move with the weightof 9, that means it has a 90% chance giventhat there's a total weight of 10 there,and the right move has a 10% chance of occurring.

Then we're simply going to pack the state into a dictionaryand pass it into findActionForAnswers methodon the tree to get our action.

Decision trees can also be modeled.

You simply supply the gameplay data,and it will find the decision-making behaviorin that data and fit a decision treeto that decision-making behavior.

As you can see here in our matrix,we have a top row which is dark gray.

That's the attributes.

And the interior matrix is our examples.

That's what various points of the game look like for gameplay.

And on the right-hand side, we have the actions we performed.

That's simply what we didat those various points in the gameplay.

You pass this into the constructor for GKDecisionTreeand it will fit a decision treeto that gameplay data you've recorded.

Let's look at what this might look like in game.

So here we have my player, the light greento turquoise colored player,playing against the dark blue player usingthat handmade decision tree we showed earlier.

As you can see, it's missing out on some of the thingsthat we're doing that make us perform well.

Let's look at a different example.

Here you'll see it behaves quite a lot morelike how we were behaving earlier.

Like I said, you just simply record your gameplay data,pass it in, and you can model behaviors like you would use.

So that's what we're bringing this yearto game AI for GameplayKit.

It's awesome and I'm excited to share it with you,and now I'd like to invite to the stage my colleague Sri Nairto tell you moreabout GameplayKit integration into Xcode.

Sri?

[ Applause ]

Thank you, Michael.

Hello, everyone.

My name is Sri Nair, and I'm a game technologies engineer hereat Apple.

So when we introduced GameplayKit last year,it was exclusively driven by code.

You had to create the constructs, do the hook-up,and tweak the properties and their values all in code.

And that can be inefficient for many obvious reasons,so I'm happy to say that we are improving that situationby introducing a more data-driven workflowfor GameplayKit by integrating itwith Xcode and SpriteKit Editor.

As you know, editor integration helps with [inaudible]on your game features much faster.

They also help to separate your engineering workflowfrom the design workflow.

So here are the four main features coming to the editorto help accelerate your GameplayKit development.

Number one, entity and component editor.

Number two, navigation graph editor.

Number three, scene outline view.

And number four, state machine quick look.

Let's dive deeper into each one of these features.

What's the component editor?

Let's recall that an entityand component system is a design patternwhere a game object is represented by entitiesand their behavior is represented by smallerand independent components.

And this provides for better structuringand usability of code.

And they also tend to be easier to maintain and to extend.

So now with the component editor, you can assign entityand components to your nodes right in the editorand tweak the properties all in the editor that's providingfor an editor-based, data-driven workflow.

The editor is closely integrated with codeand supports auto-discoveryof component classes and properties.

For example, let's say you wrote a movement component classthat's derived from GKComponent, added a few properties,and annotated with the newly introduced GKInspectableKeywordfor them to show up in the UI.

And the component editor will automatically detect thesecomponents that you have added and show up in the UI,and now you can simply select those components of your choiceand assign to the nodes.

Once you add the component, the properties are auto-populatedwith the corresponding type of [inaudible],and now you can adjust these propertiesand preview the changes right in the editor without havingto quit the editor or recompile the code that's leadingto a much faster iteration.

And all of these updates are saved in a JKCand under the SKS file.

And all the unchanged property values use the defaultsetting code.

The GKEntity to the nodes connection is madeunder the hood through a GKSKComponent.

And the UI supports all the common property types,such as float, int, bool, et cetera,and that's component editor.

Now, let's move on to the navigation graph editor.

As Bruno mentioned earlier, navigation graphs knownas GKGraphs are used in pathfindingto find an optimal way for an object to getfrom point A to point B.

And with the navigation graph editor,now you can create GKGraphs right in the editor.

You can add or edit nodes, make the connectionsbetween them just by clicking and dragging in the same window.

And these GKGraphs are saved in the GKScenethat you can later retrieve in code and use for pathfinding.

I also want to mention a highly useful feature of we introduceto SpriteKit Editor that's quite usefulfor GameplayKit development as well called scene outline view.

It outlines the scene elements, their parent-child hierarchy.

Most standard operations are supported there like add, edit,rearrange, delete, et cetera.

The navigation graphs you add in your scene also show up therein the scene outline view.

It also can be used for locking the nodesand changing the visibility.

It also comes with the context menufor more selection-specific operations.

Quite handy.

And last but not least, state machine quick look.

So just to refresh,we introduced GKStateMachine last year, and it allows youto represent some kind of execution flow in your game.

And it has many applications in games such as in AI, animation,UI, level sequencing, et cetera.

And up until this point, you had no wayof previewing what these state machine looked like.

It was quite hard to understand the connectionbetween the states, the execution flow,or what state it is in currently, so to help with that,we are integrating a state machine preview tool rightinto Xcode Debugger's quick look feature.

This allows you to put break point in code where you wantto see the state machine and click on the quick look icon,and it pops up a visual representationof for your current state machine.

And it shows the states, the connection between them,and the current state is highlighted as well.

Here are a few more examples of state machineas seen in quick look.

And with that, I would like to demonstrate the editor-basedworkflow of GameplayKit.

[ Applause ]

So here I have a, we're going to try to build a simple gamewhere a player picks up balloons, paint balloons,and throws at an enemy that's simulated by game AI,and enemy can do the same.

So we have a basic scene here.

As you can see in the scene outline view,we have a background and a player, a bunch of balloons.

So first, we will try to add,it's a pretty basic, no actions going on.

It's very static scene, so we'll start with adding some movementto the player using the keyboard.

So for that, I have added a few components here, but we'll lookat the movement component that we talked about earlieras a few properties that helps with movements such as speed,friction, acceleration, et cetera.

And you have annotated that with the GKInspectableso that you can treat those properties in the UI later.

Similarly, I have a player input component,and we will assign these to the player by going to the sceneand looking in the component editor.

So on the inspector area on the right-hand side,I have the newly introduced component editor.

Now, I can select the player and click on that plus buttonto add these components to the node.

So we'll go ahead and add the player input componentand the movement component.

And we'll see what we get with that.

So I would expect the player to be ableto move with the keyboard.

That's great, so can move in all directions.

And except you can, you'll notice that it doesn't stopat the boundaries because I haven't added any collisionto the player yet, but I do have a collision component added,which essentially adds the physics body to the player node.

So I will go ahead and assign that to the player.

And while we are at it, I will also assign a fight componentthat I added which allows you to pick up balloons and throw.

So let's see what that looks like.

Yay, now I can pick up the balloons,and he's stopped at the boundaries.

That's awesome.

We'll go ahead and do the same to the enemy, so for that,I had a game object, enemy object created in the scene,but I had set it to invisible, so I'm going to enable itin the scene outline view.

And go ahead and assign the components to the enemy.

So in this case, the difference is it's a enemy input componentso that it picks up the game AI rather than use the keyboard,and similarly, movement component, collision component,as well as the fight component.

And with that, I would expect the enemy also to pickup the balloons and, yeah, he got me.

That was quite easy for him, but we're goingto make the gameplay a little bit more interestingby dropping some balloons into the scene using a drawn object.

So I have a drawn object that I will make visible in the sceneand go ahead and add a drawn component,which basically does the dropping of the balloon as wellas follow a certain path.

So I want to add a navigation graph to the scene,and that's as simple as going into the object libraryand typing in "nav graph."

Now, you can just simply dragand drop the nav graph to the scene.

So we'll just make the navigation graph a little biggerto demonstrate the feature.

So here's the navigation graph editor.

And while we are at it, we'll also change some properties.

We'll set the health to be 2 and the movement for the player,speed up a little, give some advantageto the player a little bit, just a level 1, so, hey,you got some advantage.

And enemy will get health of 2 as well.

And let's see what we have.

You know, you can see that the drone is dropping more balloonsthat I can pick up and throw.

He got me and I got him once, but let's see.

Yay. All right.

I'm sure my son will have a lotof fun playing this game [applause].

That pretty much demonstrates the new editor-based workflowfor GameplayKit.

Let's switch back to the slides.

So to recap the session, this year,we have introduced many compellingand useful features to GameplayKit.

In the beginning, Bruno talkedabout the next spatial partitioning systemfor efficient spatial queries in your game.

The new procedural generation systemfor using various noise functionsto create more dynamic content in your game,as well as improvements to existing systemssuch as pathfinding and agents.

And Michael talked about the additions to game AIwith gameplay strategists and decision trees.

And I finally covered the newly introduced editor-based workflowof GameplayKit for faster iteration.

I hope you find these features useful and we can't waitto see what you come up with next.

And here is the URL for this session to check out for later.

Number 608 is the session number.

And here are a few sessions on related technologiesthat you might be interested in attending.

What's New in SpriteKit, SceneKit, Rendering,Game Center, and Game Technologies for Apple Watch.

Thank you for coming,and we hope you enjoy the rest of your conference.

[ Applause ]

Apple, Inc.AAPL1 Infinite LoopCupertinoCA95014US

ASCIIwwdc

Searchable full-text transcripts of WWDC sessions.

An NSHipster Project

Created by normalizing and indexing video transcript files provided for WWDC videos. Check out the app's source code on GitHub for additional implementation details, as well as information about the webservice APIs made available.