GameMaker Spritesheet Guide: Importing, Slicing, and Animating Sprites in GMS2
What Makes GameMaker Spritesheet Handling Unique
GameMaker Studio 2 treats sprites differently from most other 2D engines. Rather than importing a spritesheet and defining animation clips externally, GameMaker bakes animation frames directly into the sprite resource itself. When you create a sprite in GMS2, you are creating a self-contained animation asset — the frame data, origin point, collision mask, and playback speed are all part of the sprite definition. This tight integration makes basic animations trivially easy to set up, but it also means you need to understand how GameMaker thinks about sprites to get the most out of your spritesheets.
In Unity or Godot, you might import a spritesheet as a texture, slice it into individual sprites, then assemble those sprites into an animation timeline. In GameMaker, the import process handles slicing and frame ordering in one step. You end up with a sprite resource that already knows how to animate itself. The engine handles playback automatically through built-in variables like image_speed and image_index, which means you can get a character walking on screen in minutes rather than hours.
This approach works beautifully for small to medium projects. Where it gets interesting is when you need state-based animation (idle, walk, attack, jump), performance optimization for mobile, or precise frame control for game-feel-critical moments like attack windups. That is what this guide covers.
Importing a Spritesheet into GameMaker Studio 2
To import a spritesheet, open the Sprite Editor by creating a new sprite resource or double-clicking an existing one. Click the Import button in the top toolbar, then select Import Strip Image. This opens the strip image import dialog where you tell GameMaker how your spritesheet is organized.
GameMaker needs to know three things: how many frames are in the strip, how many columns the sheet has, and how many rows. If your spritesheet is a single horizontal row of 8 frames, you would set Number of Frames to 8, Frames per Row to 8, and Frame Height and Frame Width to match your sprite dimensions. For a 4x2 grid containing 8 frames, set Frames per Row to 4. GameMaker reads frames left to right, top to bottom.
After importing, check that your frames look correct in the preview strip at the bottom of the Sprite Editor. If frames appear offset or cropped, your width and height values do not match the actual cell size. A common mistake is forgetting to account for padding between frames — if your spritesheet has 1-pixel gaps between cells, you need to include that padding in the Frame Horizontal Separation and Frame Vertical Separation fields.
Set the origin point before closing the editor. The origin determines the point around which the sprite rotates and the position your object draws from. For character sprites, the bottom center is the most practical origin — it means your character's feet align with the floor regardless of frame size variations. Click the origin dropdown and select Bottom Center, or manually place it by clicking on the sprite preview.
Setting Frame Speed and Playback in GML
GameMaker provides several built-in variables for controlling animation playback. The most important are image_speed, image_index, and sprite_index. Understanding how these interact is essential for any project with more than one animation.
The image_speed variable controls how fast frames advance. A value of 1 plays the animation at the speed defined in the Sprite Editor. A value of 0.5 plays at half speed. Setting image_speed to 0 freezes the animation on the current frame, which is useful for holding a specific pose. You can set the default playback speed in the Sprite Editor using either frames per second or frames per game frame.
// Set animation to play at 10 frames per second
sprite_set_speed(spr_player_walk, 10, spritespeed_framespersecond);
// Or control speed per-instance
image_speed = 1; // Normal speed
image_speed = 0.5; // Half speed
image_speed = 0; // Frozen on current frameThe image_index variable holds the current frame number as a real number (not an integer). Frame 0 is the first frame. You can set image_index directly to jump to a specific frame. This is invaluable for attack animations where you need frame-precise timing — for example, spawning a hitbox exactly on frame 4 of a slash animation.
// Jump to a specific frame
image_index = 0; // Reset to first frame
// Check current frame for gameplay logic
if (floor(image_index) == 4) {
// Spawn hitbox on frame 4 of attack
instance_create_layer(x + 32, y, "Instances", obj_hitbox);
}Use sprite_set_speed to define the default playback rate for a sprite resource. This sets it globally — every instance using that sprite will inherit the speed unless overridden with image_speed. For most projects, set your sprite speeds in a controller object's Create event or in a script that runs once at game start.
Creating State-Based Animation in GameMaker
Real games rarely have characters that play a single animation forever. You need state-based animation: playing different sprites depending on whether the character is idle, walking, jumping, attacking, or taking damage. In GameMaker, you handle this by swapping sprite_index in the Step event.
The simplest approach uses if-else blocks to check movement state and assign the corresponding sprite. This works well for characters with three or four states. The key detail most beginners miss is resetting image_index when changing sprites — without this, GameMaker tries to continue from the same frame number, which can cause visual glitches if your animations have different frame counts.
// Step Event — basic state-based animation
var _moving = (abs(hspeed) > 0.1) || (abs(vspeed) > 0.1);
var _new_sprite = _moving ? spr_player_walk : spr_player_idle;
// Only reset animation if sprite actually changed
if (sprite_index != _new_sprite) {
sprite_index = _new_sprite;
image_index = 0;
}
// Flip sprite based on direction
if (hspeed > 0) image_xscale = 1;
if (hspeed < 0) image_xscale = -1;For more complex characters, use a state variable with a switch block. This scales better when you add attack combos, wall sliding, dashing, or other states that have specific entry and exit conditions. Each state controls which sprite plays and can define its own transition rules.
// Step Event — state machine approach
switch (state) {
case PLAYER_STATE.IDLE:
sprite_index = spr_player_idle;
if (_moving) state = PLAYER_STATE.WALK;
if (key_attack) {
state = PLAYER_STATE.ATTACK;
image_index = 0;
}
break;
case PLAYER_STATE.WALK:
sprite_index = spr_player_walk;
if (!_moving) state = PLAYER_STATE.IDLE;
break;
case PLAYER_STATE.ATTACK:
sprite_index = spr_player_attack;
// Return to idle when animation finishes
if (floor(image_index) >= sprite_get_number(sprite_index) - 1) {
state = PLAYER_STATE.IDLE;
}
break;
}Notice the attack state checks whether the animation has reached its last frame using sprite_get_number. This is the standard pattern for one-shot animations in GameMaker — let them play through, then transition back to idle or the next state.
Texture Groups and Performance Optimization
When GameMaker compiles your game, it packs all sprite frames onto texture pages — large images (typically 2048x2048 pixels) that the GPU loads into memory. Every time the engine needs to render a sprite from a different texture page, it triggers a texture swap. These swaps are expensive and can tank your frame rate on mobile devices if you have sprites scattered across many pages.
Texture Groups let you control which sprites share a texture page. Open the Texture Group Editor from the Resources menu and create groups based on when sprites are used together. A common setup for a platformer: one group for the player character (all states), one group for level 1 enemies and tiles, another for level 2, and so on. The principle is that sprites drawn in the same room at the same time should share a texture page whenever possible.
To assign a sprite to a texture group, select the sprite resource and change the Texture Group dropdown in the Sprite Editor. You can also assign entire folders at once in the Texture Group Editor, which is much faster for large projects.
Keep an eye on your draw call count using the debug overlay (press F1 in a debug build or use show_debug_overlay(true) in code). If your game runs at 60 FPS on desktop but drops to 30 on mobile, draw calls from texture swaps are the most likely culprit. Consolidating sprites into shared texture groups can cut draw calls by 50% or more.
Pixel Art Spritesheets in GameMaker
Pixel art requires specific settings in GameMaker to avoid the blurry, smeared look that ruins crisp pixelated graphics. The most critical setting is disabling texture interpolation. Go to Game Options, select the platform you are targeting, and make sure Interpolate Colours Between Pixels is unchecked. You can also disable it in code with gpu_set_texfilter(false).
For pixel-perfect rendering, your view and viewport setup matters enormously. If your sprites are drawn at 16x16 pixels, your view should be a clean multiple of your native resolution. A 320x180 native resolution scaled to 1920x1080 (6x) gives you sharp pixels with no subpixel rendering artifacts. Set your camera and viewport in the Room Editor, and make sure the application surface scales to whole-number multiples.
Another common pitfall is sprite origins at non-integer positions. If your origin is at (7.5, 15), GameMaker will try to draw the sprite at a sub-pixel position, causing visible shimmer during movement. Always use integer coordinates for origins. Similarly, use round(x) and round(y) in your Draw event if your character moves at non-integer speeds — this prevents the pixel grid from shifting frame to frame.
Collision masks for pixel art sprites should use precise per-frame masks only if your gameplay requires it. For most games, a simple rectangular or elliptical mask is faster and produces more predictable collision behavior. Set your collision mask in the Sprite Editor and test it with draw_sprite_ext to visualize the bounding box.
Using AI to Generate GameMaker-Ready Spritesheets
Creating multiple animation states for even a single character is time-intensive. A typical platformer character needs idle, walk, run, jump, fall, attack, hurt, and death animations — that can easily total 60 or more individual frames. For solo developers or small teams, this art workload can stall a project for weeks.
AI spritesheet generators like Spritesheets.AI dramatically compress this timeline. The workflow is straightforward: upload a reference image of your character, describe the animation you need (for example, 8-frame walk cycle, side view), and the AI generates a complete spritesheet with consistent style across every frame. You can go from concept to a full set of animation spritesheets in under an hour instead of days.
The output is a standard strip or grid PNG with transparent background — exactly the format GameMaker expects for strip import. Download the spritesheet, import it using the process described above, set your frame dimensions, and your character is animating in-engine. If any frames need cleanup, touch them up in Aseprite or Piskel before importing.
For GameMaker projects specifically, Spritesheets.AI lets you specify frame count and dimensions that match GameMaker's standard texture page sizes. This means less wasted space on your texture pages and fewer draw calls. If you are building a GameMaker game and want to generate spritesheets that import cleanly without resizing or reprocessing, try the GameMaker-optimized workflow on our spritesheet generator.