-
Notifications
You must be signed in to change notification settings - Fork 42
Movement states
Movement is the most important part of Erbium. I used state design pattern so it's much easier to control the current movement and to switch between them.
The character has a movement component, which is changing constantly depending on the logic you want to implement(the character is falling? then he should be in a falling state, etc..).
The main principle of the state component is that the parent class(Character) is not in charge of changing the movement state. The change is coming from other sources(inputs, physic state, entering the trigger, etc...). It's really important not touching movement in the character class. Try to change the state changeMovement(MovementEnum movement)
in state-related classes.
IMovement is the main interface for every movement class. Every movement should implement this interface. Let's discuss its methods.
Every movement has 3 stages of the life cycle to make it easier to set attributes(set animations, rigidbody attributes, change camera, etc...) inside every state and then set them to default ones.
void setUp()
Set the attributes you need for this state. Usually, here you should put animation bools, rigidbody attributes, character attributes, etc.. for this specific state.
Typical cases:
- Disabling gravity, adding gravity scale
- Set animation bools - onGround, falling
- Disabling components
- Changing camera perspective
- etc..
void move(Vector3 direction)
The main move method which is called every fixed update tick. It doesn't have a lot of mystery, takes the``Vector3 Direction` and moves the character as you want.
Important: don't use any input/camera related stuff here. You should pass the direction where you want your character to move, so the direction should be calculated in a different class(ICameraDirection for the player).
Don't forget to add rotation and update animator attributes if you need to do it every frame.
changeMovement(MovementEnum movement)
Changes movement state. You should use this method only in classes that implement IMovement
void cleanUp()
Before changing the movement state we need to set all attributes that were set in the Set Up cycle to the default values.
Let's see the flow of a falling change state. Let's imagine that the character is walking off the cliff and starts falling. We have to check every frame if the player is on the ground. If he is not then we have to change the state to midairMovement. But it's important to remember to call the cleanup and setup methods. That's why we invoke changeMovement in the ICharacter class.
There is an abstract class with a basic constructor to get values from the characters and a rotation method which you can override. For your movement class try to extend this class if it goes well with the class you want to create.
In the standard definition of state design patterns, when we change the state, we create a new one. It's not a problem in a normal app, but it's a big problem in Unity because of the garbage collector. The solution is to initialize all of the movements and put them in a dictionary so later we can get them by a key, which is an enum. There is another problem with that because of a dictionary with an enum as a key produces a lot of garbage as well, that's why I had to implement a custom enum comparator. You can find more on this topic here
When you are creating a new movement class, don't forget to initialize it in a start/awake method of a character class, create an enum, and put that into a movement dictionary of the character.
To create your movement class you should follow the next steps:
- Create a class inside
character\movement
folder - Extend AbstractMovement or implement IMovement
- Override methods that you need
- Create an instance of that class in the character start/awake method
- Add new movement name to the MovementEnum
- Put new movement to the dictionary
That's pretty much it, be careful when you change the state!