
In today's article, I'm going to show you how to make your player roll, manage states and basics of animation.
Creating a new action in the Input Map
Before we start writing our code, let's create a new action into ourInput Map
namedroll. I've attached the letterK
on the keyboard, but you can bind any key you prefer.
Adding a new state
Open thePlayer.gd
script and lets update ourstates
enum, adding the actionROLL
.
enumstates{MOVE,ROLL}
Using_input(event)
to change states
In the previous article I introduced the_input(event)
method, now, we're going to use it to change the player state based on the player input!
## Called when player input is detected.## @param event: InputEvent## @return voidfunc_input(event):ifeventisInputEventMouseButtonoreventisInputEventMouseMotion:return;# Only process input if the player is in the MOVE state.if_current_state==states.MOVE:# If the player presses the roll button, then the player should roll.ifevent.is_action_pressed("roll"):# sets the _current_state to states.ROLL_current_state=states.ROLL;
First, we're going to check if the player is in theMOVE
state, this will prevent the player from rolling mid attack, or attack mid rolling.
Then, we check if the player pressed what is mapped to theroll
, if so, we change the current state toROLL
.
Updating player movement
Now that we changed our state toROLL
, we need to tell the script what to do when the player is in this state.
Let's start by creating aroll
function, like we created with themove(delta)
. And as we did in themove(delta)
function, we'll create a new variable, the_roll_speed
.
@exportvar_roll_speed:float=130;
Now, we update the_physics_process(delta)
function to add the call to the roll function.
# delta = time between framesfunc_physics_process(delta):match_current_state:states.MOVE:move(delta);states.ROLL:roll();
The editor will throw you an error since we don't have aroll()
function created, so let's scroll all the way down on our script and create a new function.
funcroll():velocity=_roll_speed;move_and_slide();
But wait, we can't simply say the velocity is the_roll_speed
, we need a vector, just as we used theinput_vector
in ourmove(delta)
function.
So let's create a new variable that will receive the input vector and we can use in our roll function.
var_roll_vector:Vector2=Vector2.RIGHT;
This will create a_roll_vector
variable we can use and will initialise its value to right.
Now, ourroll()
function will look like this:
funcroll():velocity=_roll_vector*_roll_speed;move_and_slide();
And we can't forget to update ourmove(delta)
function to set our new_roll_vector
. Let's add the following code before we update our velocity.
# This will be used in the roll() function.# This will be used to determine which direction the player should roll._roll_vector=input_vector;
And why we update only when the player moves? Because this will keep the player "facing diretion", so if the player decides to walk to the left, we store this "last facing direction" to our_roll_vector
, if the player stops, this variable will keep this state, when the player rolls, it will roll to the left.
Run the player
We're ready to run our game! But notice one thing, if we roll, the player keeps going, and going and we can't stop it! But why this happens?
In the_input(event)
function we only accept input when the player state isMOVE
, but we don't have anything telling the script to revert to theMOVE
state.
To solve this issue, we're going to use animations!
Creating the animation node.
Let's get back to our player node in Godot and add two new nodesAnimationPlayer
andAnimationTree
.
Notice theAnimationTree
have a warning sign next to it, this is because it needs to be told how it should handle animations. Select theAnimationTree
node and on the right side, in the inspector, and update theTree Root
to useAnimationNodeStateMachine
The next step, is to assign theAnim Player
to the animation player we created.
This will open anAnimationTree
window on the bottom of Godot, we're going to create a couple of animations (even though they're just the godot icon 😅), and update the animations through our script!
Creating new animations
First, select theAnimation
tab in the bottom panel, then, in new panel, click onAnimation at the top and then select the optionNew.
Let's create animations for idle, walk and roll. Each of them having the facing direction, for example, idle_left, idle_right, so on.
You should have something like this
Understaing The animation window
Let's start by updating theroll_right
animation, select it on the drop down and the first thing we're going to do, is to add our sprite to it!
To do this, keep the animation window open, select theSprite2D
node in the scene and underAnimation in the inspector, select frame 0 and press the key icon to the right of it.
This will open a new window, just press create.
This will add our sprite to the tracks!
Cool! we have our first track with our sprite! But before continuing, let's update some options in the window, to make it easier for us to work.
In bottom right of the animation window, change from seconds to FPS.
Here is where we tell how many frames the animation will have, for the roll animation, lets pretend we have 4 frames, so let's update the value on the left to 4!
If you press the play button in the animation window, you'll notice that the track will stop on frame 4 (it counts 0,1,2,3), signaling the engine that the animation ended.
Adding aCall Method Track
TheCall Method Track lets you call a methoid in a script at anypoint of the animation you want! Which is great! because we're going to use this to change the state of our player.
CLick on the+ Add Track and selectCall Method Track.
This will open a new window for you to select a node to animate, in this window, select the player. We're selecting the player node becuase we're adding the script there.
Once you're done, this will create a new track in the Animation window.
Let's get back to ourPlayer.gd
and create a simple function that will set the state back to move, let's call iton_roll_ended()
.
funcon_roll_ended():_current_state=states.MOVE;
Now, to add your script, make sure the blue vertical bar is at the last frame of your animation (in this case, the end of the third frame beginning of the forth), right click it and pressAdd Key.
In the new window, select the method we just created:
This will tell the Engine that when the roll_right animation ends, it should call the method we assigned.
Before we continue, do this for all roll animations 😄.
The animation Tree
We're almost done, we need to set up the animations in the animation tree so we can use it on our scripts.
Select both animation tree under the player node and in the bottom panel.
You'll see a Start/End blocks, we're going to create a few more, one for idle, one for walk and one for roll. Right click anywhere between Start and End and select theAdd Blend Space 2D option, once it's created, double click the text and rename it toIdle, do the same for walk and roll.
Now, let's link these aniumations together!
There are a couple of tool in to top left corner of the Animation tree
From left to right:
- Select ToolWith this selected, you can click on any node in the animation tree.
- Add ToolWhen this is active, clicking anywhere in the animation tree with the left mouse button will open the add pop-up.
- Connect ToolWhen Connect Tool is selected, you can link animations together.
- Delete ToolDeletes the selected node.
Select the Connect Tool and let's start linkin them. To link animations, click on the node you want to link and drag to the next node.
You should have something like this.
Before we proceed, schange to the select tool and select the lines between nodes, now in the inspector, navigate toAdvance and change theMode property toEnabled.
Do this to all connections!
One last step!! (I swear, it's almost at the end) press the pencil icon in theRoll
node, this will open a window with the details to the Roll (or any animation you pressed) animation.
Let's add our animations we created in theAnimation
window here, and we're ready to use them!
First, change the blend mode to the tree dots here:
Now, select the select tool in the top left corner.
Right click as close as you can to the 0 in the left of the graph > add animation > roll_left. Now, when we set the blend position in our script, it'll update the animation based on the X and Y positions. Do this for the remaining animations!
At the end, you will have something like this:
!! IMPORTANT !!
in Godot, up = -1 and down = 1, that's the reason we add the down animation up and up animation down.
Updating animations in the script
This is our last step, calling different animations in our script! Open the player script and let's start working on calling these animations!
Open the Player Script, first things first, lets get our nodes in the script, we can do so like this
@onreadyvaranimationTree=$AnimationTree;@onreadyvaranimationState=animationTree.get("parameters/playback");
There are a couple of new keywords here, let's explore them.
- @onready Tells the engine that this variable will be loaded once the player (or the node) is loaded into the scene tree.
- $AnimationTree having the
$
sign is a syntax sugar that would be the same as callingget_node("AnimationTree")
.
Enable the AnimationTree
In the_ready()
function, add the following code, this will enable the animation tree once the player is ready.
animationTree.active = true;
Setting up the blend position
In this step, is very important to use the exact names in the animation tree, otherwise you'll get some errors in the run time.
The recipe to set the blend position is:
animationTree.set("parameters/<Animation_Name>/blend_position", <movement_vector>);
Let's add the following code in the_physics_process
function. First, the idle animation, just beneath theif input_vector == Vector2.ZERO:
animationTree.set("parameters/Idle/blend_position",input_vector);
And for walk and roll animation we can set after the_roll_vector = input_vector;
_roll_vector=input_vector;animationTree.set("parameters/Walk/blend_position",input_vector);animationTree.set("parameters/Roll/blend_position",input_vector);
Calling animations
In this last step, we need to tell the animation state which animation should be playing.
Let's call our animations,Idle
,Walk
andRoll
.
The code is really simple, just use:
# For IdleanimationState.travel("Idle");# For WalkanimationState.travel("Walk");# For Roll animationState.travel("Roll");
For the Idle, call it after setting the Idleblend_position
. For Walk, call it after setting the Walkblend_position
and for Roll, call it in theroll()
function.
ifinput_vector==Vector2.ZERO:animationTree.set("parameters/Idle/blend_position",input_vector);animationState.travel("Idle");
_roll_vector=input_vector;animationTree.set("parameters/Walk/blend_position",input_vector);animationTree.set("parameters/Roll/blend_position",input_vector);animationState.travel("Walk");
func roll(): velocity = _roll_vector * _roll_speed; animationState.travel("Roll"); move_and_slide();
CONGRATULATIONS!
Phew, that was a long one, but now you now how powerful the animation can be in Godot!
Now, when you run the game, once you press the Roll action, your player will roll to the last facing position!
Thank you!
I hope you're enjoying this series as much as I'm enjoying writing them!
Thank you for reading it, any problems or questions drop a comment below and I'll get to it!
Thanks again, and I'll see you in the next article!
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse