Need help implementing state machines

Hey, so I have been working on a top down RPG and I am trying to implement a state system to switch the players states i.e ( idle, movement, sprint,attack,etc). I'm fairly new to GMS(I'm using GMS 1.4.9999) and have some minor coding experience.
The problem I am stuck with is that when the player is in the idle state it does not switch to the attack state.
This is my idle state code
Code:
scr_get_input();
//if moving
if (up_key || down_key || right_key || left_key)
{
    state = scr_move_state;   
}
//if attacking
if(attack_key)
{
    state = scr_attack_state;
}
//if sprite is facing down
if(sprite_index = spr_player)
{
    image_speed = 0.1;
    sprite_index = spr_male_idle
}
//if sprite is facing up
if(sprite_index = spr_male_up)
{
    sprite_index = spr_male_idleu
    image_speed = 0.1;
}
//if sprite is facing right
if(sprite_index = spr_male_right)
{
    image_speed = 0.1;
    sprite_index = spr_male_idler 
}
//if sprite is facing left
if(sprite_index = spr_male_left)
{
    image_speed = 0.1;
    sprite_index = spr_male_idlel; 
}
This is the movement state
Code:
///scr_move_state
scr_get_input();
spd=1;
//if attacking
if(attack_key)
{
    state = scr_attack_state;
}

// go to idle state
if (!down_key && !up_key && !left_key && !right_key) {
state = scr_idle_state;
}
//if sprinting
if(sprint_key)
{
    state =scr_sprint_state;
}
//Move Down
if (down_key) {
    phy_position_y += spd;
    sprite_index = spr_player;
    image_speed = .3;
}
//Move Up
if (up_key) {
    phy_position_y -= spd;
    sprite_index = spr_male_up;
    image_speed = .3;
}
//Move Left
if (left_key) {
    phy_position_x -= spd;
    sprite_index = spr_male_left;
    image_speed = .2;
}
//Move Right
if (right_key) {
    phy_position_x += spd;
    sprite_index = spr_male_right;
    image_speed = .2;
}
Also when leaving the attack state to idle the sprite remains the attack sprite until I move the player.

Finally here is the attack state code
Code:
scr_get_input();
spd =0.05
//if not attacking
if(!attack_key)
{
    state = scr_idle_state;
}
//if sprite is facing down
if(sprite_index = spr_player)
{
    sprite_index = spr_male_attackd;
    image_speed = .2;
}
//if sprite is facing up
if(sprite_index = spr_male_up)
{
    sprite_index = spr_player_attacku;
    image_speed = .2;
}
//if sprite is facing right
if(sprite_index = spr_male_right)
{
    sprite_index = spr_male_attackr;
    image_speed = .2;
}
//if sprite is facing left
if(sprite_index = spr_male_left)
{
    sprite_index = spr_male_attackl;
    image_speed = .2;
}

//Move Down
if (down_key)
{
    phy_position_y += spd;
    sprite_index = spr_male_attackd;
    image_speed = .2;
}
//Move Up
if (up_key)
{
    phy_position_y -= spd;
    sprite_index = spr_player_attacku;
    image_speed = .2;
}
//Move Left
if (left_key)
{
    phy_position_x -= spd;
    sprite_index = spr_male_attackl;
    image_speed = .2;
}
//Move Right
if (right_key)
{
    phy_position_x += spd;
    sprite_index = spr_male_attackr;
    image_speed = .2;
}
All that's in my create event for now with regards to the states is just setting the variable state to the idle state and my step event looks like this;
Code:
script_execute(state);
Thanks for any help in advance.
 

Bentley

Member
Without getting too into your code, it looks like pressing attack takes you to the attack state.
BUT, not pressing any key takes you back to the idle state.
So you're in the attack state for a frame.
I would use an animation end event (under other) and check my state or sprite. Ex:
Code:
// Animation end event
if (state == en_states.attack)
{
    state = en_states.idle;
}
The attack state, at least for me, would be where a sprite plays out and a hitbox is created. At the end of the animation, the player returns to idle or to previous state.
 

TheouAegis

Member
The sprite doesn't change back to the idle sprite because you handle the sprite changes in the idle state itself. Sprite changes should happen the moment you change the state, not after it. What's worse, in your idle state you only tell it to change to the idle sprite if you're already in the moving sprite; it says nothing about changing from the attacking sprite to the idle sprite.

Also, your conditional tree is pretty convoluted just for changing sprites. You have a series of "if sprite_index==" checks just for the sake of changing the sprite. You should streamline this. Most people create a variable, like facing, which has a value from 0 to 3, and then use that to determine what sprite to use. My personal method is to put all the sprites in one or more arrays, like so:
Code:
idle_sprite[0] = spr_idle_right;
idle_sprite[1] = spr_idle_up;
idle_sprite[2] = spr_idle_left;
idle_sprite[3] = spr_idle_down;
Then to change the sprite, you just pass your facing variable as the array index, like so:
Code:
sprite_index = idle_sprite[facing];
So...
  1. Make your attack state end after an elapsed amount of time or the sprite has finished animating, not based on any key presses or lack thereof.
  2. Change sprites at the same time you change state.
  3. Streamline your sprite changing conditional, preferable to an array.
 
Top