GMS 2 [SOLVED] How to animate a weapon when attacking?

Sarena

Member
I managed to get my sword weapon to work correctly in regards to function, but whenever I attack, it only shows the first frame of my animation instead of playing through all 8 frames.

Here is the code I have in regards to the sword in my objPlayer's Step Event:
Code:
// Sword Attack

// If Expression
if(keyboard_check_pressed(vk_shift))
{
    // Set Sprite
    sprite_index = sprPlayerSword;
    image_index += 0;

    // Declare Temp
    var xdifference = x - xprevious;
    var ydifference = y - yprevious;

    // If Expression
    if(!(xdifference = 0 and ydifference = 0))
    {
        // Assign Variable
        swordx = xdifference;
        swordy = ydifference;
    }

    // Create Instance
    instance_create_layer(x + sign(xdifference) * 32, y + sign(ydifference) * 32, "Instances", objPHitBox);
}
Anyone know how I could get it to play through all 8 frames of my animation each time it attacks?
 

JeffJ

Member
Think about this logically;

Your code happens once shift is pressed. That means once. How do you advance your animation? By adding 1 to your image_index. But this only happens once, because it only happens once shift is pressed.

Actually, now that I took a second glance, you aren't even adding anything to image_index - you're literally saying "increase by 0".

A better solution would be to replace "image_index+=0" with "image_speed=0.3" (replace 0.3 with whatever works), and then add an "animation end" event, where you do something like:

Code:
if sprite_index == sprPlayerSword
{
 sprite_index = sprPlayerIdle //or whatever you want to go back to once attack animation is done
}
If you aren't familiar with this event, its name kind of gives it away - it's an event that triggers whenever an animation is done playing (as in: reached its final frame - consult the documentation for a better description). By going into this event and checking whether the current animation that just finished is your attack animation, you can ensure that the player goes back to his / her idle state.

Also, by setting an image_speed when pressing shift, the animation will automatically play until its final frame, upon which it will trigger your "animation end" event.
 

Sarena

Member
Your code happens once shift is pressed. That means once. How do you advance your animation? By adding 1 to your image_index. But this only happens once, because it only happens once shift is pressed.

A better solution would be to replace "image_index+=0" with "image_speed=0.3" (replace 0.3 with whatever works), and then add an "animation end" event.

Also, by setting an image_speed when pressing shift, the animation will automatically play until its final frame, upon which it will trigger your "animation end" event.
Thanks, JeffJ! This does make a lot more sense why it's happening, now that you explain it that way.

Unfortunately it still doesn't seem to be working for me. I think it might actually have something to do with the collisions/other animations that I set up earlier in my step event that is causing it to immediately show the idle sprite now.

Here's what I've tried to set up in the Step Event with that in mind, as well as taking your suggestions:

Code:
// Animations

// If Object At
var l6827878A_0 = instance_place(x, y + 1, objWall);
if (!(l6827878A_0 > 0))
{
    // If Expression
    if(sign(vsp) > 0)
    {
        // Set Sprite
        sprite_index = sprPlayerJump;
        image_index = 0;
    
        // Set Animation Speed
        image_speed = 0;
    }

    // Else
    else
    {
        // Set Sprite
        sprite_index = sprPlayerJump;
        image_index = 1;
    
        // Set Animation Speed
        image_speed = 0;
    }
}

// Else
else
{
    // Set Animation Speed
    image_speed = 1;

    // If Variable
    if(hsp == 0)
    {
        // If Expression
        if(keyboard_check_pressed(vk_shift))
        {
            // Set Sprite
            sprite_index = sprPlayerSword;
            image_index = 1;
        
            // Set Animation Speed
            image_speed = 1;
        }
    
        // Else
        else
        {
            // Set Sprite
            sprite_index = sprPlayer;
            image_index = 0;
        }
    }

    // Else
    else
    {
        // Set Sprite
        sprite_index = sprPlayerRun;
        image_index += 0;
    }
}

// If Variable
if(!(hsp == 0))
{
    // Set Instance Scale
    image_xscale = sign(hsp);
    image_yscale = 1;
}


// Sword Attack

// If Expression
if(keyboard_check_pressed(vk_shift))
{
    // Declare Temp
    var xdifference = x - xprevious;
    var ydifference = y - yprevious;

    // If Expression
    if(!(xdifference = 0 and ydifference = 0))
    {
        // Assign Variable
        swordx = xdifference;
        swordy = ydifference;
    }

    // Create Instance
    instance_create_layer(x + sign(xdifference) * 32, y + sign(ydifference) * 32, "Instances", objPHitBox);
}
I understand part of this might be like you said that it is only playing when Shift is pressed, but would I need to set up an alarm or something to tell it to continue playing the animation even after it has been released?

I also added this into the Animation End Event, as you suggested:

Code:
// If Expression
if(sprite_index = sprPlayerSword)
{
    // If Expression
    if(image_index = 8)
    {
        // Set Sprite
        sprite_index = sprPlayer;
        image_index = 0;
    }
}
 

JeffJ

Member
First off, you are still manually setting the image_index to be 1 when you press shift. This likely means the animation will never advance. Remove that line, and just keep with setting your image_speed.

Second, there is no need for checking "if image_index = 8" in your animation end event; this is literally what the animation end event does for you. So remove that check, and just set your sprite.

Finally, what specifically isn't working? Is it the same as before, or another problem? When you press shift, does your player just go to the first frame and then... What? Describe what happens.
 

Sarena

Member
Yeah, the issue was the same where it would flash the first frame, so nothing had changed.

I was able to resolve the issue by actually creating a variable that checks if the sword swing animation is playing. So now it correctly plays through the animation each time the sword swings, and it will only play once.

Here is the working Step Event:
Code:
// Animations

// If Object At
var l6827878A_0 = instance_place(x, y + 1, objWall);
if (!(l6827878A_0 > 0))
{
    // If Expression
    if(sign(vsp) > 0)
    {
        // Set Sprite
        sprite_index = sprPlayerJump;
        image_index = 0;
    
        // Set Animation Speed
        image_speed = 0;
    }

    // Else
    else
    {
        // Set Sprite
        sprite_index = sprPlayerJump;
        image_index = 1;
    
        // Set Animation Speed
        image_speed = 0;
    }
}

// Else
else
{
    // Set Animation Speed
    image_speed = 1;

    // If Variable
    if(hsp == 0)
    {
        // If Variable
        if(swordswing == true)
        {
            // Set Sprite
            sprite_index = sprPlayerSword;
            image_index += 0;
        
            // If Expression
            if(sprite_index = sprPlayerSword)
            {
                // If Expression
                if(image_index = 8)
                {
                    // Set Sprite
                    sprite_index = sprPlayer;
                    image_index += 0;
                
                    // Assign Variable
                    swordswing = false;
                }
            }
        }
    
        // Else
        else
        {
            // Set Sprite
            sprite_index = sprPlayer;
            image_index += 0;
        }
    }

    // Else
    else
    {
        // Set Sprite
        sprite_index = sprPlayerRun;
        image_index += 0;
    }
}

// If Variable
if(!(hsp == 0))
{
    // Set Instance Scale
    image_xscale = sign(hsp);
    image_yscale = 1;
}

// Execute Code
// Sword Attack

// If Expression
if(keyboard_check_pressed(vk_shift))
{
    // Assign Variable
    swordswing = true;

    // Declare Temp
    var xdifference = x - xprevious;
    var ydifference = y - yprevious;

    // If Variable
    if(swordswing == true)
    {
        // Set Sprite
        sprite_index = sprPlayerSword;
        image_index += 0;
    
        // If Expression
        if(sprite_index = sprPlayerSword)
        {
            // If Expression
            if(image_index = 8)
            {
                // Set Sprite
                sprite_index = sprPlayer;
                image_index += 0;
            
                // Assign Variable
                swordswing = false;
            }
        }
    }

    // If Expression
    if(!(xdifference = 0 and ydifference = 0))
    {
        // Assign Variable
        swordx = xdifference;
        swordy = ydifference;
    }

    // Create Instance
    instance_create_layer(x + sign(xdifference) * 32, y + sign(ydifference) * 32, "Instances", objPHitBox);
}
And the working Animation End Event:
Code:
// If Expression
if(sprite_index = sprPlayerSword)
{
    // Assign Variable
    swordswing = false;

    // Set Sprite
    sprite_index = sprPlayer;
    image_index = 0;
}
Thank you so much for your help, JeffJ!
 
Top