• 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!

Programming Buttons for Certain Attacks

I been trying to implement some "heavy" attacks into a beat em up game I am making and did mange to get them to work(I am trying to make it similar to a smash attack from Smash Bros). However, my basic kick button always plays before the heavy kick attack. What I want to happen is when I press the right buttons, I want it to go straight to the heavy kick.

Player Inputs

GML:
    //Player Input
key_right = keyboard_check(vk_right);
key_left = keyboard_check(vk_left);
key_up = keyboard_check(vk_up);
key_down = keyboard_check(vk_down);
key_jump = gamepad_button_check_pressed(0,gp_face1) //+ keyboard_check_pressed(vk_space);
key_shoot = gamepad_button_check(0,gp_face3) + keyboard_check(vk_control);
key_dodge = gamepad_button_check(0,gp_face4)
key_reflect =  gamepad_button_check_pressed(0,gp_face4)
key_kick =  gamepad_button_check_pressed(0,gp_face3) + keyboard_check(vk_control);
key_heavykick =  gamepad_button_check(0,gp_face3)
key_kickgo = gamepad_button_check_released(0,gp_face3) + keyboard_check(vk_control);
key_kickair =  gamepad_button_check(0,gp_face3) + keyboard_check(vk_control);

GML:
    if  (!dodge && hsp != 0 && abs(move) <= 0.99)
    {
    move = 1
    walkspd = 4
    sprite_index = spr_flarewalk
    image_speed = 1
    flare = flare.walk
    }
    
    else if place_meeting(x, y+1, obj_wall) && (key_jump)
    {
    vsp = -jumpspeed
    ground = false
    sprite_index = spr_flarejump
    flare = flare.jump
    }
    
    else if (key_dodge)
    {
    move = 0
    key_jump = 0
    hsp = 0
    flash = 3
    dodge = true;
    reflect_sprite = false
    sprite_index = spr_flareblock
    flare = flare.dodge
    }
    
    [COLOR=rgb(235, 107, 86)]else if (key_kick)
    {
    move = 0;
    key_jump = 0;
    hsp = 0;
    combo = 0;
    audio_play_sound(sn_Kick_1,7,false);
    sprite_index = spr_flarekick1;
    image_index = 0;
    image_speed = 1;
    flare = flare.kick;   
    }
    
    else if (key_right) && (key_heavykick)
    {
    move = 0;
    key_jump = 0;
    flare = flare.heavykick_anticipation
    }

    else if (key_left) && (key_heavykick)
    {
    move = 0;
    key_jump = 0;
    flare = flare.heavykick_anticipation
    }[/COLOR]
    
    else
    {
    hsp = 0
    sprite_index = spr_flare;
    image_speed = 1;
    flare = flare.idle;
    }
 

Simon Gust

Member
you check button presses as true (for pressing) or false (for not pressing). But you define your buttons as 0, 1 or 2.

true refers to every value greater than 0.5

if gamepad_button_check_pressed(0,gp_face3) is pressed, both key_kick and key_heavykick will be set to 1 (true)
if you also press control, key_heavykick will still be 1 (true), but key_kick will be 2 (still true). Both will then execute their code.

You need to combine button presses with && not +.

Code:
key_shoot = gamepad_button_check(0,gp_face3) && keyboard_check(vk_control);
key_kick =  gamepad_button_check_pressed(0,gp_face3) && keyboard_check(vk_control);
key_kickgo = gamepad_button_check_released(0,gp_face3) && keyboard_check(vk_control);
key_kickair =  gamepad_button_check(0,gp_face3) && keyboard_check(vk_control);
here both the gamepad and control need to be pressed for the key to be 1.
 
you check button presses as true (for pressing) or false (for not pressing). But you define your buttons as 0, 1 or 2.

true refers to every value greater than 0.5

if gamepad_button_check_pressed(0,gp_face3) is pressed, both key_kick and key_heavykick will be set to 1 (true)
if you also press control, key_heavykick will still be 1 (true), but key_kick will be 2 (still true). Both will then execute their code.

You need to combine button presses with && not +.

Code:
key_shoot = gamepad_button_check(0,gp_face3) && keyboard_check(vk_control);
key_kick =  gamepad_button_check_pressed(0,gp_face3) && keyboard_check(vk_control);
key_kickgo = gamepad_button_check_released(0,gp_face3) && keyboard_check(vk_control);
key_kickair =  gamepad_button_check(0,gp_face3) && keyboard_check(vk_control);
here both the gamepad and control need to be pressed for the key to be 1.

Oh ok, but those with the keyboard checks are pressed if I am pressing the buttons on the keyboard. I should have deleted those because they are not apart of it.

As you can see with the else if statements with the heavy kick state, I used the && in the equation, unless I am doing something wrong.
 

Simon Gust

Member
Oh ok, but those with the keyboard checks are pressed if I am pressing the buttons on the keyboard. I should have deleted those because they are not apart of it.

As you can see with the else if statements with the heavy kick state, I used the && in the equation, unless I am doing something wrong.
there you are combining a directional key with another key so that if you press no direction, no heavy kick can be executed. All fine.

Your code is setup to provide priorities to attacks, if you press every key at once, only the jump should be executed, since every other action cannot play at the same time.
Except for kick and heavy kick (and others most likely). They have the same button, that is how the compiler sees it.
I would be surprised if your character didn't just start doing an animation when you hit nothing but vk_control.

Another problem is that right has priority over left. If you hit both right and left with a heavy kick, only right will be executed.

Your code seems very unstable to me. I see variables that don't do much, else-if structures instead of a state machine and non-boolean controls.
This is not something I would like to work with.

I recommend making vk_control it's own button
Code:
key_control = keyboard_check(vk_control);
and then make a tree like structure in the execution part until every possible combination is covered.
An example from my code where I handle movement apart from attacking. Movement consiting of walking, standing and jumping.
GML:
if (place_meeting(x, y+1, obj_ground))
{
    if (move != 0)
    {
        sprite_index = spr_walking;
    }
    else
    {
        sprite_index = spr_standing;
    }
}
else
{
    sprite_index = spr_jumping;
}
I can extend this code with more keys. Say I want sprinting when hitting control.
GML:
if (place_meeting(x, y+1, obj_ground))
{
    if (move != 0)
    {
        if (key_control)
        {
            sprite_index = spr_sprinting;
        }
        else
        {
            sprite_index = spr_walking;
        }
    }
    else
    {
        sprite_index = spr_standing;
    }
}
else
{
    sprite_index = spr_jumping;
}
and I want to shoot my gun too.
GML:
if (key_shoot)
{
    sprite_index = spr_shooting;
}
else
{
    if (place_meeting(x, y+1, obj_ground))
    {
        if (move != 0)
        {
            if (key_control)
            {
                sprite_index = spr_sprinting;
            }
            else
            {
                sprite_index = spr_walking;
            }
        }
        else
        {
            sprite_index = spr_standing;
        }
    }
    else
    {
        sprite_index = spr_jumping;
    }
}
maybe I want both shooting, kicking and heavy kicking as options for attack.
GML:
var attacking = key_shoot || key_kick;

if (attacking)
{
    if (key_shoot) sprite_index = spr_shooting;
    else
    if (key_kick)
    {
        if (key_control)
        {
            sprite_index = spr_kicking_heavy;
        }
        else
        {
            sprite_index = spr_kicking;
        }
    }
}
else
{
    if (place_meeting(x, y+1, obj_ground))
    {
        if (move != 0)
        {
            if (key_control)
            {
                sprite_index = spr_sprinting;
            }
            else
            {
                sprite_index = spr_walking;
            }
        }
        else
        {
            sprite_index = spr_standing;
        }
    }
    else
    {
        sprite_index = spr_jumping;
    }
}
of course just setting a sprite will not give you something fully working, in this example, animations can be interrupted if you let go of a key and press another.
If you don't want that, a state machine will be needed.
GML:
switch (state)
{
    case flare.idle: // where button presses matter
   
        if (attacking)
        {
            if (key_shoot) state = flare.shooting;
            else
            if (key_kick)
            {
                if (key_control)
                {
                    state = flare.heavy_kicking;
                }
                else
                {
                    state = flare.kicking;
                }
            }
        }
        else
        {
            if (place_meeting(x, y+1, obj_ground))
            {
                if (move != 0)
                {
                    if (key_control)
                    {
                        sprite_index = spr_sprinting;
                    }
                    else
                    {
                        sprite_index = spr_walking;
                    }
                }
                else
                {
                    sprite_index = spr_standing;
                }
            }
            else
            {
                sprite_index = spr_jumping;
            }
        }
       
    break;
    case flare.shooting:
   
        sprite_index = spr_shooting;
       
    break;
    case flare.kicking:
   
        sprite_index = spr_kicking;
   
    break;
    case flare.heavy_kicking:
   
        sprite_index = spr_heavy_kicking;
   
    break;
}
you would have to use the animation end event to see if shooting, kicking... states are done animating and go back into the idle state, where actually most of the action happens. Because from there, all controls are freely avaliable.
 
there you are combining a directional key with another key so that if you press no direction, no heavy kick can be executed. All fine.

Your code is setup to provide priorities to attacks, if you press every key at once, only the jump should be executed, since every other action cannot play at the same time.
Except for kick and heavy kick (and others most likely). They have the same button, that is how the compiler sees it.
I would be surprised if your character didn't just start doing an animation when you hit nothing but vk_control.

Another problem is that right has priority over left. If you hit both right and left with a heavy kick, only right will be executed.

Your code seems very unstable to me. I see variables that don't do much, else-if structures instead of a state machine and non-boolean controls.
This is not something I would like to work with.

I recommend making vk_control it's own button
Code:
key_control = keyboard_check(vk_control);
and then make a tree like structure in the execution part until every possible combination is covered.
An example from my code where I handle movement apart from attacking. Movement consiting of walking, standing and jumping.
GML:
if (place_meeting(x, y+1, obj_ground))
{
    if (move != 0)
    {
        sprite_index = spr_walking;
    }
    else
    {
        sprite_index = spr_standing;
    }
}
else
{
    sprite_index = spr_jumping;
}
I can extend this code with more keys. Say I want sprinting when hitting control.
GML:
if (place_meeting(x, y+1, obj_ground))
{
    if (move != 0)
    {
        if (key_control)
        {
            sprite_index = spr_sprinting;
        }
        else
        {
            sprite_index = spr_walking;
        }
    }
    else
    {
        sprite_index = spr_standing;
    }
}
else
{
    sprite_index = spr_jumping;
}
and I want to shoot my gun too.
GML:
if (key_shoot)
{
    sprite_index = spr_shooting;
}
else
{
    if (place_meeting(x, y+1, obj_ground))
    {
        if (move != 0)
        {
            if (key_control)
            {
                sprite_index = spr_sprinting;
            }
            else
            {
                sprite_index = spr_walking;
            }
        }
        else
        {
            sprite_index = spr_standing;
        }
    }
    else
    {
        sprite_index = spr_jumping;
    }
}
maybe I want both shooting, kicking and heavy kicking as options for attack.
GML:
var attacking = key_shoot || key_kick;

if (attacking)
{
    if (key_shoot) sprite_index = spr_shooting;
    else
    if (key_kick)
    {
        if (key_control)
        {
            sprite_index = spr_kicking_heavy;
        }
        else
        {
            sprite_index = spr_kicking;
        }
    }
}
else
{
    if (place_meeting(x, y+1, obj_ground))
    {
        if (move != 0)
        {
            if (key_control)
            {
                sprite_index = spr_sprinting;
            }
            else
            {
                sprite_index = spr_walking;
            }
        }
        else
        {
            sprite_index = spr_standing;
        }
    }
    else
    {
        sprite_index = spr_jumping;
    }
}
of course just setting a sprite will not give you something fully working, in this example, animations can be interrupted if you let go of a key and press another.
If you don't want that, a state machine will be needed.
GML:
switch (state)
{
    case flare.idle: // where button presses matter
 
        if (attacking)
        {
            if (key_shoot) state = flare.shooting;
            else
            if (key_kick)
            {
                if (key_control)
                {
                    state = flare.heavy_kicking;
                }
                else
                {
                    state = flare.kicking;
                }
            }
        }
        else
        {
            if (place_meeting(x, y+1, obj_ground))
            {
                if (move != 0)
                {
                    if (key_control)
                    {
                        sprite_index = spr_sprinting;
                    }
                    else
                    {
                        sprite_index = spr_walking;
                    }
                }
                else
                {
                    sprite_index = spr_standing;
                }
            }
            else
            {
                sprite_index = spr_jumping;
            }
        }
     
    break;
    case flare.shooting:
 
        sprite_index = spr_shooting;
     
    break;
    case flare.kicking:
 
        sprite_index = spr_kicking;
 
    break;
    case flare.heavy_kicking:
 
        sprite_index = spr_heavy_kicking;
 
    break;
}
you would have to use the animation end event to see if shooting, kicking... states are done animating and go back into the idle state, where actually most of the action happens. Because from there, all controls are freely avaliable.

I was using a state machine, I just didn't show everything. I was using the Switch statement in the step event for the state machine. Also, what does the "control" do, I'm not understanding that. And would I use control with a controller since that is what I'm using, or would it be better using the keyboard.

And yes, this is very sloppy and I do need to make some serious changes to the code. I noticed that when playing my game is see alot of issues which shouldn't be there.
 
Last edited:

Simon Gust

Member
I was using a state machine, I just didn't show everything. I was using the Switch statement in the step event for the state machine. Also, what does the "control" do, I'm not understanding that. And would I use control with a controller since that is what I'm using, or would it be better using the keyboard.

And yes, this is very sloppy and I do need to make some serious changes to the code. I noticed that when playing my game is see alot of issues which shouldn't be there.
"control" is the variable I set for when I hit the Ctrl key on my keyboard. If you use a controller, it could be a button best hit with the index finger on the left or right.

to my knowledge, the state machine you have is one you don't seem to use.
You do set
flare = flare.jump
flare = flare.dodge
but that is not legal code to my knowledge. "flare" is the name of your enum and cannot be the name of your state variable.
Then, everytime a button is pressed or an action is taken, there should be a state check, not a long else if chain.
Try to keep the code in one place and in one big switch statement. And finally, there isn't a rule, but I think not every animation needs their own state.
I usually assign a state to an animation that has timed actions (damage object created at frame 3 for example), say attacking, dying, spawning, being stunned etc.
Here's some example from my actual game
GML:
// animation
sprite_index = spr_shirhix_attack2;
image_speed = 0.16 * atk_spd;

// launch
if (image_index < 3) {
    if (on_ground) {
        hspd = move * move_spd * 0.20;
    }
}
else
if (image_index >= 3 && image_index < 3 + image_speed)
{  
    // recoil
    hspd += image_xscale * move_spd * 1.50;
   
    // position
    var xoff = x + 5 * image_xscale;
    var yoff = y - 10;
   
    // attack
    var inst = instance_create(xoff, yoff, obj_proj_shirhix2);
        inst.hspd = image_xscale * random_range(25, 30);
        inst.vspd = random_range(-0.2, -0.5);
        inst.damage = atk * attack_damage[1] * random_range(0.80, 1.20);
        inst.dot_damage = atk * 0.60;
        inst.dot_ticks = irandom_range(4, 7);
        inst.player = id;
       
    // particle
    particle_create(attack_fx[1], xoff, yoff);
    part_type_scale(attack_fx[1], image_xscale, 1);
}
else
if (image_index >= image_number - image_speed)
{
    // get medium
    var dec = acc_spd / 2.00;
   
    // deceleration
    if (hspd > 0) hspd -= min(dec,  hspd);
    else
    if (hspd < 0) hspd += min(dec, -hspd);
  
    attack_chosen = noone;
    state = STATE.CHILL;       
    image_index = 0;
}
the attack goes as following, the player tries to spit poison, at frame 3, the actual projectile is being created. At the end of the animation, the state is set back to normal state.
The code is in a user event and can only get called from normal state.
 
This
"control" is the variable I set for when I hit the Ctrl key on my keyboard. If you use a controller, it could be a button best hit with the index finger on the left or right.

to my knowledge, the state machine you have is one you don't seem to use.
You do set
flare = flare.jump
flare = flare.dodge
but that is not legal code to my knowledge. "flare" is the name of your enum and cannot be the name of your state variable.
Then, everytime a button is pressed or an action is taken, there should be a state check, not a long else if chain.
Try to keep the code in one place and in one big switch statement. And finally, there isn't a rule, but I think not every animation needs their own state.
I usually assign a state to an animation that has timed actions (damage object created at frame 3 for example), say attacking, dying, spawning, being stunned etc.
Here's some example from my actual game
GML:
// animation
sprite_index = spr_shirhix_attack2;
image_speed = 0.16 * atk_spd;

// launch
if (image_index < 3) {
    if (on_ground) {
        hspd = move * move_spd * 0.20;
    }
}
else
if (image_index >= 3 && image_index < 3 + image_speed)
{ 
    // recoil
    hspd += image_xscale * move_spd * 1.50;
  
    // position
    var xoff = x + 5 * image_xscale;
    var yoff = y - 10;
  
    // attack
    var inst = instance_create(xoff, yoff, obj_proj_shirhix2);
        inst.hspd = image_xscale * random_range(25, 30);
        inst.vspd = random_range(-0.2, -0.5);
        inst.damage = atk * attack_damage[1] * random_range(0.80, 1.20);
        inst.dot_damage = atk * 0.60;
        inst.dot_ticks = irandom_range(4, 7);
        inst.player = id;
      
    // particle
    particle_create(attack_fx[1], xoff, yoff);
    part_type_scale(attack_fx[1], image_xscale, 1);
}
else
if (image_index >= image_number - image_speed)
{
    // get medium
    var dec = acc_spd / 2.00;
  
    // deceleration
    if (hspd > 0) hspd -= min(dec,  hspd);
    else
    if (hspd < 0) hspd += min(dec, -hspd);
 
    attack_chosen = noone;
    state = STATE.CHILL;      
    image_index = 0;
}
the attack goes as following, the player tries to spit poison, at frame 3, the actual projectile is being created. At the end of the animation, the state is set back to normal state.
The code is in a user event and can only get called from normal state.
unknown.png
This is what I doin the step event
 
Top