How to implement STATE MACHINE, HURT ANIMATION, SCREENSHAKE in GDEVELOP
Welcome to the Eighth entry in our Gdevelop FREE VISUAL Game Engine, where we are building a Contra’s like game.
In this article , we are going to go further in modularizing our game to make it easier to control aspects of the game. We are going to implement the player damage and death animations and we are going to add some screen shakes when hits happen.
Welcome to Part 8, in our tutorial series on how to develop a contra’s like-game, with free visual game engine G DEVELOP.
In this video, we are going to go further in modularizing our game to make it easier to control aspects of the game. We are going to implement the player damage and death animations and we are going to add some screen shakes when hits happen.
To control it correctly without having to make a lot of complex code, we are going to shift our player to a state machine that will manage all the different behaviors that the player can have.
But first, as always, let’s quickly check what we have done in the previous videos and what is the current state of the game
We can move, jump, and shoot. The enemies are correctly spawned and we can correctly shoot at the enemies and kill them with some simple damage effects.
It is starting to take shape.
So, to implement the player damage we need to create the damage or hurt animation.
Go to the scene view, and double click on the player object, on the scene, or, on the objects pane.
Click the ADD Animation button and name hit PLAYER HURT. Click on the ADD box to open the file explorer and select the HURT Animations for the player.
When imported, these animations are supposed to be played only once, so there is no need to click the LOOP option.
Click on EDIT POINTS to set the origin point of the new animation to the same position as the other animations, in our case 165 on X by 250 on Y, as to put it in the center bottom of the sprite.
Click Close to exit the edition of the points, and then APPLY to leave the OBJECT propriety edition.
Now, we need to modify the way our player code is working. As we have done in the case of the enemy, as we validate some of the code and before starting adding a lot of new features, it is important to consolidate what you have, to make sure that you will be able to keep control of the code.
The way we have implemented the player mechanics is working, but we can see that in some cases managing the animations was somewhat complex, and now if we are to add HURT and DEATH animations, the level of complexity is to increase.
So before adding them, let’s restructure the player by using state machines.
State Machines are an abstraction for coding, that allows you to manage the complexity by defining different states where an object can be. Each state has associated with it, a set of instructions that needs to be run, a set of entry conditions that will define when we can move from a state to the other, and a set of exit conditions, that will define what would be the next state to run in case the conditions for the exit are met.
By implementing a state machine, you don´t need to think about all the possibilities that can happen to your object, you just think in the context of the state you are in, which makes it much easier to manage.
The question is: How can we implement state machines with G DEVELOP?
The answers are not straightforward or too easy, but it is not very complex too. We can implement it by using External event sheets. So, each state in our state machine is a new event sheet that is enabled and ran the player is in a certain state.
For that, we need to think about what will the states that we are to use.
In our case, we have thought on the following states:
Init that is called the first time the player is created.
Idle, for when the player is not doing anything
Moving, for when the player is moving right and left
Jumping, for when the player is jumping
Falling, for when the player is falling from a jump, or from a platform
Damage, for when the player is taking damage
Dead, for when the player has been killed and the game needs to restart.
To create the new states we need to perform three different actions, Creating the Links that will connect the event sheet to the new EVENTS SHEETS. Create the new EVENTS SHEETS and then associate them one to the other.
For the LINKS, from the ADD button on the top bar, and then selecting LINK. Do it a couple of times to have some links.
For the EXTERNAL EVENTS SHEETS, from the project manager button on the left top bar, click on EXTERNAL EVENTS to open the interface, and then by clicking on the PLUS sign, create the new events sheets that will be implementing the new states. Rename each of the new events being created to the correct name by clicking on the 3 dots to the right, or by RIGHT CLICKING on the event name and then click on rename to the name that you want to assign to the states.
In our case PlayerInit, PlayerIdle, PlayerMoving, Player Jumping, Player Falling, Player Damage, Player Dead.
Before linking the event sheets into the project, let’s first add a variable to the Player Object that will hold the current state that is being run.
For this, go to SCENE VIEW, click on the Player Character, and in the LEFT PANE, click on the Button with the ARROW pointing up near INSTANCE VARIABLES. In the new dialog box, click on EDIT OBJECT VARIABLES, and then click on the Button ADD to a new variable named STATE. Set its original value to INIT, and since we are here, let’s initialize the HEALTH to 10.
Click Apply to close.
Go back to the EVENT view and start to associate the links to the new external events that we have just created.
Click on all the links created in the previous steps and associate it from the popup menu to one of the external events sheets.
Once all the links are associated with their respective event sheet, let’s start to address moving from one event sheet to the other based on the state of the player.
Create a new event, and for the condition, select PHYSIC PLAYER and in the search box type variable. Select TEXT OF AN OBJECT VARIABLE and then in the right pane, the variable STATE. For the Sign of the Text select Equal to and then in Value type INIT.
Leave the actions empty and then drag as a subevent the Link to the PLAYERINIT event sheet.
Copy-paste a couple of times the event. In our case, we also copied the subevent that we had to delete afterward, so it is better to copy on the event where the state is being checked.
Modify the text being compared to each of the state conditions that you want to use.
In our case: IDLE, JUMPING, FALLING, MOVING, DAMAGE, and DEAD.
As you modify the state tags, drag the respective link to the external event sheet into its right place below the event.
Let’s also create a new group, to clean somewhat the overall events, and call it PLAYER STATE MACHINE.
Drag all the events related to the state machine into the group.
Time to create the states. Let’s start with the Moving State.
Click in the BOX with the ARROW pointing up to the right of the Link to the Player Moving event sheet.
A new dialog box will pop up, asking you to enter the scene in which you want to link the external event sheet.
This is a default question, so you are not actually making the new event sheet to just the select scene, but G DEVELOP needs to set it.
Click on CHOOSE SCENE and then, in the next dialog box, select the current scene.
Once finished, we will be presented with an empty sheet.
We need to move in this event sheet, all the events that we have created in the previous episodes that deal with the player movement.
Go back to the SCENE EVENTS, and select all the events dealing with the player movement and paste them in the new PlayerMoving event sheet.
Repeat the same steps for PLAYER FALLING, PLAYER JUMPING, and PLAYER INIT.
In this last case, we will found that we have nothing to copy from, as it is the first state the players start in, and that will get moved afterward to other states.
It could be also a good time to highlight clearly what are the actions to be performed and what are the transitions to other states.
Click on the PLUS SIGN on the TOP BAR and add two new groups, name the first one ACTIONS and the second one for TRANSITIONS.
Once done, create a new subevent under TRANSITIONS. Leave the condition empty and in the actions let’s sets the STATE Variable of the player to what will be the next state.
Click on ADD ACTION and then select PHYSICS PLAYER. Type VAR on the search box, and then MODIFY THE TEXT OF AN OBJECT VARIABLE. In the right pane choose the variable STATE.
In the modification sign choose SET TO and between quotes “FALLING”.
Click OK to close.
So, when our player starts the game, he is hanged on the air, and set to FALLING, which is actually what he does when the game starts.
Let’s go now, to the event sheet Player Fallng event sheet, which will be the first state of the player.
Let’s ADD also here some of the same formattings for the ACTIONS AND TRANSITIONS by click on the PLUS BUTTON on the top bar and then GROUPS.
Let’s drag the actions that we had copied under the ACTIONS group.
Under transition, let’s create a new subevent by clicking on the button on the top bar.
For the CONDITION let’s check if the PHYSIC PLAYER is on the floor by testing the platformer behavior method ISONFLOOR.
So, if we were falling and now, we are touching the floor, this means that we have stopped falling and just landed on the grounded or platform.
Add a new condition and check if not the key is being pressed, which will represent that we have fallen to the ground and we are not moving and we should be going to the STATE IDLE.
So, ADD and action, select the PHYSIC PLAYER and then the MODIFY THE TEXT VARIABLE OF AN OBJECT for the STATE variable and set it to IDLE.
Copy the event, and paste it, and change the condition where we are checking if any key is pressed from inverted to normal, and then if any is being pressed then change the VALUE to be assigned to STATE to MOVING.
Let’s go now to PLAYER MOVING, and let’s make all the events sheets consistent between them, so ADD the TWO Groups for ACTIONS AND TRANSITIONS.
Drag the events under the ACTIONS GROUP.
Add a new SUB EVENT TO TRANSITIONS.
Add a condition to check if the PHYSIC PLAYER IS moving, in which case, we are going to set the STATE to IDLE.
But it could happen, that we are falling and not touching any key, so let’s add a sub-event wherein the condition we are going to test if the PHYSIC PLAYER is on the ground or not.
Drag the event that we created previously under this new event.
Let’s create a new event to check if we are jumping. We have the conditions to the event, in the PLAYER JUMPING STATE where we copied the events associated with jumping.
Let’s go to the PLAYER JUMPING STATE and copy the conditions associated with the jump, and then go back to the PLAYER MOVING STATE and paste them in the conditions of the new event that we have just created.
Copy the action to change states to IDLE and paste it in the new event, and change the STATE to JUMPING.
Go back to the SCENE EVENTS and let’s create the PLAYER IDLE STATE by clicking on the link associated with it and then going through the process of choosing the scene.
Create the groups for the ACTIONS AND TRANSITIONS and add a new subevent to the ACTIONS group.
Add a new action to the event and select the PLAYER and then Change Animation by name and in the animation-name text field type PLAYER IDLE, which is the name of the IDLE ANIMATION for the PLAYER:
Add now a new subevent to the transitions and let’s see when you can leave the IDLE STATE.
IN the condition test if the PHYSIC PLAYER is moving and for the Action, set the TEXT VALUE OF THE VARIABLE OBJECT to MOVING.
We can also leave the IDLE STATE by Jumping, lo let’s check if the player has pressed the JUMP key and if it is the case then let’s set the variable STATE value to JUMPING. Although in the video, we have made the mistake of typing the only JUMP.
Since we are addressing a JUMP, let’s go to the JUMP state to make sure it is correctly setup.
Again let’s add the groups for ACTIONS and TRANSITIONS. Drag the existing events under the ACTIONS group.
Add a new subevent to TRANSITIONs, and let’s check if the PHYSICS PLAYER IS ON THE FLOOR; in which case let’s change the STATE TO IDLE.
Add a new subevent, and this time for the condition, let’s check that the PHYSIC PLAYER is not on the floor, which means that it is falling and there so, change the STATE VALUE TO FALLING.
Let’s go to PLAYER INIT, and ADD a subevent to the ACTIONS GROUP, leave the condition in blank and add an action associated to PHYSIC PLAYER and in the search box type CONTROL, then from the options choose IGNORE DEFAULT CONTROLS and set it to no.
Go the PLAYER IDLE STATE, and in the ACTIONS GROUP, Add a new action to set the animation of the GUN to GUN IDLE.
And let’s run the game to see if what we have implemented is working correctly or not. AND …
We are not able to do anything. So no moving, no jumping. Let’s check where could error be.
One of the errors is on the PLAYER INIT STATE, when added the IGNORE DEFAULT CONTROLS, we should have set it to YES, and instead we have set it to no. Let’s correct the error and change the condition to YES.
Let’s check the PLAYER FALLING State too. Everything seems to be OK. Let’s just indent some of the events as to put them below the groups.
Let’s check the PLAYER IDLE STATE. Part of the problem could be here, associated with the testing of the PHYSIC PLAYER being MOVING. Let’s delete it, and replace it with a check on If we are pressing the keys associated with the movement.
Let’s run it again, to see if we have been able to solve it, and still, nothing is happening. Plus we are not sure what is the state is being run and if we changing correctly between states.
To be sure, we need to have some debug information being displayed onscreen to make sure that everything in the code is running as it should be.
So, let’s create a debug function.
Go to the scene view and create a new TEXT OBJECT and name it DEBUGINFO, or any other name,
Select a color and a font size to have the information shown on screen. Let’s initialize the text to INIT, which will be the first state that the player will have.
Click Apply to close.
Let’s drag it to the scene.
Now. we need to have it always under our eyes, so let’s create some code that will place the DEBUG INFO at all times near the player. So you can either create a new event with a blank condition, or look for the event where we refresh the position of the sprites with animations to the PHYSICS PLAYER, or create a new event for it with an empty condition.
Either way, set the position of the DEBUGINFO text box to the Player Position, and set its text value to the value of the STATE variable.
Let’s try it.
Well it is running but the text is very small and practically invisible, so we will need to increase the size of the font.
Run it again, and now we can see what is the state we currently are in.
If we try to move the player, we can see that we are not leaving the INIT state, which means that the VALUE for the state is not being modified. Let’s go to the main scene event sheet and see what is happening.
Ok, when we were comparing the value of the STATE, we didn´t include the quotes in the text. So add quotes to the text on each comparison.
Let’s check it again, and we can see that now we are changing correctly between states.
Ok, most of the things are working, but we are not able to jump now. But that shouldn´t be a problem, because now, we know that it will certainly be related to the JUMP STATE or what will transition into the state.
The first problem is that we are not making sure that we are not jumping when performing the jump or we will be double jumping. Although this is not responsible for not jumping. So, let’s check too, where we are transitioning into the JUMP State.
Let’s add a new condition in the event. Select the PLAYER PHYSIC and then on the condition is the IS JUMPING OPTION and invert it as to only be true if the the PLAYER is not jumping.
Let’s continue to search for where the problem could be located.
Ok, in the PLAYER IDLE State, we are setting the STATE variable to the wrong value, it is JUMPING and not JUMP.
Run the game, and now, we can jump correctly. But we have another problem, we are not able to shoot in the IDLE State, Only when we are moving. Let’s address this issue by copying the fire events to the PLAYER IDLE.
In the PLAYER MOVING State, we had a group of events that were associated with the fire when not moving, so let’s copy them to the PLAYER IDLE STATE.
Ok. It is working, we are now firing from the IDLE STATE too.
It is now time to implement the hurt animation and as a bonus, some damage effects.
For that, we need to copy the events where we were checking if the player was being hurt, to the PLAYER DAMAGE state. This will allow us, when implementing the hurt animations, to have better control of the player for the time the player is receiving the hurt, and that is defined by the duration of the hurt animation. If we wanted to implement a knock back, it would also be the place to make it in a very easy way.
When going to the PLAYER DAMAGE state for the first time, you already know how to deal with the scenes and the creating of the groups for actions and transitions.
Paste the new events under the actions group.
Add a new condition to the event where the player is receiving the damage, associated with PLAYER SPRITE, where we are checking the PLAYER is not currently running the HURT ANIMATION. This is to avoid that the player could be restarting the animation every time he receives an impact.
So for the duration of the HURT ANIMATION, he will play only once the animation and will only receive once the damage. So for that, in the condition SELECT THE PLAYER SPRITE, and in the search box type ANIMATION. From the list choose the CURRENT ANIMATION NAME and type in the value field PLAYER HURT. Invert the condition as we want to make sure the animation is not yet running.
Click on OK to close.
Now, let’s add the transition to another state, which in our case can only be two different states, IDLE, and a future DEATH that we will create in another video as death states are more than just deleting the player.
So, add a new event into the TRANSITION STATE, and in the condition for the PLAYER SPRITE select ANIMATION FINISHED. Add a new condition where we are going to check if the animation that was being played was PLAYER HURT by choosing the CURRENT ANIMATION NAME condition and setting the value to PLAYER HURT too.
These conditions are not going to stay here in the state, as we will move later on to the SCENE main events.
In the action, select the PHYSIC PLAYER and then MODIFY TEXT VALUE OF VARIABLE OBJECT. In the variable field select the STATE variable. In the modification sign, SET TO.
And in the value IDLE as we will be moving from the DAMAGE State to the IDLE. If you want it in any other state, just set the value to any of your own states.
Now let’s move the conditions to the right place.
Copy the entire group for PLAYER HEALTH, and goto the SCENE Main events.
Paste in the group. And delete the actions. In its place, let’s SELECT THE PHYSIC PLAYER and Modify the value of STATE to DAMAGE.
Let’s go to the SCENE VIEW and duplicate the ENEMY DEAT PARTICLES object. Name it PLAYER DAMAGE PARTICLES.
Let’s go to the PLAYER DAMAGE STATE and in the actions associated to the player receiving damage, create a new ACTION. Select the PLAYER DAMAGE PARTICLES object, and in the function CREATE.
Set the position X to player X and position Y to PLAYER position minus 100. Be sure to have the layer selected to GAME.
Create a new action for the recently created PLAYER DAMAGE particles, and in the functions select the Z ORDER and set to the PLAYER SPRITE Z ORDER plus 1, as to guarantee that the effects will always be above the player.
Run the game to see if everything is running as it was supposed. And we can see that the player is correctly receiving the impacts showing the animation and the damage effects.
Let’s try to implement the screen shake when the player is hurt. But before that, let’s delete the conditions on the PLAYER HURT because we don’t need them there anymore.
First thing is to create a global Variable for when the SCREENSHAKE is active. For that Click on the PROJECT MANAGER on the right TOP BAR, and then on Click on GAME SETTINGS and Finally on GLOBAL VARIABLES.
In the dialog box that opens up, click on the button ADD and name the variable SCREENSHAKE set its initial value to 0 which will mean that no screen shaking is occurring.
Click apply to close.
Now, let’s go to the SCENE main events window, and, in the event that sets the player state to DAMAGE let’s add a new action that will set the Global Variable SCREENSHAKE to 1.
So, in the action dialog box, in the search box type global and select the option VALUE OF A GLOBAL VARIABLE. IN. In the variable field choose the SCREENSHAKE variable and in the modification sign, SET TO.
Finally, in the value enter the value 1.
Click ok to close the action window.
Now, we will need also a timer to control how long we want the Screenshaking to happen. After the added action, add a new one.
In the search box type Timer, and the action lists choose START OR RESET A SCENE TIMER. In the timer’s field name, type the name of the Timer between quotes. In our case SCREENSHAKETIMER. Although in the video we have initially set it to SCREENSHAKETIME, just use the first name we referred. We will modify it later on in the video.
Click OK to close.
Now, let’s implement the screen shaking.
ADD a new group by clicking on the PLUS BUTTON on the TOP BAR, and Then GROUP.
Rename the group to SCREENSHAKE and add a new event to the group.
For the condition, we will check if the VARIABLE SCREENSHAKE has been set to a value bigger than one, and if not, it has not finished.
So in the condition search box type GLOBAL, and then choose the option VALUE OF GLOBAL VARIABLE.
In the Variable field choose SCREENSHAKE, in the modification sign Bigger than, and in the value, 0.
Let’s add a new condition where we are going to check the value of the timer to see if we have reached the end of the screen shake. For that, in the condition search box type Timer, then choose the option VALUE OF SCENE TIMER.
In the timer value set 0.2, and in the timer’s name type between quotes SCREENSHAKETIMER. Check the Invert Timer, as we want only to get in the function while the time is below the value.
Click OK to close the dialog box.
But, thinking better, let’s change the value of the timer to 1, which is the same value for the SCREENSHAKE.
Let’s add the actions, and select the Camera Position X, then in the modification sign, choose SET TO, in the VALUE field type in, PHYSIC PLAYER X + GLOBALVARIABLE SCREENSHAKE multiplied by SCREENSHAKESIGN.
This is a global variable that we have not created and that we are going to create next.
The purpose of this value is to be switching between positive and negative 1, which will be causing the values calculated to be alternating around the player position.
Set the layer to be GAME.
Copy the function that we have calculated for the camera X, as we will need for the position Y of the camera too.
Add the new action, and now select the Camera Position Y and repeat the previous steps.
In the value field, paste the previous formula and switch the PHYSIC PLAYER X by PHYSIC PLAYER Y.
Add a new action, type in the search box GLOBAL and then choose the option VALUE OF GLOBAL VARIABLE. In the variable field select the variable SCREENSHAKE.
In the modification sign, choose SUBTRACT and in the value type TIMERELAPSEDTIME and as a parameter between quotes SCREENSHAKETIMER.
Click OK to close.
Add another action, again choose the option VALUE OF GLOBAL VARIABLE and since we are going to modify the value of SCREENSHAKESIGN, a variable that is not yet created, click on the Button with an arrow pointing up.
This will open the dialog box for the Global variables.
Click add variable and type SCREENSHAKESIGN, and in the value field 1.
Click apply to close the dialog box.
Select now, in the variable field the recently created variable, in the modification sign, MULTIPLY BY, and in the value -1. This will make the SCREENSHAKEDESIGN to be shifting between +1 and -1 in each iteration, which will make also the result where it is used, to be shifting too.
Add a new event, and in the condition type TIMER. Select the option VALUE OF A SCENE TIMER.
In the timer’s name field on the right pane, type the name of the timer that we are using to control the screen shake, SCREENSHAKETIMER. In the TIMER’s value type 1.
Click OK to close.
For the action, in the search box type Timer and then select the PAUSE timer option, and in the TIMER’s NAME type again the SCREENSHAKETIMER.
Click OK to close.
If you have not yet modified it earlier on. Go to the Player HEALTH group and in the action where we are unpausing the Timer, add an R to the end of the timer’s name.
Now, before, trying the game, when we are modifying the values of camera X and Y, the value that we have calculated may be too small to be seen, so let’s multiply both values by 20, to increase the range of shake. Later on, if needed, we could parameterize this value in a variable to allow the different intensity of screen shakes.
Let’s try the game and especially let the bullets come and see if we have that juicy screen shake.
And yes! We have it! Looks and feels cool.
Let’s finish the video. In the next episodes, we will probably deal with the player death, and start to look at the game flow with some game screens from start to end.
We hope that you have liked this video. If it has been the case, consider subscribing, giving a Like, and clicking on the notification button. If you have any questions, problems, or comments, don´t hesitate in putting a comment and we will answer as fast as we could.
See you in the next video GAME DEVELOPERS!
We will upload all the new assets to to the ITCHIO and we are thinking in opening a Github for the project, let us know which you like the most in the comments below.
the Contra Level Map used in the video:
Contra´s Wikipedia https://en.wikipedia.org/wiki/Contra_%28video_game%29
Contra is a complex game but we will try to get as far as possible in cloning.
Free Art Assets:
in case you want to make something close from Contra, you have also this spritesheets
The Enemy Juggernaut
Play the game the current version of the game being developed
Get you controllers ready, download Gdevelop and we will be starting …
GDevelop is an open-source, cross-platform game engine designed for everyone – it’s extensible, fast and easy to learn.
In its concept it is very similar to Scirra Construct game engine ( somewhat less polished) with a growing community developing games, tutorials and supporting the game engine development.
We will post a serie of easy gdevelop tutorials to let you start your way into game development.
Download Gdevelop is free!
#gamedev #indiedev #gametutorial #gamedevelopers #gdevelop
Tweets by game_developers
From Game Developers to Game Developers, sharing knowledge
RolemusicThe Little BrothThe Black DotChiptune, Chip Music
▶ Please Subscribe : https://bit.ly/GameDevelopers ▶