Welcome to part 2 of this Unity tutorial series where we’re creating a survival shooter
game using Unity’s new implementation of the Entity Component System pattern, or Unity
ECS for short.
In part 1 we configured the editor and imported the Entities package, which contained all
of the classes need to work with Unity ECS.
In this video we’ll begin implementing the first half of player movement, which we’ll
finish in part 3.The goal is to get the player’s avatar to move in response to vertical and
horizontal input from the controller.
So where do we begin?
Well, when you’re working with the Entity Component System pattern it’s important
to always think in terms of data and behavior.
Data is stored within components, which are simple data containers that are attached to
entities.
In Unity ECS components come in one of two forms; MonoBehaviours and structs that implement
IComponentData.
MonoBehaviours are used for hybrid ECS and IComponentData structs are used for pure ECS.
We’ll examine the differences a little later on in the series but for now we’re going
to take the hybrid approach and stick to MonoBehaviours.
So what sort of data is required for player movement in our survival shooter?
Well we know from documentation that Unity’s static Input class has a GetAxis method that
returns a value between negative and positive one for horizontal and vertical input.
We can leverage this data to produce the kind of behavior that we’re looking for.
A positive value on the horizontal axis should cause the player avatar to move to the right,
and a negative value from the vertical axis should cause the player avatar to move down,
and so on.
This sort of behavior used to be defined right within MonoBehaviours attached to GameObjects.
But with Unity ECS behavior is stored within systems, which are classes that perform logic
on a list of entities that contain a specific set of components.
Unity ECS Systems implement one of two base classes; ComponentSystem and JobComponentSystem.
Again, the variations relate to hybrid ECS and pure ECS respectively.
And again we will be sticking to the hybrid approach, for now.
So let’s get started by creating our first component; the one that’ll hold our input
data.
Since we’re sticking to the hybrid approach, all we need to do is create a MonoBehaviour.
I’ll name it “InputComponent”.
Now we can add two floats to hold the values of the horizontal and vertical axes.
Back in the editor we can add InputComponent to a prefab that has everything we need to
represent the player.
Alright, we’re almost ready to start defining behaviour, but there’s one more important
aspect of ECS that we still need to cover.
We’ve talked about components and we’ve talked about systems, but it’s called the
Entity Component System pattern right?
So what about entities?
Well, an entity is an object that has a collection of components.
Systems iterate over subsets of entities based on the components that they have in their
collection.
We’ll need to transform the player GameObject into an entity so our system can access it.
As you’ve probably already guessed, there are two ways to create entities in Unity ECS;
the hybrid way and the pure way.
Sticking to the hybrid approach, all we need to do is attach a GameObjectEntity component
to the player GameObject.
This will cause Unity to register it as an entity and all of its MonoBehaviours as components.
There’s a little bit of magic involved here in order to give each system access to the
appropriate entities.
Let’s explore that now by creating our first system.
It’s sole purpose will be to define player movement behavior, so I’ll call it “PlayerMovementSystem”.
The first thing we’ll need to do is make it implement the ComponentSystem base class
and the OnUpdate method.
Next we need to define which entities this system should iterate over.
Systems only care about entities that contain a certain subset of components.
We can represent that subset of components by defining a struct that has those components
we want to filter entities by.
The PlayerMovementSystem only needs to operate on entities that at least have a Rigidbody
and an InputComponent, so I’ll add those to the filter.
Now we can utilize a method provided by the ComponentSystem class called “GetEntities”
to iterate over the entities that meet the requirements of our fitler.
Again, there’s a little bit of magic in the way that Unity ECS is written that handles
this in an extremely optimized way.
The last thing we need to do is implement player movement behavior with some fairly
basic logic that’ll be applied to each entity in the list.
In our case, there'll only ever be one entity in the list; the player.
Now we aren’t actually consuming Input just yet, but we can still test this behavior by
manually setting the values of the InputComponent from the inspector when the scene is running.
We can also confirm a couple of important details using the very handy Entity Debugger,
which you should definitely have docked somewhere in your editor.
The first thing we can check is whether or not our entity has been registered by clicking
on “EntityManager”.
Sure enough there’s “entity zero”, complete with all of it’s MonoBehaviours which have
been converted to ECS components.
The next thing we can do is make sure that the player movement system has been loaded
by searching for it in the same list that we found the entity manager.
There it is, and check it out.
It’s even got “entity zero” in it’s list of entities.
That means our filter worked!
Now we’re ready to test our behavior.
With the scene still running, I’ll select the player GameObject and manipulate the horizontal
and vertical values of the input component.
First horizontal.
Now vertical.
Beautiful.
Just a heads up, the Unity project used in this video, which you’ll see evolve throughout
this series will be available for download to my tier two patrons.
You are, of course, free to copy the code you see as you follow along, but if you’re
feeling a little lazy or you’d like to support my work, please consider becoming a patron
today.
I’ll even include some bonus content for each part of the series.
The package for part two, the one you’re currently watching, will include some integration
tests that asserts the correctness of the logic used in the player movement system.
So we’ve got our player movement behavior defined, which is based on input data.
In part 3 of this series, we’ll actually begin consuming player input and transforming
it into the data that the player movement system needs to operate correctly.
We’ll also take a look at an alternate method for filtering entities at the system level.
If you found this tutorial helpful, please leave a like and a comment letting me know
what you thought.
And for more Unity tutorials just like this one, don’t forget to subscribe with notifications
on.
I’ll see you in the next video!