GMS 2 need help with attack animation that keeps looping

N

nired360

Guest
Hello everyone, i created a state machine for my character and am having a problem with my attack state, whenever i press the attack button my characters keeps on repeating the attack animation, here's the code incase it helps , thx !

switch (state)
{
case states.idle:
{
sprite_index = idle;
if (hsp != 0 ) and grounded = true state = states.run;
if key_attack and grounded = true state = states.attack;
if key_jump and grounded = true state = states.jump;
}
break;
case states.run:
{
sprite_index = run;
if (hsp = 0) and grounded = true state = states.idle;
if vsp < 0 and grounded = false state = states.jump;
if key_attack and grounded = true state = states.attack;
}
break;
case states.jump:
{
sprite_index = jump;
if (hsp = 0) and grounded = true state = states.idle;
if (hsp != 0 ) and grounded = true state = states.run;
}
break;
case states.attack:
{
sprite_index = tak;
instance_create_layer(x,y,"Collision_Layer",hitbox);
}
break;

}
while vsp > 0
{
sprite_index = jump;
image_index = 4;
break;
}
 
S

Spencer S

Guest
This code is pretty hard to read for me. I'm going to assume this wasn't copied and pasted over, as this code as written wouldn't even work.

My best guess is that either: you are forgetting to set key_attack to false after the animation finishes, or, less likely, you are setting the sprite_index to attack somewhere else, and you just forgot about it.

It would help to see the actual code you have written, so we can identify any actual problems.
 
T

trialuser

Guest
@nired360 Try this: update your states.attack case.
Code:
case states.attack:
{
 sprite_index = tak;
 instance_create_layer(x,y,"Collision_Layer",hitbox);
 if(image_index = image_number) state = states.idle; // add this new line
}
break;
 
N

nired360

Guest
This code is pretty hard to read for me. I'm going to assume this wasn't copied and pasted over, as this code as written wouldn't even work.

My best guess is that either: you are forgetting to set key_attack to false after the animation finishes, or, less likely, you are setting the sprite_index to attack somewhere else, and you just forgot about it.

It would help to see the actual code you have written, so we can identify any actual problems.
actually this code IS copied and pasted over and it's working fine so far , i have assigned cases for different states like ( idle, attacking, jumping ....etc) , this is my attack button code:
key_attack = keyboard_check_pressed(vk_lalt);
and this is the attack state code :
case states.attack:
{
sprite_index = tak;
instance_create_layer(x,y,"Collision_Layer",hitbox);
if (hsp != 0) and grounded = true state = states.run;
if vsp < 0 and grounded = false state = states.jump;
attack = false;

}
break;
like i said the attack animaion keeps on repeating if i press the button and it transits to the other assigned animations if i run, jump...etc.
PS : is there a command that only draws a sprite once without repeating it???
 
S

Spencer S

Guest
That's insane, lol. Idk how that is running, but props to you for making it work.

Its probably just me then, but I truly can't see whats happening here. My best guess? It doesn't look like you're resetting your "state" variable anywhere after the attack state is supposed to end, so the variable "state" just stays equal to "states.attack". In your switch statement, here:
Code:
case states.attack:
{
sprite_index = tak;
instance_create_layer(x,y,"Collision_Layer",hitbox);
}
break;
I would simply add the following, just like @trialuser said:

Code:
case states.attack:
{
 sprite_index = tak;
 instance_create_layer(x,y,"Collision_Layer",hitbox);
 if(image_index = image_number) state = states.idle; // add this new line
}
break;
 
N

nired360

Guest
@nired360 Try this: update your states.attack case.
Code:
case states.attack:
{
 sprite_index = tak;
 instance_create_layer(x,y,"Collision_Layer",hitbox);
 if(image_index = image_number) state = states.idle; // add this new line
}
break;
didn't work :(
 
T

trialuser

Guest
@nired360 How about use 'else if' instead of 'if':
Code:
if (hsp != 0 ) and grounded = true state = states.run;
else if key_attack and grounded = true state = states.attack;
else if key_jump and grounded = true state = states.jump;
I guess it's something about the priority of the attack state is above the idle state :d
 

samspade

Member
In your original code the problem is that you don't have anything that will exit you out of attack state. If that code is outside of the state machine, it would be helpful to see it.

Code to stop an action at animation end is:

Code:
if (image_index + image_speed >= image_number) {
  state = states.idle;
}
There is also an animation end event.

A couple side notes. I'm very surprised your while statement doesn't crash the game as there is no apparent exit from it. In your original code, you probably want to put breaks after each line as otherwise you will overwrite the previous line, which may or may not be what you want. For example, in the idle state, if you push attack and jump, jump will overwrite attack. Example of what I mean:

Code:
case states.idle:
{
    sprite_index = idle;
    if (hsp != 0 ) && (grounded == true) {state = states.run; break;}
    if (key_attack) && {grounded == true) {state = states.attack; break;}
    if (key_jump) && (grounded == true) {state = states.jump; break;}
}
break;
Also, you should indent and post your code in code brackets. Finally while I generally think any form of writing code is okay if it is consistent, which your code actually is, this might be one of the times I think that isn't true. I would strongly recommend reading this and adopting one of the suggestions You're current code would only work in something as forgiving as GM, is hard to read (for people trying to help) requires you to re-write it if you want to extend the code beyond a single line and contains several bad practices that will get you in trouble elsewhere (such as when using shaders).

https://forum.yoyogames.com/index.p...on-the-programming-forum-dos-and-donts.22926/
 
N

nired360

Guest
In your original code the problem is that you don't have anything that will exit you out of attack state. If that code is outside of the state machine, it would be helpful to see it.

Code to stop an action at animation end is:

Code:
if (image_index + image_speed >= image_number) {
  state = states.idle;
}
There is also an animation end event.

A couple side notes. I'm very surprised your while statement doesn't crash the game as there is no apparent exit from it. In your original code, you probably want to put breaks after each line as otherwise you will overwrite the previous line, which may or may not be what you want. For example, in the idle state, if you push attack and jump, jump will overwrite attack. Example of what I mean:

Code:
case states.idle:
{
    sprite_index = idle;
    if (hsp != 0 ) && (grounded == true) {state = states.run; break;}
    if (key_attack) && {grounded == true) {state = states.attack; break;}
    if (key_jump) && (grounded == true) {state = states.jump; break;}
}
break;
Also, you should indent and post your code in code brackets. Finally while I generally think any form of writing code is okay if it is consistent, which your code actually is, this might be one of the times I think that isn't true. I would strongly recommend reading this and adopting one of the suggestions You're current code would only work in something as forgiving as GM, is hard to read (for people trying to help) requires you to re-write it if you want to extend the code beyond a single line and contains several bad practices that will get you in trouble elsewhere (such as when using shaders).

https://forum.yoyogames.com/index.p...on-the-programming-forum-dos-and-donts.22926/
Thx dude! the problem seems to have been solved , and btw i used the break statement after each line but some animations didn't work but they do when i use the break statement at the end of the case and there seems to be no crashes at the moment :) , one more thing when i use image_index = sign(hsp) ; inside my run state or idle state :

case states.idle:
{
sprite_index = idle;
if (hsp != 0 ) and grounded = true state = states.run;
if key_jump and grounded = true state = states.jump;
if key_attack and grounded = true state = states.attack;
}
break;
case states.run:
{
sprite_index = run;
if (hsp = 0) and grounded = true state = states.idle;
if vsp < 0 and grounded = false state = states.jump;
if key_attack and grounded = true state = states.attack;

}
break;
my character animates for like 0.5 sec and then disappears when i face the other direction , any idea on how to solve this???
 

samspade

Member
I'm not exactly sure what image_index = sign(hsp) would do but it definitely won't work in a normal way. Sign returns only -1, 0, 1; So you're setting the image_index to one of those three numbers. -1 might actually play a sprite normally? but 0 and 1 will definitely lock a sprite to that index.

Normally you would do that with image_xscale. Which is maybe what you meant. You can lock image_xscale to sign of hsp but you only want to do that if hsp does not equal 0. If hsp equals 0, then image_xscale will equal 0 and the sprite will effectively have a width of 0.

Some common ways to do this are:

Code:
if (hsp != 0) {
    image_xscale = sign(hsp);
}

//or using a separate variable which is sometimes useful for other portions of the code
// or I f you wan to handle more of the drawing yourself.

if (hsp != 0) {
    facing = sign(hsp);
}

image_xscale = facing;
 
N

nired360

Guest
I'm not exactly sure what image_index = sign(hsp) would do but it definitely won't work in a normal way. Sign returns only -1, 0, 1; So you're setting the image_index to one of those three numbers. -1 might actually play a sprite normally? but 0 and 1 will definitely lock a sprite to that index.

Normally you would do that with image_xscale. Which is maybe what you meant. You can lock image_xscale to sign of hsp but you only want to do that if hsp does not equal 0. If hsp equals 0, then image_xscale will equal 0 and the sprite will effectively have a width of 0.

Some common ways to do this are:

Code:
if (hsp != 0) {
    image_xscale = sign(hsp);
}

//or using a separate variable which is sometimes useful for other portions of the code
// or I f you wan to handle more of the drawing yourself.

if (hsp != 0) {
    facing = sign(hsp);
}

image_xscale = facing;
LOL i meant image_xscale, thank you so much bro !, my char is animating without any problems now , again thanks for the help everyone!
 
Top