GML How do I animate a character holding a gun object at different angles and in different states?

Hey everyone,

I am trying to get my character in my game to hold a gun object, allow for free aim control with the mouse, and have the animation look somewhat realistic. I was thinking that the gun object could take the form of the arm of the character holding the gun, which would allow for free aim with the mouse. However, I'm unsure as to how this would effect the different states of animation. The problems are: The size of the gun with the arm ( or the gun object) is too small when rendered together, I'm unsure how to handle this with all other states I have, and whether this is a good method in the long term if I want more than one gun in the game. Here is some reference game footage:


I am still having a problem getting the bullets to aim in the right direction and maneuvering the gun with the mouse. Here is the relevant code:


GML:
o_gun
//Create

recoil= 0;

// Begin Step

x =o_player.x;
y = o_player.y-58;
image_index = 3
image_speed = 0;


image_angle = point_direction(x,y,mouse_x,mouse_y);

firingdelay =  firingdelay - 1;
recoil = max(0,recoil - 1);
if (mouse_check_button(mb_left)) and (firingdelay < 0)
{
    recoil = 4;
    scr_screen_shake(0.5,2);
    firingdelay= 5;
    audio_play_sound(snd_pistol_shot,5,false);
    with (instance_create_layer (x,y,"Bullets",o_bullet))
    {
        spd = 25;
        direction = other.image_angle +random_range(-3,3);
        image_angle = direction;
    }

}

x = x - lengthdir_x(recoil, image_angle);
y = y - lengthdir_y(recoil, image_angle);

if (image_angle > 200) and (image_angle < 300)
{
image_yscale = -1;
}

else
{
image_yscale = 1;
}


GML:
o_bullet
//Step
x += lengthdir_x(spd,direction);
y += lengthdir_y(spd,direction);
if(place_meeting(x,y,p_shootable))
{


    with (instance_place(x,y,p_shootable))
    {
        hp--;
        flash = 3;
        hitfrom = other.direction;
    }
    instance_destroy();
}

//Animation End

image_speed = 0;
image_index = 1;

GML:
//This Script is in the Player's Create Event
function player_armed_state(){
        //get input
    get_input();

    //calculate movement
    calc_movement();

    //check state
    if hsp == 0 state = states.IDLE;
if instance_create_layer(o_player.x,o_player.y,"Gun",o_gun) and state = states.WALK{
    sprite_index = s_player_armless
    image_index= 1;
    image_speed = 0;


}
    //apply movement
    collision();

    //check players hp
    check_player_hp();

    //apply animations
    anim();

}


//Player's Create Event
//states
enum states {
IDLE,
WALK,
JUMP,
ATTACK,
BLOCK,
CROUCH,
CROUCH_BLOCK,
HURTING,
KNOCKBACK,
DIE,
ARMED,
GAME_END
}

state = states.IDLE;

//create states array
states_array[states.IDLE] = player_idle_state;
states_array[states.WALK] = player_walk_state;
states_array[states.JUMP] = player_jump_state;
states_array[states.ATTACK] = player_attack_state;
states_array[states.BLOCK] = player_block_state;
states_array[states.CROUCH] = player_crouch_state;
states_array[states.CROUCH_BLOCK] = player_crouch_block_state;
states_array[states.HURTING] = player_hurting_state;
states_array[states.KNOCKBACK] = player_knockback_state;
states_array[states.DIE] = player_die_state;
states_array[states.ARMED] = player_armed_state;
states_array[states.GAME_END] = player_game_end_state;


//create sprites array
sprites_array[states.IDLE] = s_player_idle;
sprites_array[states.WALK] = s_player_walk;
sprites_array[states.JUMP] = s_player_jump;
sprites_array[states.ATTACK] = s_player_attack;
sprites_array[states.BLOCK] = s_player_block;
sprites_array[states.CROUCH] = s_player_crouch;
sprites_array[states.CROUCH_BLOCK] = s_player_crouch_block;
sprites_array[states.HURTING] = s_player_hurting;
sprites_array[states.KNOCKBACK] = s_player_knockback;
sprites_array[states.DIE] = s_player_die;
sprites_array[states.ARMED] = s_player_armless;
sprites_array[states.GAME_END] = s_player_die;


//create mask array
mask_array[states.IDLE] = s_player_idle;
mask_array[states.WALK] = s_player_idle;
mask_array[states.JUMP] = s_player_idle;
mask_array[states.ATTACK] = s_player_idle;
mask_array[states.BLOCK] = s_player_idle;
mask_array[states.CROUCH] = s_player_crouch;
mask_array[states.CROUCH_BLOCK] = s_player_crouch;
mask_array[states.HURTING] = s_player_idle;
mask_array[states.KNOCKBACK] = s_player_idle;
mask_array[states.DIE] = s_player_die;
mask_array[states.GAME_END] = s_player_die;
mask_array[states.ARMED
 
Last edited:

baconlovar

Member
You are on the right track, I would just keep the arm behind the character straight and adjust the character based on the arm rotation, in addition I would make a pivoting head that follows the arm too
 
You are on the right track, I would just keep the arm behind the character straight and adjust the character based on the arm rotation, in addition I would make a pivoting head that follows the arm too
Thanks for the help, I did straighten out the arm, but I'm sure how to pivot the head without hiding the head and body separation. I am also not sure how to change the sprite. I tried introducing a state change that appears like this:

GML:
function player_armed_state(){
    //get Input
    get_input();


    //calculate movement
    calc_movement();

    //check state
    if hsp != 0 and state != states.WALK and instance_exists(o_pistol){
        image_speed = 1;
        sprite_index = s_player_armless;
    
    
    
    }


    //apply movement
    collision();

    //check players hp
    check_player_hp();

    //apply animations
    anim();

}
 

baconlovar

Member
What I've done is have a headless and one-armless sprite so their head would be in the draw event as well as the aiming arm. As for the sprite changes, I would do something based on the arm rotation

ex


GML:
if(arm_angle > 270 || arm_angle < 90){
    player.image_xscale = 1;
}
if(arm_angle >= 90 && arm_angle <= 270){
    player.image_xscale = -1;
}

head_angle = arm_angle; //going to need to limit rotation so head doesnt spin 360
 
Top