SOLVED [Solved by TailBit] Animate Sprite Frames

Nyro17

Member
Hello! Its me again! :D

I would like to know if there is a way to draw all frames from 1 sprite once I click a button.

I have the following structure:
objPlayer containing:
GUI Draw
Create
...
sprEnergySpell
It contains 8 frames and the speed is set to 8.

About the touch button it works, so I wont say something about it...

Main problem:
When I write the following in GUI draw:
Code:
if(device_mouse_button_checked_released){
draw_sprite(sprEnergySpell,0,objPlayer.x, objPlayer.y);
}
It only draw the last frame of all sprites and dissappear so fast without respect the frame speed.

Any idea? :O

Thanks,
Nyro.
 
D

Deleted member 13992

Guest
Gamemaker will only do what you tell it to do. So when you're telling it, using draw_sprite, to draw index 0 of the sprite, it will only draw index 0. Exactly as you wrote it.

Use image_index. This will "count up" by default assuming your frame speed is good.

Also make sure device_mouse_button_checked_released is true for the duration of the 8 frames. hard to tell with the code you posted because you don't tell how it's set.
 

rIKmAN

Member
Gamemaker will only do what you tell it to do. So when you're telling it, using draw_sprite, to draw index 0 of the sprite, it will only draw index 0. Exactly as you wrote it.

Use image_index. This will "count up" by default assuming your frame speed is good.

Also make sure device_mouse_button_checked_released is true for the duration of the 8 frames. hard to tell with the code you posted because you don't tell how it's set.
device_mouse_check_button_released() is a GML function, so they are either using a variable that clashes with the built in function name or they aren't using the function correctly as it requires arguments.
The function also only fires for a single frame when the button is released, so it's impossible for the function to return true for the duration of 8 frames.

OP: Check out the manual page for the function here: Manual Page
 
D

Deleted member 13992

Guest
device_mouse_check_button_released() is a GML function
My bad. That'll teach me to use the old manual to search for a function.
Also, because as you said, no arguments were used so I thought it was a variable.
 

Nyro17

Member
device_mouse_check_button_released() is a GML function, so they are either using a variable that clashes with the built in function name or they aren't using the function correctly as it requires arguments.
The function also only fires for a single frame when the button is released, so it's impossible for the function to return true for the duration of 8 frames.

OP: Check out the manual page for the function here: Manual Page
Hello, I know the correct sentence to do clicks, I just wrote a short way...

Is there any way to draw all these frames once I click?

Thanks
 
Something around these lines would display the frames laid out horizontally from left to right.
From there, I think you're good to go on your own.
GML:
var _num = sprite_get_number(spr_your_sprite);
var _w = sprite_get_width(spr_your_sprite);

for(var _i=0; _i<_num; _i++){
    draw_sprite(spr_your_sprite, _i, x+(_i*_w), y);
}
 

Nyro17

Member
Something around these lines would display the frames laid out horizontally from left to right.
From there, I think you're good to go on your own.
GML:
var _num = sprite_get_number(spr_your_sprite);
var _w = sprite_get_width(spr_your_sprite);

for(var _i=0; _i<_num; _i++){
    draw_sprite(spr_your_sprite, _i, x+(_i*_w), y);
}
Hello,
thanks for your suggestions, I have already tested it before and It just draw the last sprite =[.

Is there any way more?

Thanks
 
Hello,
thanks for your suggestions, I have already tested it before and It just draw the last sprite =[.

Is there any way more?

Thanks
Works on my end. Which means something else is wrong in your code.
The _i variable at the place of the sprite index ensures all frames will be drawn.

 
Last edited:
D

Deleted member 13992

Guest
Temporarily remove your if condition and just draw_sprite, with image_index and the same x/y coords you were trying in your original post. It's a quick test. What happens then?
 

Nyro17

Member
Works on my end. Which means something else is wrong in your code.
The _i variable at the place of the sprite index ensures all frames will be drawn.

This is my code with yours:
Code:
var _x = device_mouse_x_to_gui(0);
var _y = device_mouse_y_to_gui(0);
if (device_mouse_check_button(0,mb_any) and point_in_rectangle(_x, _y, spellWindow1_x, spellWindow1_y, spellWindow1_x+spellWindow1_width, spellWindow1_y+spellWindow1_height)){
        var _num = sprite_get_number(sprEneryStrike);
        var _w = sprite_get_width(sprEneryStrike);

        for(var _i=0; _i<_num; _i++){
            draw_sprite(sprEneryStrike, _i, objCamara.iw/2, objCamara.ih/2+16);
            image_speed = 1;
        }
}
Pasting your code, i see the same like you, all sprites draw to right. But I need all sprites in sequence at same x,y position so, for me, its not working, it just draw the last frame=[
 

Nyro17

Member
Temporarily remove your if condition and just draw_sprite, with image_index and the same x/y coords you were trying in your original post. It's a quick test. What happens then?
Hello, I've tried the following:
Code:
draw_sprite(image_index(sprEneryStrike), 0, objCamara.iw/2, objCamara.ih/2+16);
It gives error:
Code:
camera_create() - doesn't take any arguments
 at gml_Object_objPlayer_Draw_64 (line 15) -                      draw_sprite(image_index(sprEneryStrike), 0, objCamara.iw/2, objCamara.ih/2+16);
############################################################################################
gml_Object_objPlayer_Draw_64 (line 15)
Maybe Im not doing it well!
 
Pasting your code, i see the same like you, all sprites draw to right. But I need all sprites in sequence at same x,y position so, for me, its not working, it just draw the last frame=[
Dude, if you draw them on the same x and y, they are just going to be on top of each other, hence you'll only view the last frame...
Go with a little logic before you blame the code, come on...
 

Nyro17

Member
Dude, if you draw them on the same x and y, they are just going to be on top of each other, hence you'll only view the last frame...
Go with a little logic before you blame the code, come on...
I do, I have my sprites from bigger to smaller..
But I always see the same, bigger or smaller, according to FOR loop.
So I ask about how to do that, maybe you didnt understand me?
Lets suppose something to do it more easy:
X = player
A = frame

I try to do the following:
According to X direction, A must be next to X. So sprites will be drawn next to X.
The problem is that I just see the first or the last sprite frame
Is there any way to draw the others sprites? I have them in reverse mode, from Bigged to Smaller.
If I move my player, the others frames are drawn. I need to do it without moving the player.
 
D

Deleted member 13992

Guest
Hello, I've tried the following:
Code:
draw_sprite(image_index(sprEneryStrike), 0, objCamara.iw/2, objCamara.ih/2+16);

This isn't how draw_sprite works. And that's not how you use image_index. Look at the draw_sprite example in the manual:


Code:
draw_sprite(sprite_index, image_index, x, y);
draw_sprite(spr_Halo, 0, x, y-32);
And read this part carefully, and apply it to how you've written your own code. The answer as to why you're only seeing a single frame is there.

This will draw the instances assigned sprite (sprite_index) with the current sub-image at the x and y position of the instance within the room. It will then draw the first frame of the sprite indexed by "spr_Halo" at the same x and y position but 32 pixels 'above'.
I also explained it in my first reply in the thread.






Spoiler: here's what your draw_sprite should look like.
Code:
draw_sprite(sprEnergySpell, image_index, objPlayer.x, objPlayer.y);
See how I replaced 0 with image_index? image_index "counts up" automatically as long as your frame speed is correct. You had a 0 there, so it was only ever going to show you frame 0.

Now just make sure your if condition is true for the duration of your 8 frames.
 
Last edited by a moderator:

Nyro17

Member
This isn't how draw_sprite works. And that's not how you use image_index. Look at the draw_sprite example in the manual:


Code:
draw_sprite(sprite_index, image_index, x, y);
draw_sprite(spr_Halo, 0, x, y-32);
And read this part carefully, and apply it to how you've written your own code. The answer as to why you're only seeing a single frame is there.



I also explained it in my first reply in the thread.






Spoiler: here's what your draw_sprite should look like.
Code:
draw_sprite(sprEnergySpell, image_index, objPlayer.x, objPlayer.y);
See how I replaced 0 with image_index? image_index "counts up" automatically as long as your frame speed is correct. You had a 0 there, so it was only ever going to show you frame 0.

Now just make sure your if condition is true for the duration of your 8 frames.
Hello, I have the followin:
1627057706581.png

And this is now my draw_sprite();
1627057802082.png

I dont know what Im doing wrong, it just draw the first or the last...

To all who read it: dont be mad with me!! im new :D
 
I try to do the following:
According to X direction, A must be next to X. So sprites will be drawn next to X.
The problem is that I just see the first or the last sprite frame
Is there any way to draw the others sprites? I have them in reverse mode, from Bigged to Smaller.
If I move my player, the others frames are drawn. I need to do it without moving the player.
Well, for a first, you have to set and get the direction you are facing somehow, and if you are moving. Once you got all that stored in variables, then you could work in a neat switch statement.
 

Nyro17

Member
Well, for a first, you have to set and get the direction you are facing somehow, and if you are moving. Once you got all that stored in variables, then you could work in a neat switch statement.
I will, but not now, i just need to know how to draw all the frames from 1 sprite =[
 
D

Deleted member 13992

Guest
Hello, I have the followin:
View attachment 41566

And this is now my draw_sprite();
View attachment 41567

I dont know what Im doing wrong, it just draw the first or the last...

To all who read it: dont be mad with me!! im new :D



You're using device_mouse_check_button_pressed for draw_sprite. This is a problem, because it's only set as true once, for a single frame, until the mouse is clicked again. Look at the manual:


This function is only triggered once by the actual pressing action


That said, I got confused with the object you're using to draw the sprite. I thought you were using an object that wasn't objPlayer, since you're refering to tha tobject in the draw event. (you dont' have to use objPlayer.x within the object called objPlayer, since it already knows what x and y is).

There are multiple problems. Partly it's me who confused the issue. However, my comments on image_index and 0 are still valid. When you're using draw_sprite and telling it to draw frame 0, it'll just draw frame zero. Normally you'd have image_index in there instead of the 0, but sicne you are drawing a sprite that is not objPlayer but within objPlayer events, you need to write your own variable that counts up.

Slow Fingers solution is good.
 
D

Deleted member 13992

Guest
Does this do anything?


create event:
Code:
energy_strike_enable = false;
energy_strike_f = 0;
step event:
Code:
if (device_mouse_check_button_pressed(0, mb_any) {
    energy_strike_enable = true;
}

if (energy_strike_f >= 8) {
    energy_strike_enable = false;
    energy_strike_f = 0;
}
draw event:
Code:
draw_self();

if (energy_strike_enable) {
    draw_sprite(sprEnergySpell, energy_strike_f , x, y);
}
If so, do you understand how this code works?
 

Nyro17

Member
Does this do anything?


create event:
Code:
energy_strike_enable = false;
energy_strike_f = 0;
step event:
Code:
if (device_mouse_check_button_pressed(0, mb_any) {
    energy_strike_enable = true;
}

if (energy_strike_f >= 8) {
    energy_strike_enable = false;
    energy_strike_f = 0;
}
draw event:
Code:
draw_self();

if (energy_strike_enable) {
    draw_sprite(sprEnergySpell, energy_strike_f , x, y);
}
If so, do you understand how this code works?

If so, do you understand how this code works?
[/QUOTE]

I think is not about mouse clicks. This click work like that: if you touch the button, you will cast 1 spell, after that, button comes like not pressed.
Well, I think the problem is the speed, is there any way to add some delay between frames?
 
D

Deleted member 13992

Guest
I think is not about mouse clicks. This click work like that: if you touch the button, you will cast 1 spell, after that, button comes like not pressed.
Well, I think the problem is the speed, is there any way to add some delay between frames?
A delay between frames isn't necessary if you've correctly set the framerate on the sprite. The framerate you set on the sprite *is* the "delay" between frames.

What is your game speed set to? What is sprEnergySpell's framerate? And did you try the code I posted above?
 

Nyro17

Member
A delay between frames isn't necessary if you've correctly set the framerate on the sprite. The framerate you set on the sprite *is* the "delay" between frames.

What is your game speed set to? What is sprEnergySpell's framerate? And did you try the code I posted above?
Hello
I have tried it, when I set draw_self, it draw another objPlayer xD next to button.
Game speed is 60 and frame speed is 5 per second
 
D

Deleted member 13992

Guest
Hello
I have tried it, when I set draw_self, it draw another objPlayer xD next to button.
Game speed is 60 and frame speed is 5 per second
You can remove draw_self. I put it there because I don't see your whole project, so I didn't know how you were drawing the player. Normally you'd need to put that there if you're drawing sprites on top of the player sprite, within the player's draw event.

But more importantly, did sprEnergySpell animate?
 

Attachments

Last edited by a moderator:

Nyro17

Member
You can remove draw_self. I put it there because I don't see your whole project, so I didn't know how you were drawing the player. Normally you'd need to put that there if you're drawing sprites on top of the player sprite, within the player's draw event.

But more importantly, did sprEnergySpell animate?
sprEnergySpell contain 1 main sprite and 4 sub sprites/frames, each 1 is bigger than last sprite(same size, 16x16bits), so its 5 frames in total.

Sorry, Im new in GMS2...šŸ˜­
 
D

Deleted member 13992

Guest
sprEnergySpell contain 1 main sprite and 4 sub sprites/frames, each 1 is bigger than last sprite(same size, 16x16bits), so its 5 frames in total.

Sorry, Im new in GMS2...šŸ˜­
In the screenshot you posted earlier, why is it written 60 fps, if you say it's set at 5 fps?

1627063337300.png



Sorry for the simple questions. I'm just trying to get an idea of how your project is set up.
 

Nyro17

Member
@muki
I surrender, I tried 100 different code ways, 0 results.
The only who could work was: create 1 obj, give him sprEnergyStrike...
On map I see the full frames, but still the same problem, how to draw it instead of draw it on map manually?
I surrender.
Thanks to everyone who supported here.šŸ„°
 

TailBit

Member
Okay, so this is a spell button, and this button already have its own sprite that you want to show

At work I wrote this code, but I'm unsure if this object need to draw itself as well.

Create event
Code:
show = false;
Global mouse left pressed event
GML:
show = true;
sprite_index = sprEnergySpell;
image_speed = 1/4;
image_index = 0;
Animation end event
GML:
show = false;
Draw event
GML:
if show {
draw_sprite(sprite_index,image_index,objPlayer.x, objPlayer.y);
}
But if you need separate variables for it then it could be something like this instead:

create
GML:
spr_index = noone;
img_index = 0;
image_speed = 0.2;
EDIT: added a lower image_speed to slow it down

step event
GML:
if spr_index!=noone{
    img_index += image_speed;
    if sprite_get_number(spr_index)<=img_index {
        spr_index = noone;
        img_index = 0;
    }
}

/* I used this to test so I could press anywhere in room
var spellWindow1_x = 0,
spellWindow1_y = 0,
spellWindow1_width=room_width,
spellWindow1_height = room_height;
*/

if (device_mouse_check_button(0,mb_any)){
    var _x = device_mouse_x_to_gui(0);
    var _y = device_mouse_y_to_gui(0);
    
    if(point_in_rectangle(_x, _y, spellWindow1_x, spellWindow1_y, spellWindow1_x+spellWindow1_width, spellWindow1_y+spellWindow1_height)){
        spr_index =sprEnergySpell;
    }
}
EDIT: fixed the spr_ind so it is spr_index, and added the missing "(" that gave a few errors
draw event:
GML:
draw_self() // draw self don't work if it doesn't have a sprite

if spr_index != noone with(objPlayer) draw_sprite(other.spr_index,other.img_index,x,y);
Since you tried to draw it at the player first, then I will tell it to draw it on player here.

Because I use "with", then the player is now running the code, so I have to use "other" to refer back to the variables that is in this instance and not in player
 
Last edited:

Nyro17

Member
Okay, so this is a spell button, and this button already have its own sprite that you want to show

At work I wrote this code, but I'm unsure if this object need to draw itself as well.

Create event
Code:
show = false;
Global mouse left pressed event
GML:
show = true;
sprite_index = sprEnergySpell;
image_speed = 1/4;
image_index = 0;
Animation end event
GML:
show = false;
Draw event
GML:
if show {
draw_sprite(sprite_index,image_index,objPlayer.x, objPlayer.y);
}
But if you need separate variables for it then it could be something like this instead:

create
spr_index = noone;
img_index = 0;

step event
GML:
if spr_ind!=noone{
    img_index += image_speed;
    if sprite_get_number(spr_index)<=img_index {
        spr_index = noone;
        img_index = 0;
    }
}

if (device_mouse_check_button(0,mb_any){
    var _x = device_mouse_x_to_gui(0);
    var _y = device_mouse_y_to_gui(0);
   
    if point_in_rectangle(_x, _y, spellWindow1_x, spellWindow1_y, spellWindow1_x+spellWindow1_width, spellWindow1_y+spellWindow1_height)){
        spr_index =sprEnergySpell;
    }
}
draw event:
GML:
draw_self()

if spr_index != noone with(objPlayer) draw_sprite(other.spr_index,other.img_index,x,y);
Since you tried to draw it at the player first, then I will tell it to draw it on player here.

Because I use "with", then the player is now running the code, so I have to use "other" to refer back to the variables that is in this instance and not in player
Hello, I have tried it, it doesnt do anything =[
Thanks
 

TailBit

Member
I tested the bottom one and it worked
press_test.gif
It had some typos.. img_ind should have been img_index and missing ( and )

Edited the code in my last post
 

Nyro17

Member
I tested the bottom one and it worked
View attachment 41586
It had some typos.. img_ind should have been img_index and missing ( and )

Edited the code in my last post
Thank you so much, you already solved my biggest problem ever!!!!!!!!!
I found another error, it wasnt drawing anything because I wrote your code in objEnergyStrike, it wasnt right, it should be placed on GUI object, this way works.

Here I write final solution in case someone need to find it more easy:
Code:
//Create event
spr_index = noone;
img_index = 0;
image_speed = 0.2;
   
//Step Event

if spr_index!=noone{
img_index += image_speed;
if sprite_get_number(spr_index)<=img_index {
spr_index = noone;
img_index = 0;
}
}

if (device_mouse_check_button(0,mb_any)){
var _x = device_mouse_x_to_gui(0);
var _y = device_mouse_y_to_gui(0);

if(point_in_rectangle(_x, _y, spellWindow1_x, spellWindow1_y, spellWindow1_x+spellWindow1_width, spellWindow1_y+spellWindow1_height)){
spr_index =sprEnergySpell;
}
}

//Draw Event:
if spr_index != noone with(objPlayer) draw_sprite(other.spr_index,other.img_index,x,y);
All credits goes to @TailBit
 
Top