GameMaker: Image Index In-Depth

In GameMaker, sprite resources are bound to an object via the sprite_index variable on the object. Once a sprite is set (either by assigning it to the variable or selecting it in the object editor), you can access the more fine-grained details of the sprite using the image_ variables. There are a good handful of them, but today I want to focus on two important image variables: image_index and image_speed.

image_index

The image index is the 0-indexed number of the sub image in the sprite that is currently displayed. This is the most basic way to animate sprites in GameMaker: have a sprite with multiple sub-images that plays like a .gif file. The image_index variable can be read to see which image in your sprite is currently being displayed, or set to a real to set which sub image to display.

image_speed

The image speed is how fast your sprite's animation plays. It defaults to 1, which means your sprite will animate 1 frame per step of your game. If your room is set to 60 steps / second, your sprite will animate at 60 frames per second.

You can set the image_speed variable to a decimal to slow this down. For example, if you set it to 0.5, your animation will play at 50% of the room's speed. 0.25 for a quarter of the speed, and so on. Now, here is where I got messed up recently.

How they actually work

The short of it is that every step of your game, image_speed gets added to image_index, and the sub image that displays from your sprite resource is the floor of the value of image_index. When image_speed is 1, that means that image_index will always be a whole number. However, in my project, I frequently use smaller values in image_speed, which means there are steps where my image_index can be some random value, like 2.36.

This messed me up when I had logic in a step event of an object to perform an action when the image index is a certain value. I wanted the 5th frame of my animation to cause an action to happen, so I had this simple code:

if (image_index == 4) {  
  // Do something
}

Surprisingly, this worked fine until I compiled my game with YYC, which actually caused this conditional to get skipped right over. It wasn't until I put a show_debug_message in my step event to log the image_index every step to see what is going on. I saw a bunch of logs of increasing floating point numbers, but no integers to be found. Sure, GameMaker doesn't differentiate between the two, but I was comparing 4.02 to 4, which is flat out false.

Luckily, it's an easy fix:

if (floor(image_index) == 4) {  
  // Do something
}

In short, floor your image_index if you're ever reading it, because you probably don't think in terms of percentages of frames.