• Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

image_index in GMS 2.3

We've just now upgraded our project to GMS 2.3, but sadly a lot of features broke for us because of a seemingly undocumented change that was made to the image_index variable. It appears that image_index is now forced to stay within the bounds of the sprite; that is, if the sprite has 4 animation frames and image_index would become greater than or equal to 4, it would automatically be changed back to 0. This makes code like this no longer function:

GML:
image_index += 0.2;
if image_index >= image_number
{
    // Do something when the animation ends
}
You're probably thinking of just using image_speed instead, but that only actually updates image_index at the end of the frame. Modifying image_index directly gives us exact control over where in the code we want to progress the animation. But since image_index can no longer be greater or equal to image_number, nearly all instances of manually altering image_index no longer function as intended.

I'm unsure if this was an intentional change by YoYo. If so, this seems like a weird and unnecessary limitation to me. It forces you to use image_speed, which gives you no control over the time that the animation is updated, and the old image_index would still draw sprites just fine if it exceeded image_number - it would internally apply this "value looping" when drawing something, but without affecting the image_index variable itself.

Does anyone know if there's a way around this, or if this is intended behaviour in the first place? Going back and changing all code structured like this is sadly not an option because of the size of our project.
 

kburkhart84

Firehammer Games
We've just now upgraded our project to GMS 2.3, but sadly a lot of features broke for us because of a seemingly undocumented change that was made to the image_index variable. It appears that image_index is now forced to stay within the bounds of the sprite; that is, if the sprite has 4 animation frames and image_index would become greater than or equal to 4, it would automatically be changed back to 0. This makes code like this no longer function:

GML:
image_index += 0.2;
if image_index >= image_number
{
    // Do something when the animation ends
}
You're probably thinking of just using image_speed instead, but that only actually updates image_index at the end of the frame. Modifying image_index directly gives us exact control over where in the code we want to progress the animation. But since image_index can no longer be greater or equal to image_number, nearly all instances of manually altering image_index no longer function as intended.

I'm unsure if this was an intentional change by YoYo. If so, this seems like a weird and unnecessary limitation to me. It forces you to use image_speed, which gives you no control over the time that the animation is updated, and the old image_index would still draw sprites just fine if it exceeded image_number - it would internally apply this "value looping" when drawing something, but without affecting the image_index variable itself.

Does anyone know if there's a way around this, or if this is intended behaviour in the first place? Going back and changing all code structured like this is sadly not an option because of the size of our project.
I'm guessing this may be an unintentional bug. I understand that sprites internally are now under the hood sequences, and this may have changed because of that. I personally wouldn't understand why you would ever want the image_index higher than the bounds of the sprite...as the variable can't designate a sprite frame for a sprite that isn't there...can't show the 5th frame of a 4 frame sprite. So maybe now they are just forcing the issue with the internal changes. It also may have something to do with how sprites can now have different speeds throughout the animation. Scroll down on this manual page and it shows you how you can stretch a single image onto various frames instead of duplicating it. I'm guessing that due to these changes, the image_index variable simply can't be used the same way as before.
 

Roldy

Member
We've just now upgraded our project to GMS 2.3, but sadly a lot of features broke for us because of a seemingly undocumented change that was made to the image_index variable. It appears that image_index is now forced to stay within the bounds of the sprite; that is, if the sprite has 4 animation frames and image_index would become greater than or equal to 4, it would automatically be changed back to 0. This makes code like this no longer function:

GML:
image_index += 0.2;
if image_index >= image_number
{
    // Do something when the animation ends
}
You're probably thinking of just using image_speed instead, but that only actually updates image_index at the end of the frame. Modifying image_index directly gives us exact control over where in the code we want to progress the animation. But since image_index can no longer be greater or equal to image_number, nearly all instances of manually altering image_index no longer function as intended.

I'm unsure if this was an intentional change by YoYo. If so, this seems like a weird and unnecessary limitation to me. It forces you to use image_speed, which gives you no control over the time that the animation is updated, and the old image_index would still draw sprites just fine if it exceeded image_number - it would internally apply this "value looping" when drawing something, but without affecting the image_index variable itself.

Does anyone know if there's a way around this, or if this is intended behaviour in the first place? Going back and changing all code structured like this is sadly not an option because of the size of our project.
You had to be careful with that even in 2.2.5. I made a post about it yesterday. How it works is undocumented, but GMS2 does attempt to roll over out of bound frame numbers in certain situations at certain times:

These comment apply to 2.2.5.. I haven't look at it in 2.3.


In general it is best to allow Animation End event to handle that for you (that is what it is there for), or set your image_speed to zero and manually advance frames yourself. But attempting both outside of the Animation End event must be done with care.
 

kburkhart84

Firehammer Games
Its funny though, because the manual page for image_index and image_number in 2.2.5 actually has an example that checks if image_index is greater than image_number - 1...so at the least going by that example it theoretically should work still. And that same example appears in the new 2.3 manual too.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Its funny though, because the manual page for image_index and image_number in 2.2.5 actually has an example that checks if image_index is greater than image_number - 1...so at the least going by that example it theoretically should work still. And that same example appears in the new 2.3 manual too.
This is (was?) correct and I am unaware of any changes to the way it does (should?) work. Please file bug reports!
 

kburkhart84

Firehammer Games
This is (was?) correct and I am unaware of any changes to the way it does (should?) work. Please file bug reports!
@Roldy seems to know more about it than I do. I've never manipulated the image_index except to check for a specific frame to do something on said frame or to stop the looping from happening.
 

Roldy

Member
Its funny though, because the manual page for image_index and image_number in 2.2.5 actually has an example that checks if image_index is greater than image_number - 1...so at the least going by that example it theoretically should work still. And that same example appears in the new 2.3 manual too.
It is a pretty easy thing to see. This is a 2.2.5 project that has a single object with a two frame animation. I set the frame rate to 13 so you can more easily see the roll over in animation end.
(DOH... can't attach .yyz file)
I put show_debug_message in various event that print the event name and image_index: e.g.



GML:
show_debug_message("End Step " + string(image_index));
The output shows clearly that image_index is advance (and rolls over) after most events in the frame but before animation end. Again this only happens when image_speed is non zero and image_index is within a certain range (-image_number, 2*image_number). It does the same for negative image_speed and going below zero. It will roll over to image_number.

If you set the image_index to 10 for example, it will no longer auto roll over because it is out of the range (-image_number, 2*image_number).

OUTPUT:

Code:
Begin Step1.93
Step 1.93
End Step 1.93
Draw 1.93
Post Draw 1.93
Draw Gui ENd 1.93
Animation End 0.15  ------ ANIMATION END ROLLOVER ------
Begin Step0.15
Step 0.15
End Step 0.15
Draw 0.15
Post Draw 0.15
Draw Gui ENd 0.15
Begin Step0.37
Step 0.37
End Step 0.37
Draw 0.37
Post Draw 0.37
Draw Gui ENd 0.37
Begin Step0.58
Step 0.58
End Step 0.58
Draw 0.58
Post Draw 0.58
Draw Gui ENd 0.58
Begin Step0.80
Step 0.80
End Step 0.80
Draw 0.80
Post Draw 0.80
Draw Gui ENd 0.80
Begin Step1.02
Step 1.02
End Step 1.02
Draw 1.02
Post Draw 1.02
Draw Gui ENd 1.02
Begin Step1.23
Step 1.23
End Step 1.23
Draw 1.23
Post Draw 1.23
Draw Gui ENd 1.23
Begin Step1.45
Step 1.45
End Step 1.45
Draw 1.45
Post Draw 1.45
Draw Gui ENd 1.45
Begin Step1.67
Step 1.67
End Step 1.67
Draw 1.67
Post Draw 1.67
Draw Gui ENd 1.67
Begin Step1.88
Step 1.88
End Step 1.88
Draw 1.88
Post Draw 1.88
Draw Gui ENd 1.88
Animation End 0.10  ------ ANIMATION END ROLLOVER ------
 
Last edited:

kburkhart84

Firehammer Games
It is a pretty easy thing to see. This is a 2.2.5 project that has a single object with a two frame animation. I set the frame rate to 13 so you can more easily see the roll over in animation end.
(DOH... can't attach .yyz file)
I put show_debug_message in various event that print the event name and image_index: e.g.



GML:
show_debug_message("End Step " + string(image_index));
The output shows clearly that image_index is advance (and rolls over) after most events in the frame but before animation end. Again this only happens when image_speed is non zero and image_index is within a certain range (-image_number, 2*image_number). It does the same for negative image_speed and going below zero. It will roll over to image_number.

If you set the image_index to 10 for example, it will no longer auto roll over because it is out of the range (-image_number, 2*image_number).

OUTPUT:

Code:
Begin Step1.93
Step 1.93
End Step 1.93
Draw 1.93
Post Draw 1.93
Draw Gui ENd 1.93
Animation End 0.15  ------ ANIMATION END ROLLOVER ------
Begin Step0.15
Step 0.15
End Step 0.15
Draw 0.15
Post Draw 0.15
Draw Gui ENd 0.15
Begin Step0.37
Step 0.37
End Step 0.37
Draw 0.37
Post Draw 0.37
Draw Gui ENd 0.37
Begin Step0.58
Step 0.58
End Step 0.58
Draw 0.58
Post Draw 0.58
Draw Gui ENd 0.58
Begin Step0.80
Step 0.80
End Step 0.80
Draw 0.80
Post Draw 0.80
Draw Gui ENd 0.80
Begin Step1.02
Step 1.02
End Step 1.02
Draw 1.02
Post Draw 1.02
Draw Gui ENd 1.02
Begin Step1.23
Step 1.23
End Step 1.23
Draw 1.23
Post Draw 1.23
Draw Gui ENd 1.23
Begin Step1.45
Step 1.45
End Step 1.45
Draw 1.45
Post Draw 1.45
Draw Gui ENd 1.45
Begin Step1.67
Step 1.67
End Step 1.67
Draw 1.67
Post Draw 1.67
Draw Gui ENd 1.67
Begin Step1.88
Step 1.88
End Step 1.88
Draw 1.88
Post Draw 1.88
Draw Gui ENd 1.88
Animation End 0.10  ------ ANIMATION END ROLLOVER ------
Indeed, this makes perfect sense to me. I'm not sure how the OP had it working before and if any of this changed with 2.3. In my case, if I wanted to manipulate the image_index to my tastes, I'd just roll my own variable and draw it manually. But I've never had a use case for that yet.
 

Roldy

Member
Indeed, this makes perfect sense to me. I'm not sure how the OP had it working before and if any of this changed with 2.3. In my case, if I wanted to manipulate the image_index to my tastes, I'd just roll my own variable and draw it manually. But I've never had a use case for that yet.
Right. I mean if it didn't do roll over for you then the user couldn't do things like:

GML:
if (image_index == 10 ) {
  // do something
}
Because once the image_index went above image_number the user would have to modulate image_index themselves to know which frame they were on.

I was going to try and use a different runtime (2.1.4) but I can't run them. It gives me Permision Denied error. But I assume it has always worked this way, because... how else would it work?
 

Roldy

Member
This is (was?) correct and I am unaware of any changes to the way it does (should?) work. Please file bug reports!
I am pretty sure it has always worked this way. But I havn't looked at 2.3. Maybe there are new events dealing with Sequences or they changed exactly WHEN roll over occurs. But I'm pretty sure it has always rolled over image_index.

EDIT: I built and ran on the oldest runtime it allows me too: 2.2.2.326 (3/25/2019) And it rolls over image_index the same as 2.2.5 does. So it has been doing that at least more than a year.
 
Last edited:

vdweller

Member
In regards to this issue: Just made a test update to see how many things have changed.

In a lot of events, mainly cutscenes in Gleaner Heights, you can find code like this:

GML:
image_index=min(image_number,image_index+0.08);.

if (image_index==image_number) { blah...}
This is a useful idiom especially in state machine code when determining the end of an animation. Apparently, in 2.5 you could overshoot the number of subimages and the engine would modulo it internally. Therefore, this code worked.
However now it seems that the expression
Code:
image_index+0.08
is %ed and then returns. As a result then condition
Code:
min(image_number,image_index+0.08);
can never be satisfied.
So if image_number is 3 and image_index is 2.95, in 2.5 we would have:
image_index+0.08 = 3.03 -> Allowed, image_index is %ed in drawing routines and wherever else is appropriate.
While in 2.3:
image_index+0.08 = 0.03 -> Messes up all code formerly relying on this check.

My question is, is this intentional or an unwanted byproduct? The former application of image_index seems more...correct to me. Would you consider this a bug or has it been documented somewhere since? (can't find it)
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
My question is, is this intentional or an unwanted byproduct? The former application of image_index seems more...correct to me. Would you consider this a bug or has it been documented somewhere since? (can't find it)
As far as I am concerned this is 100% a bug and should be fixed. This behaviour has been the standard in GM for many many years, and your project isn't the only one to break because of this change. I would recommend that EVERYONE files a bug report to let YYG know that this should be fixed (if it's not already flagged for fixing, or already fixed in the current beta, which I haven't tested):
 

gnysek

Member
So if image_number is 3 and image_index is 2.95, in 2.5 we would have:
image_index+0.08 = 3.03 -> Allowed, image_index is %ed in drawing routines and wherever else is appropriate.
While in 2.3:
image_index+0.08 = 0.03 -> Messes up all code formerly relying on this check.
I understand that:

in pre 2.3 image_index would return 2.95 (which means we're 5% away from displaying 4th frame), while in 2.3 results are closer to round(image_index) or even floor(image_index), so you can't find out where between frames we are now? Or you mean that on last frame it doesn't includes progress to first frame?
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
In pre 2.3 (and every other version of GM previously) the image_index would be allowed to overrun for one step and be modulo'd at the end of the frame... However now you can no longer check if (image_index >= image_number - 1) as it will NEVER go over or be equal, as GM now - behind the scenes - mods the return value instead of waiting till the end of the frame. This has been a valid check for decades and the change has broken more than a few projects (my own included).... I'm assuming this is related to the change to sequence based sprites, but it's still incredibly frustrating to have something that has always worked suddenly stop, and not get any notification of it.
 

vdweller

Member
As far as I am concerned this is 100% a bug and should be fixed. This behaviour has been the standard in GM for many many years, and your project isn't the only one to break because of this change. I would recommend that EVERYONE files a bug report to let YYG know that this should be fixed (if it's not already flagged for fixing, or already fixed in the current beta, which I haven't tested):
Thx a lot Noc. I'll file a bug right away. AFAIK after taking a look at Mantis it hasn't been filed yet.

BTW image_angle works like it did before, if you increment and do a debug print it will go to the thousands, and % will happen where it's needed like draw_sprite(..) routines.
 

Dan

GameMaker Staff
GameMaker Dev.
Confirmed an issue now where if your sprite has an odd number of frames then the if (image_index==image_number) { blah...} check above would not pass, due to a rounding issue. However, sprites with an even number of frames work fine.

This is in 2.3.1 and also 2.3.2 Beta 2.
 
Confirmed an issue now where if your sprite has an odd number of frames then the if (image_index==image_number) { blah...} check above would not pass, due to a rounding issue. However, sprites with an even number of frames work fine.

This is in 2.3.1 and also 2.3.2 Beta 2.
What an odd occurrence.
 

Dan

GameMaker Staff
GameMaker Dev.
Bahdumtish!

However... I later realised a second person from this thread had sent us a ticket and actually included a sample, so I was then able to confirm exactly what was going on.

There is still the odd-numbered frames issue I just mentioned, but I now suspect this might actually be a different bug already in our bug database. This bit will definitely need fixing.

But using the sample in the second ticket, I can see now that actually the issue here is as Mark says and that in 2.2.5-and-older the runner would initially return a false value larger than image_number and then on the next frame it would return the correct clamped value, whereas 2.3.0+ just returns the correct clamped value straight away. I have amended my bug report now to cover both issues, but I will have to see if we want to revert this behaviour.
 

kupo15

Member
However... I later realised a second person from this thread had sent us a ticket and actually included a sample, so I was then able to confirm exactly what was going on.
Haha I was the lazy one that just saw that everyone should file a ticket and just sent you one with just the link to here with no project file! :p Thanks for the prompt reply with all that info!
 
  • Like
Reactions: Dan

Yal

šŸ§ *penguin noises*
GMC Elder
We've just now upgraded our project to GMS 2.3, but sadly a lot of features broke for us because of a seemingly undocumented change that was made to the image_index variable. It appears that image_index is now forced to stay within the bounds of the sprite; that is, if the sprite has 4 animation frames and image_index would become greater than or equal to 4, it would automatically be changed back to 0. This makes code like this no longer function:
I thought this had been a feature since like, the GM6 days... I must've never exploited the one-frame window where it could exceed the cap. (I mostly use the Animation End event for convenience rather than manually checking image_index)

Historically, the only case where image_index can have arbitrarily huge values used to be an instance without a sprite, where the value would be incremented by image_speed indefinitely. Not sure if that changed, and it's not all that useful for features anyway... you could always just add a custom variable, increment by image_speed each step, and set image_index to it manually for full control.
 
Top