GML Beginner learning animation codes and tricks

C

Canamla

Guest
So I wasn't able to find anything useful while searching, but I have a stationary plant creature that I designed a few idling animations to switch between.

I wanted to stage the animation sequences so that it can be still for a few seconds, run one animation and then the following one at an interval.

So like:
Idle for a few seconds, idle action 1, idle for a few seconds, idle action 2. Each animation/action stopping after it runs once.

I'm not very savy with code so if you can suggest some lesson or something that would cover at least this, I'd be very grateful.

Basically, I'm just trying to see how my animations flow for this and future designs without creating a long chain of frames like a traditional or flash animation.
Thanks!
 
D

DyingSilence

Guest
My suggestion:

Code:
//rather pseudocode, change it for your purposes

//CREATE

next_anim = 60; //or something else you like
image_speed=0; // sets the engine animation speed to 0 so your sprite doesn't autoplay

//here's an array of your other idles, sprite indexes are in fact numbers
idles_number[0] = spr_idle_01;
idles_number[1] = spr_idle_02;
idles_number[2] = spr_idle_03;
idles_number[3] = spr_idle_04;

//STEP

//counts down to changing to the special animation and picks one at random
if(sprite_index == main_idle)
{
 next_anim--;
if(next_anim<0)
{
sprite_index = idles_number[irandom(array_length_1d(idles_number)-1)];
}
}

if(image_index==image_number)
{
if(sprite_index!=main_idle)
{
//if a special animation is finished, switches back to the main one
sprite_index=main_idle;
next_anim=room_speed*2;
}
else
{
//if a main animation is finished, it starts over
image_index=0;
}
}
else
{
//if animation is NOT finished, it goes one frame further
image_index++;
}
That's how i would handle that. If you don't understand anything, just ask :)

edit: corrected a misleading typo
 
C

Canamla

Guest
That's how i would handle that. If you don't understand anything, just ask :)

edit: corrected a misleading typo
I don't think I fully grasp it and I feel like I made a mistake (not working). It's frozen on the main idle.
//CREATE
next_anim = 60;
image_speed = 0;

idle_number[0] = spr_wallop_idle;
idle_number[1] = spr_wallop_idle_mouth_wet;
idle_number[2] = spr_wallop_idle_mouth_grind;


//STEP
if (sprite_index == spr_wallop_idle){
next_anim --;
if (next_anim < 0){
sprite_index = idle_number[irandom(array_length_1d(0))];
}
}


if (image_index = 1){
if (sprite_index != spr_wallop_idle){
sprite_index = spr_wallop_idle;
next_anim = room_speed * 2;
}
else {
image_index = 0;
}
}

else {
image_index ++;
}
 
Code:
//CREATE
anim_speed = 1 // <-- ADDED because we are not using image_speed in this code, you might want a way to adjust the frame rate of the animation speed manually.
// anim_speed of one means the animation plays one frame per step, or 60 frames per second if your room_speed is 60
next_anim = 60;
image_speed = 0;

// REMOVED spr_wallop_idle from array - if you have this in the array, it might end up playing the main idle a few times if randomly selected and appear like its not changing to the other idle states.
// You could leave it in there if that's the effect you wanted.
idle_number[0] = spr_wallop_idle_mouth_wet;
idle_number[1] = spr_wallop_idle_mouth_grind;


//STEP
if (sprite_index == spr_wallop_idle)
{
    next_anim --;
    if (next_anim < 0)
    {
        sprite_index = idle_number[irandom(array_length_1d(idle_number) - 1)]; //<-- EDITED - Need to put array name (not just the number 0 ) to get the actual length of the array
        image_index = 0 // <-- ADDED So animation of this idle starts at beginning
    }
}


if (image_index = image_number) //<-- EDITED (You had changed this to 1, which meant only 1 frame would play before switching back to spr_wallop_idle)
{
    if (sprite_index != spr_wallop_idle)
    {
        sprite_index = spr_wallop_idle;
        next_anim = room_speed * 2;
    }
    else
   {
        image_index = 0;
    }
}
else
{
    image_index += anim_speed; //<-- EDITED
}
 
Last edited:

CMAllen

Member
I will presume each idle animation is its own sprite, and not just a sub-image of a single over-arching 'idle' sprite.

(all of the following will only occur when the object is idling)
You want random interval between performing the idle animations. When this interval reaches 0, it's time to check which idle animation to perform, switch to that sprite and set your image_index value to 0. Then you compare that image_index value to the image_number value, and when it exceeds a certain threshold (image_number *0.95 for example) you switch back to your main idling sprite, reset your random interval timer, and repeat.
 
D

DyingSilence

Guest
Code:
//CREATE
anim_speed = 1 // <-- ADDED because we are not using image_speed in this code, you might want a way to adjust the frame rate of the animation speed manually.
// anim_speed of one means the animation plays one frame per step, or 60 frames per second if your room_speed is 60
next_anim = 60;
image_speed = 0;

// REMOVED spr_wallop_idle from array - if you have this in the array, it might end up playing the main idle a few times if randomly selected and appear like its not changing to the other idle states.
// You could leave it in there if that's the effect you wanted.
idle_number[0] = spr_wallop_idle_mouth_wet;
idle_number[1] = spr_wallop_idle_mouth_grind;


//STEP
if (sprite_index == spr_wallop_idle)
{
    next_anim --;
    if (next_anim < 0)
    {
        sprite_index = idle_number[irandom(array_length_1d(idle_number))]; //<-- EDITED - Need to put array name (not just the number 0 ) to get the actual length of the array
        image_index = 0 // <-- ADDED So animation of this idle starts at beginning
    }
}


if (image_index = image_number) //<-- EDITED (You had changed this to 1, which meant only 1 frame would play before switching back to spr_wallop_idle)
{
    if (sprite_index != spr_wallop_idle)
    {
        sprite_index = spr_wallop_idle;
        next_anim = room_speed * 2;
    }
    else
   {
        image_index = 0;
    }
}
else
{
    image_index += anim_speed; //<-- EDITED
}
That's a very nice correction of both his and mine mistakes :)
 
C

Canamla

Guest
Awesome, it's almost working! I had to change the anim_speed to .1 as anything higher causes the first animation to loop forever. The other issue is that when it does move to the second animation, it loops that forever. I really appreciate the efforts to help me out, but I feel guilty that you guys basically just wrote the code for me. How/where did you all learn this? I'd like to understand it so I don't rely on others if I don't need to. Seriously, thank you!
 
A

A. DeVivo

Guest
I second Canamla, I used this code for similar purposes and am having the second animation loop forever. I also agree that I don't just want code written for me, so any resources would be appreciated! <3
 
Awesome, it's almost working! I had to change the anim_speed to .1 as anything higher causes the first animation to loop forever.
Ahhh, my mistake.

Change this line:

Code:
if (image_index = image_number) //<-- EDITED (You had changed this to 1, which meant only 1 frame would play before switching back to spr_wallop_idle)
To this:
Code:
if (image_index >= image_number) //<-- EDITED (You had changed this to 1, which meant only 1 frame would play before switching back to spr_wallop_idle)
This is because if you set the anim speed to say, 0.4, then it will never equal exactly the image_number, so we need to check if it is greater than or equal to the image number, then switch back to the original image.

E.g: Anim speed = 0.4 and for example purposes lets say there is just 1 image in the animation (image_number = 1), even though that's not really an animation!

Code:
Step 1 : image_index += anim_speed -> image_index = 0.4
Step 2: image_index += anim_speed -> image_index = 0.8
Step 3: image_index += anim_speed -> image_index = 1.2 !!!! The original code I wrote won't catch this!!!
I *think* that should do it. If not, let us know.

P.S. Some of this stuff I think is just learned organically from using GMS for a while. As I start to get used to sprites and how they work, making various games, I learn how all the pieces fit together better.

An analogy would be when I first played Counter Strike many years ago, I was getting killed within seconds and couldn't believe how hard the game was. However, once I had a bit of practise and had gotten familiar with the layout of the maps, and knew the bigger picture of where everything was, I became better at not dying. :)

P.P.S Resources - If I am wanting to do something but don't know how...first stop is the manual and reading up on all related functions to what it is I am doing. So for Sprite stuff...check all the functions and variables related to sprites. I was surprised how often that GMS already has built in stuff to solve most of the common problems that people face.
 
Last edited:
A

A. DeVivo

Guest
Hi IndianaBones! I made the
Code:
if (image_index >= image_number)
but seem to still be experiencing the same issue!

Unless you want the
Step 1 : image_index += anim_speed -> image_index = 0.4
Step 2: image_index += anim_speed -> image_index = 0.8
Step 3: image_index += anim_speed -> image_index = 1.2 !!!! The original code I wrote won't catch this!!!
in the actual code but I got the impression that was just for ~teaching purposes~. Thanks so much for helping us out with this!
 
A

A. DeVivo

Guest
Has anyone had any luck solving this? Still grappling with it.
 
Hey there, didn't notice there was a reply to this thread!

Ok I've simplified it down a bit. Not going to use anim_speed this time, so the animation will just use the built in image_speed value.

Create Event:
Code:
//CREATE
idle_time = 60; // How long the basic idle animation will play for. 
image_speed = 1;

idle_number[0] = spr_wallop_idle_mouth_wet;
idle_number[1] = spr_wallop_idle_mouth_grind;
STEP Event
Code:
//STEP
if (idle_time > 0)
{
    idle_time--;
    if (idle_time <= 0) // Switch to one of the idle action animations
    {
        sprite_index = idle_number[irandom(array_length_1d(idle_number) - 1)]; 
        image_index = 0 
    }
}

if (image_index >= image_number )
{
    // If one of the idle actions are playing, switch it back to basic idle
    if (sprite_index != spr_wallop_idle)
    {
        sprite_index = spr_wallop_idle;
        // How long to play the basic idle until we select the next action idle.
        // You could instead assign a random number to idle_time to make the pauses between animations
        // less predictable
        idle_time = room_speed * 2;
    }
}
Instead of writing

idle_time = room_speed * 2

you could write

idle_time = 60 + random(60)

so that the idle actions are not always repeated at the same time intervals.
 
A

A. DeVivo

Guest
Man I unfortunately am still experiencing the same issues- it getting stuck on repeat with the last animation in the order. I've fiddled around with the numbers a lot, still seems to be unhappy with it. Thanks so much for spending so much on this!
 
A

A. DeVivo

Guest
Ah alright so I think the issue is that my idle animations are different frame lengths- any way to account for this, or do I just need to break them up evenly?
 
Different lengths shouldn't be a problem, because when we are playing one of the idle animations it will play the animation until the end because of this check:

Code:
if (image_index >= image_number )
Maybe post a copy of the code that you have now so we can take a look.
 
C

Canamla

Guest
So after a long break from GMS2, I check back here and find that @IndianaBones latest create/step event codes work exceptionally! Thanks so much! This should be a good enough basis for me to work from for other animations. @A. DeVivo , have you sorted out your issues?
 
F

Fhuma

Guest
Hi guys! I tired @IndianaBones latest code, but experiencing the same issue, stuck on the animation chosen after the base idle animation. Since I'm more of an artist, than a coder, I just made some checks, and it looks when idle_time reaches 0 it changes one of the other idle animation, but it won't reset itself, it's value stays 0.
I assume this part suppose to reset the timer:

Code:
if (image_index >= image_number )
{
    // If one of the idle actions are playing, switch it back to basic idle
    if (sprite_index != ani_Idle_base)
    {
        sprite_index = ani_Idle_base;
        idle_time = irandom(60);
    }
    
}
So how can I reset that? Maybe that solve the issue.

I try to achieve that a guy jut standing, main idle is breathing (ani_idle_base), and then randomly adjust his sunglasses or his hair. (It's a point to click game)
 

Rayman2001

Member
I'm having the same issue with @IndianaBones' code! Rayman will only play his stance idle and not switch to the other five. Here's the code I have:


GML:
//CREATE
idle_time = .1;
image_speed = 1;


idle_number[0] = SRayman_Idle;
idle_number[1] = SRayman_idle1;
idle_number[2] = SRayman_Idle2;
idle_number[3] = SRayman_Idle3;
idle_number[4] = SRayman_Idle4;
idle_number[5] = SRayman_Idle5;
GML:
//STEP
if (idle_time > 0)
{
    idle_time--;
    if (idle_time <= 0) // Switch to one of the idle action animations
    {
        sprite_index = idle_number[irandom(array_length_1d(idle_number) - 1)];
        image_index = 0
    }
}

if (image_index >= image_number )
{
    // If one of the idle actions are playing, switch it back to basic idle
    if (sprite_index != SRayman_Idle)
    {
        sprite_index = SRayman_Idle;
        // How long to play the basic idle until we select the next action idle.
        // You could instead assign a random number to idle_time to make the pauses between animations
        // less predictable
        idle_time = 10 + random(6)
    }
}
Is there anyway to fix this? I've been stuck on this for a few days now!
 

Pzaan

Member
The built-in variable image_index will never be greater than or equal to the built-in variable image_number. image_index is zero-based.
 

HayManMarc

Member
So, according to Pzaan, you need to change this...
Code:
if (image_index >= image_number )
...to this...
Code:
if (image_index = image_number - 1)
 

Nidoking

Member
Use the Animation End event for this, unless you've got a very good reason not to.

And whatever you're thinking, it's almost certainly not a very good reason.
 
Top