• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GML [SOLVED] problems with moving and jumping attacks

pretty new to programming but i'm gradually figuring it out. found out how to get my attack animation to work through states but i cant quite figure out how to attack and move at the same time and when i jump the object freezes in air

create
Code:
hsp = 0;
vsp = 0;
grv = 0.3;
walksp = 4;
hascontrol = true;
canjump = 0;

hitfrom = 0;

enum st
{
    normal,
    attack
}
state = st.normal
state
Code:
switch(state)
{
    case st.normal:
    {

        //Player imput

        if (hascontrol)
        {
            key_left = keyboard_check(vk_left) || keyboard_check(ord("A"));
            key_right = keyboard_check(vk_right) || keyboard_check(ord("D"));
            key_jump = keyboard_check_pressed(vk_space);
            key_enter = keyboard_check_pressed(vk_enter);
        }
        else
        {
            key_right = 0;
            key_left = 0;
            key_jump = 0;
            key_enter = 0;
        }

        //Calculate movement
        var move = key_right - key_left;

        hsp = move * walksp;

        vsp = vsp + grv;

        //Jumping
        canjump -= 1;
        if (canjump > 0) && (key_jump)
        {
            vsp = -7;
            canjump = 0;
        }
       
        //Attacking
        if (key_enter = 1)
        {
            state = st.attack;
            image_index = 0;
            sprite_index = sPYattack;
            break;
        }


        //Horizontal collision
        if (place_meeting(x+hsp,y,obj_wall))
        {
            while (!place_meeting(x+sign(hsp),y,obj_wall))
            {
                x = x + sign(hsp);   
            }
            hsp = 0;   
        }

        if (place_meeting(x+hsp,y,oDoor2))
        {
            while (!place_meeting(x+sign(hsp),y,oDoor2))
            {
                x = x + sign(hsp);   
            }
            hsp = 0;   
        }
        x = x + hsp;

        //Vertical collision
        if (place_meeting(x,y+vsp,obj_wall))
        {
            while (!place_meeting(x,y+sign(vsp),obj_wall))
            {
                y = y + sign(vsp);   
            }
            vsp = 0;   
        }
        y = y + vsp;


        //Animation
        if (!place_meeting(x,y+1,obj_wall)) 
        {
            sprite_index = sPYjump;
            image_speed = 0;
            if (sign(vsp) > 0) image_index = 1; else image_index = 0;
        }
        else
        {
            if (sprite_index == sPYjump) 
            {
                audio_sound_pitch(snLand1,random_range(1,1.3));
                audio_play_sound(snLand1,4,false);
            }
            canjump = 10;
            image_speed = 1;
            if (hsp == 0)
            {
                sprite_index = sPYand;
            }
            else
            {
                sprite_index = sPYmove;
            }
        }
       
        if (hsp != 0) image_xscale = sign(hsp);
        break;
    }

    case st.attack:
    {
        {
            //Animate
            sprite_index = sPYattack;
                   
            if (image_index >= 1) && (image_index <= 3)
                {
                    with (instance_create_layer(x,y,layer,oHitbox))
                    {
                        image_xscale = other.image_xscale;
                        with (instance_place(x,y,parEnemy))
                        {
                            if (hit == 0)
                            {
                                hit = 1;
                                vsp = -3;
                                hsp = sign(x - other.x) * 4;
                                image_xscale = sign(hsp);
                            }
                        }
                    }
                }
        }
    }
}
animation end
Code:
if (sprite_index == sPYattack) state = st.normal;
 
any tutorial you suggest? been watching a lot of Shaun Spalding if its not obvious from the code. i'm just staring at this code wondering how to chop it up and put into different states
 

hogwater

Member

That's a good one. Generally the idea is to only put code into a state that is needed. So for example in a walking state, you may not even need gravity or vertical collision.

Anything that many states will need can go in a script, and anything all states need can go outside the state machine.
 
omg, i'm still confused after watching that. like its good information for later like when i'm going to make enemies but just how do i break this code up. its like i'm learning french and i really want to say "where is the bathroom?" but i'm saying something really offensive instead.
i'm going to hold off working on this until morning. sooo sleepy.
 
ok...soooooo now when i hit a move key my player flies off into the sky. i mean its pretty funny but i have no idea why.

step
Code:
//Player imput
if (hascontrol)
        {
            key_left = keyboard_check(vk_left) || keyboard_check(ord("A"));
            key_right = keyboard_check(vk_right) || keyboard_check(ord("D"));
            key_jump = keyboard_check_pressed(vk_space);
            key_enter = keyboard_check_pressed(vk_enter);
        }
        else
        {
            key_right = 0;
            key_left = 0;
            key_jump = 0;
            key_enter = 0;
        }

//Calculate movement
        var move = key_right - key_left;
        hsp = move * walksp;
        vsp = vsp + grv;
       
//Horizontal collision
        if (place_meeting(x+hsp,y,obj_wall))
        {
            while (!place_meeting(x+sign(hsp),y,obj_wall))
            {
                x = x + sign(hsp);   
            }
            hsp = 0;   
        }

        if (place_meeting(x+hsp,y,oDoor2))
        {
            while (!place_meeting(x+sign(hsp),y,oDoor2))
            {
                x = x + sign(hsp);   
            }
            hsp = 0;   
        }
        x = x + hsp;

        //Vertical collision
        if (place_meeting(x,y+vsp,obj_wall))
        {
            while (!place_meeting(x,y+sign(vsp),obj_wall))
            {
                y = y + sign(vsp);   
            }
            vsp = 0;   
        }
        y = y + vsp;       
       
switch(state)
{
    case st.normal:
    {
        if (hsp == 0)
        {
            sprite_index = sPYand;
        }
       
        //Jumping
        canjump -= 1;
        if (canjump > 0) && (key_jump)
        {
            state = st.jump
            break;
        }
       
        //Attacking
        if (key_enter = 1)
        {
            state = st.attack;
            image_index = 0;
            sprite_index = sPYattack;
            break;
        }
       
        //Animation
       
        image_speed = 1;
        if (hsp > 0) or (hsp < 0)
        {
            state = st.move;
            sprite_index = sPYmove;
            break;
        }
       
        break;
    }
    case st.move:
    {
       
        sprite_index = sPYmove;
        if (hsp != 0) image_xscale = sign(hsp);
       
       
    }
   
    case st.jump:
    {
        vsp = -7;
        canjump = 0;
        if (!place_meeting(x,y+1,obj_wall)) 
        {
            sprite_index = sPYjump;
            image_speed = 0;
            if (sign(vsp) > 0) image_index = 1; else image_index = 0;
        }
        else
        {
            if (sprite_index == sPYjump) 
            {
                audio_sound_pitch(snLand1,random_range(1,1.3));
                audio_play_sound(snLand1,4,false);
            }
            canjump = 10;       
        }
        if (hsp != 0) image_xscale = sign(hsp);
       
       
    }
   
    case st.attack:
    {
        {
            //Animate
            sprite_index = sPYattack;
                   
            if (image_index >= 1) && (image_index <= 3)
                {
                    with (instance_create_layer(x,y,layer,oHitbox))
                    {
                        image_xscale = other.image_xscale;
                        with (instance_place(x,y,parEnemy))
                        {
                            if (hit == 0)
                            {
                                hit = 1;
                                vsp = -3;
                                hsp = sign(x - other.x) * 4;
                                image_xscale = sign(hsp);
                            }
                        }
                    }
                }
        }
    }
}
create
Code:
hsp = 0;
vsp = 0;
grv = 0.3;
walksp = 4;
hascontrol = true;
canjump = 0;

hitfrom = 0;

enum st
{
    normal,
    move,
    jump,
    attack
}
state = st.normal
 
Ok, so now i organized inputs and collisions into scripts after watching Shaun Spalding's state machine video and now my player flies off much faster when i press a direction. jump key doesn't work and the only action that seems to work properly is attacking.

Code:
switch(state)
{
    case st.normal:
    {
        scrPinputs()
       
        //Calculate movement
        var move = key_right - key_left;
        hsp = move * walksp;
        vsp = vsp + grv;
       
        if (hsp == 0)
        {
            sprite_index = sPYand;
        }
       
        //Jumping
        canjump -= 1;
        if (canjump > 0) && (key_jump)
        {
            state = st.jump
            break;
        }
       
        //Attacking
        if (key_enter = 1)
        {
            state = st.attack;
            image_index = 0;
            sprite_index = sPYattack;
            break;
        }
       
        //Animation
       
        image_speed = 1;
        if (hsp > 0) or (hsp < 0)
        {
            state = st.move;
            sprite_index = sPYmove;
            break;
        }
        scrCollision()
        break;
    }
    case st.move:
    {
        scrPinputs()
        sprite_index = sPYmove;
        if (hsp != 0) image_xscale = sign(hsp);
        scrCollision()
       
    }
   
    case st.jump:
    {
        scrPinputs()
        vsp = -7;
        canjump = 0;
        if (!place_meeting(x,y+1,obj_wall)) 
        {
            sprite_index = sPYjump;
            image_speed = 0;
            if (sign(vsp) > 0) image_index = 1; else image_index = 0;
        }
        else
        {
            if (sprite_index == sPYjump) 
            {
                audio_sound_pitch(snLand1,random_range(1,1.3));
                audio_play_sound(snLand1,4,false);
            }
            canjump = 10;       
        }
        if (hsp != 0) image_xscale = sign(hsp);
       
        scrCollision()
    }
   
    case st.attack:
    {
        scrPinputs()
        {
            //Animate
            sprite_index = sPYattack;
                   
            if (image_index >= 1) && (image_index <= 3)
                {
                    with (instance_create_layer(x,y,layer,oHitbox))
                    {
                        image_xscale = other.image_xscale;
                        with (instance_place(x,y,parEnemy))
                        {
                            if (hit == 0)
                            {
                                hit = 1;
                                vsp = -3;
                                hsp = sign(x - other.x) * 4;
                                image_xscale = sign(hsp);
                            }
                        }
                    }
                }
        }
        scrCollision()
    }
}
 
ok, making some progress. took out jumping for now (as it was overwhelming me) and simplified my code. now the problem is the move animation isn't running as its just playing the first frame before canceling which i think means its only registering the key press and playing just that frame.
Code:
switch(state)
{
    case st.normal:
    {
        scrPinputs()
        vsp = vsp + grv;
        hsp = 0
        sprite_index = sPYand;
       
        if (key_left) || (key_right)
        {
            state = st.move;
                       
        }
       
        if (key_enter)
        {
            state = st.attack;
        }   
        scrCollision()
        break;
    }
    case st.move:
    {
        scrPinputs()
       
        //Calculate movement
        var move = key_right - key_left;
        hsp = move * walksp;
        vsp = vsp + grv;
        if (hsp != 0) image_xscale = sign(hsp);
        image_speed = 1;
        sprite_index = sPYmove;
       
       
        if (!key_left) || (!key_right)
        {
            state = st.normal;
        }
       
        if (key_enter)
        {
            state = st.attack;
        }   
       
        scrCollision()
       
    }

    case st.attack:
    {
        scrPinputs()
        vsp = vsp + grv;
        {
            //Animate
            sprite_index = sPYattack;
                   
            if (image_index >= 1) && (image_index <= 3)
                {
                    instance_create_layer(x,y,layer,oHitbox)
                   
                }
        }
        scrCollision()
    }
}
 

hogwater

Member
The thing that helped me when transitioning my player to a state machine was simply starting fresh. Save what you have (so you can revert if you want to), and then delete your entire step event and start over.

Start with the idle state, and give it what it needs to function piece by piece. Then give it a transition to another state (probably walking), and give that what it needs to function. Slowly build the character and create branches to new states as needed.

Build it up slowly bit by bit. Don't be afraid to start over and try a new approach!
 
thank you hogwater. I've already started doing that with making duplicate copies just so i can back track if need be. I've mostly figured out moving (with a little help). The only problem now is if i attack while moving the animation sometimes doesn't play completely for attack. But for right now i'm going back to jumping. the current problem is there is a delay before it will allow my player to jump and if i try to attack while in air it breaks somehow and i cant move after landing. also i've found that if i take out all instances of "canjump" then my player will have an air jump when the jump button is pressed.
Code:
switch(state)
{
    case st.normal:
    {
        scrPinputs()
        vsp = vsp + grv;
        hsp = 0
               
        if (key_left) || (key_right) state = st.move;           
        if (key_enter) state = st.attack;
        if (key_jump) state = st.jump;
   
        sprite_index = sPYand;
        scrCollision()
        break;
    }
    case st.move:
    {
        scrPinputs()       
        scrCalcMove()
        image_speed = 1;
        sprite_index = sPYmove;
       
        if (hsp = 0) state = st.normal;
        if (key_enter) state = st.attack;   
       
        scrCollision()
        break;
    }
   
    case st.jump:
    {
        scrPinputs()
        scrCalcMove()
        canjump -= 1;
        if (canjump > 0) && (key_jump)
        {
            vsp = -7;
            canjump = 0;
        }
        if (!place_meeting(x,y+1,obj_wall)) 
        {
            sprite_index = sPYjump;
            image_speed = 0;
            if (sign(vsp) > 0) image_index = 1; else image_index = 0;
        }
        else
        {
            if (sprite_index == sPYjump) 
            {
                state = st.normal;
                audio_sound_pitch(snLand1,random_range(1,1.3));
                audio_play_sound(snLand1,4,false);
            }
            canjump = 10;       
        }
        if (hsp != 0) image_xscale = sign(hsp);
       
       
        scrCollision()
        break;
    }

    case st.attack:
    {
        scrPinputs()
        scrCalcMove()
        {
            //Animate
            sprite_index = sPYattack;
                   
            if (image_index >= 1) && (image_index <= 3)
                {
                    instance_create_layer(x,y,layer,oHitbox)
                   
                }
        }
        scrCollision()
        break;
    }
}
 
hahahahahahahahahahahaha!! finally got this nut cracked! its not 100% perfect but 80-90% is fine by me.
So what i ended up doing was creating 5 states
Code:
enum st
{
    normal,
    move,
    jump,
    attack,
    jumpattack
}
state = st.normal
then i put my jump height variable right after my input is pressed and not in the jump state.
Code:
switch(state)
{
    case st.normal:
    {
        scrPinputs()
        vsp = vsp + grv;
        hsp = 0
               
        if (key_left) || (key_right) state = st.move;           
        if (key_enter) state = st.attack;
        if (key_jump) 
        {
            vsp = -7;
            state = st.jump;
        }
        sprite_index = sPYand;
        scrCollision()
        break;
    }
i then had problems with my attack animations not working and my inputs would stop if i tried to attack so first i had to put a change state at the end of my jump attack state. this resulted in when my player landed it'd go back to normal state so i could move normally again.
Code:
    case st.jumpattack:
    {
        scrPinputs()
        scrCalcMove()           
                           
        if (image_index >= 1) && (image_index <= 3)
        {
            with (instance_create_layer(x,y,layer,oHitbox))
            {
                image_xscale = other.image_xscale;
                with (instance_place(x,y,parEnemy))
                {
                    if (hp == 0)
                    {
                        hp--;
                        flash = 3;
                        hsp = sign(x - other.x) * 4;                       
                    }
                }
            }
        }
        if (place_meeting(x,y+1,obj_wall)) state = st.normal;
        scrCollision()
        break;
    }
}
finally i had to realize that my animation wasn't working right so i looked over the code and found i stopped my image speed so i did two things: change my sprite index to jump attack after the attack key was pressed and turned image speed back to normal.
Code:
    case st.jump:
    {
        scrPinputs()
        scrCalcMove()
        if (!place_meeting(x,y+1,obj_wall)) 
        {
            sprite_index = sPYjump;
            image_speed = 0;
            if (sign(vsp) > 0) image_index = 1; else image_index = 0;
        }
        else
        {
            if (sprite_index == sPYjump) 
            {
                state = st.normal;
                audio_sound_pitch(snLand1,random_range(1,1.3));
                audio_play_sound(snLand1,4,false);
            }   
        }   
        if (key_enter) 
        {
            sprite_index = sPYjumpa;
            image_speed = 1;
            state = st.jumpattack;
        }
        scrCollision()
        break;
    }
i also added an end animation
if (sprite_index == sPYattack) state = st.normal;
if (sprite_index == sPYjumpa) state = st.jump;

and like that, wala! my code finally works!
Thank you for your help hogwater and tomsaram!
 
Top