GameMaker Studio sprite editor showing pixel art character with origin point and collision mask

GameMaker sprites: importing, animating, and getting pixel-perfect results

How to import sprites into GameMaker, set up animations with GML, configure collision masks, and avoid the mistakes that waste hours of debugging.

GameMaker makes sprites easy — until it doesn't

Getting a sprite into GameMaker takes about five seconds. Drag a PNG into the IDE, done. But then your character floats two pixels above the ground. Or collisions feel wrong. Or your walk cycle plays at the wrong speed and you can't figure out why.

The import is trivial. Everything after the import is where people lose hours.

This guide covers the full workflow for GameMaker sprites — from getting your art into the engine to writing GML that actually handles animation properly. Whether you're working with sprites you drew in Aseprite, generated with AI, or ripped from a sprite sheet, the process is the same.


Importing sprites into GameMaker

You've got three ways to get sprites in.

Drag and drop

Literally drag a PNG from your file explorer into the GameMaker Asset Browser. That's it. GameMaker creates a sprite resource with one sub-image. Works for static sprites — items, UI elements, single-frame objects.

Import strip image

This is what you'll use for animations. Go to the Sprite Editor, click Image > Import Strip Image, and select your sprite strip. GameMaker asks for the number of frames, frame width, frame height, and how many frames per row.

Thing is, GameMaker's strip import expects a horizontal strip by default. If your sprite sheet is arranged in a grid (multiple rows), you'll need to set "frames per row" correctly or you'll get garbled frames. A 4x3 grid with 32x32 frames means: frame width 32, frame height 32, number of frames 12, frames per row 4.

Add individual frames

Open a sprite resource, click Edit Image, then Image > Import on each sub-image. Tedious for animations but useful when you need to add one or two frames to an existing sprite.

MethodBest forAnimation support
Drag and dropSingle sprites, quick prototypingNo (one frame)
Import StripSprite sheets, walk cycles, effectsYes (auto-sliced)
Add frames manuallyFixing existing animationsYes (manual)

The sprite editor: what actually matters

GameMaker's Sprite Editor packs a lot of panels into one window. Most of them you'll never touch. Here's what matters.

Origin point

The origin is the "anchor" of your sprite — the point that sits at the object's x,y position in the room. This one setting causes more frustration than anything else in GameMaker sprite work.

Top-left origin (default): Your object's x,y is the top-left corner of the sprite. Fine for tiles and UI. Terrible for characters, because "move to x=100" puts the character's feet somewhere weird.

Center origin: x,y sits at the sprite's center. Better for projectiles and effects.

Bottom-center origin: The sweet spot for characters. x,y sits at the character's feet. When you place them on a platform, they stand on it correctly. When you change sprite sizes mid-animation, they don't float or sink.

Set origin in the Sprite Editor toolbar — there's a dropdown with presets, or click directly on the sprite preview to place it manually.

// If you need to change origin in code (rare, but useful for debugging)
sprite_set_offset(spr_player_walk, sprite_get_width(spr_player_walk) / 2, sprite_get_height(spr_player_walk));

My honest recommendation: use bottom-center for every character and enemy sprite. Just do it. You'll save yourself from a dozen alignment bugs down the road.

Sub-images

Sub-images are your animation frames. Frame 0 is the first, frame 1 is the second, and so on. GameMaker cycles through these automatically when the object draws.

You can see all sub-images as thumbnails at the top of the Sprite Editor. Click any frame to edit it directly. Right-click for options like duplicate, delete, or insert.

Collision mask

This is the invisible shape GameMaker uses for collision detection. It's independent of what the sprite looks like visually, and choosing the wrong type will make your game feel broken.


Collision masks: picking the right one

GameMaker gives you four collision mask modes. Most tutorials gloss over this. Don't.

Automatic — GameMaker traces the non-transparent pixels and creates a tight mask. Sounds great, changes per frame. This means your collision shape shifts as the animation plays. A sword swing frame suddenly has a wider collision than an idle frame. Avoid this for characters.

Full image — The entire bounding rectangle is the collision. Simple but sloppy. Your character's collision box includes all the transparent space around them.

Manual — You define a rectangle yourself. This is what you want for most game objects. Set it once, it stays consistent across all frames. A character's collision box shouldn't change when they swing a sword.

Precise — Per-pixel collision checking. Expensive and almost never necessary for pixel art games. The only real use case is irregularly shaped static objects where rectangle collision looks obviously wrong.

Mask typePerformanceBest forAvoid for
AutomaticMediumRarely usefulCharacters, moving objects
Full imageFastQuick prototypingAnything with transparency padding
Manual rectangleFastCharacters, enemies, projectilesNothing — this is the default choice
Precise (per-pixel)SlowIrregular static terrainMoving objects, large sprites

For platformers and action games, set your character's collision mask to Manual, then draw a rectangle slightly smaller than the visual sprite. Players won't notice the mask is smaller, but they will notice when they get stuck on a ledge because their hat clipped the ceiling. Forgiving collision boxes feel better.


Animation setup in GML

GameMaker handles sprite animation automatically — it cycles through sub-images each step. But the defaults are rarely what you want.

image_speed

Controls how fast animation plays. A value of 1 means one frame per game step. At 60fps, a 6-frame walk cycle finishes in 0.1 seconds. Way too fast.

// Create Event
image_speed = 0.15;  // ~9 frames per second at 60fps room speed

Lower values = slower animation. This is a multiplier, not frames-per-second, which trips people up.

// Common speeds for different animations
image_speed = 0.1;   // Idle breathing — slow, subtle
image_speed = 0.2;   // Walking — moderate pace
image_speed = 0.3;   // Running — noticeably quicker
image_speed = 0.5;   // Attack — fast, snappy

image_index

The current frame number. GameMaker auto-increments this, but you can set it manually for precise control.

// Reset to first frame (useful when switching animations)
image_index = 0;

// Jump to specific frame
image_index = 3;

// Check what frame we're on
if (image_index >= sprite_get_number(sprite_index) - 1) {
    // Last frame reached — do something
}

sprite_index

Which sprite resource is currently assigned. Changing this is how you switch between animations.

// Step Event — switch sprites based on state
if (is_attacking) {
    sprite_index = spr_player_attack;
} else if (abs(hspeed) > 0) {
    sprite_index = spr_player_walk;
} else {
    sprite_index = spr_player_idle;
}

Putting it together

Here's a pattern that handles animation state properly. Most beginner code just sets sprite_index every frame without checking if it changed — which resets image_index and causes flickering.

// Step Event — proper animation switching
var _target_sprite = spr_player_idle;
var _target_speed = 0.1;

if (is_attacking) {
    _target_sprite = spr_player_attack;
    _target_speed = 0.4;
} else if (abs(hspeed) > 1) {
    _target_sprite = spr_player_run;
    _target_speed = 0.25;
} else if (abs(hspeed) > 0) {
    _target_sprite = spr_player_walk;
    _target_speed = 0.2;
}

// Only change sprite if it's different — prevents animation reset
if (sprite_index != _target_sprite) {
    sprite_index = _target_sprite;
    image_index = 0;  // Start new animation from frame 0
}

image_speed = _target_speed;

This avoids the single most common GameMaker animation bug: the sprite flickering because you're reassigning sprite_index every frame.


Pixel-perfect rendering settings

GameMaker sprites will look blurry by default in certain situations. Here's how to fix that.

Texture filtering

Go to Game Options > [Platform] > Graphics and make sure texture filtering is off (or set to "Point" filtering). Linear filtering smooths pixels — the opposite of what you want for pixel art.

You can also set this per-draw in GML:

// Draw Event — force nearest-neighbor for this sprite
gpu_set_texfilter(false);
draw_self();

Integer scaling

In your Room settings, make sure your viewport scales by whole numbers. A 320x180 game view scaled to 1280x720 is 4x — clean, crisp pixels. Scaled to 1366x768? That's 4.26x. Fractional scaling means some pixels are 4px wide and others are 5px. Looks terrible.

// In a camera/view setup script
var _scale = floor(display_get_width() / view_w);
surface_resize(application_surface, view_w * _scale, view_h * _scale);

Application surface

GameMaker draws everything to the application surface, then scales it to the window. If this surface doesn't match your pixel resolution, you'll get subpixel rendering artifacts.

// Room creation code
application_surface_draw_enable(false);

// Draw GUI Event (ensures clean scaling)
var _scale = floor(min(
    display_get_width() / camera_get_view_width(view_camera[0]),
    display_get_height() / camera_get_view_height(view_camera[0])
));
var _sw = camera_get_view_width(view_camera[0]) * _scale;
var _sh = camera_get_view_height(view_camera[0]) * _scale;
var _sx = (display_get_width() - _sw) / 2;
var _sy = (display_get_height() - _sh) / 2;

draw_surface_ext(application_surface, _sx, _sy, _scale, _scale, 0, c_white, 1);

That's more code than most tutorials show. But skipping it is why so many GameMaker pixel art games have inconsistent pixel sizes.


Sprite strips vs individual frames

Should you import one strip or separate PNGs for each frame?

Strips win almost every time. One file per animation. Easier to manage, easier to version control, fewer assets cluttering your project. GameMaker's strip import handles the slicing for you.

Individual frames make sense when you're iterating on specific frames during development — tweaking frame 3 of a walk cycle without re-exporting the whole strip. But once you're past prototyping, combine them.

If you're generating sprites with AI, you'll typically get individual frames. Generate your character poses, tweak them in the pixel editor, then arrange them into a strip using any image editor or sprite sheet tool before importing to GameMaker.


Exporting from Sprite AI for GameMaker

Quick workflow for getting AI-generated sprites into GameMaker.

  1. Generate your sprite at your target resolution (32x32 or 64x64 work well for GameMaker)
  2. Edit in the pixel editor if needed — fix colors, clean up edges
  3. Export as PNG with transparent background
  4. For animations, generate each pose separately with consistent prompting
  5. Combine frames into a horizontal strip (any image editor works)
  6. In GameMaker: Sprite > Import Strip Image and set your frame dimensions

GameMaker doesn't care where your sprites come from. AI-generated, hand-drawn, converted from photos — it's all PNGs in the end. The import process is identical. For more detail on export options, the sprite export formats guide covers PNG settings and transparency.


Common mistakes (and fixes)

These are the problems I see constantly in GameMaker pixel art projects.

Wrong origin point across animation sprites. You have spr_player_idle with bottom-center origin and spr_player_walk with top-left. When the sprite switches, the character teleports. Fix: set the same origin point on every sprite for that object. Every single one.

Forgetting to set image_speed. The default is 1, which means one full frame per step. At 60fps, your 8-frame walk cycle completes in 0.13 seconds. Nobody can even see the frames. Always set image_speed in the Create Event.

Using automatic collision masks. Your character's collision changes shape every frame. Suddenly they can walk through walls during frame 4 of the attack animation because the mask shrunk. Use manual rectangle masks.

Blurry sprites. Texture filtering is on. Turn it off. Check Game Options, check your draw code, check everything. One wrong setting and your crisp pixel art turns to mush.

Sprite flickering. You're setting sprite_index every frame in the Step Event, which resets image_index to 0 every frame. Check if the sprite actually changed before reassigning it (see the GML pattern above).

Non-integer scaling. Your game view is 320x180 but your window is 1366x768. That's not an even multiple. Some pixel rows will be thicker than others. Use floor() to calculate the largest integer scale that fits.


Quick reference: GML sprite functions

// Get sprite info
sprite_get_width(sprite)       // Width in pixels
sprite_get_height(sprite)      // Height in pixels
sprite_get_number(sprite)      // Number of sub-images (frames)
sprite_get_xoffset(sprite)     // Origin X
sprite_get_yoffset(sprite)     // Origin Y

// Drawing
draw_self()                    // Draw current sprite at x,y
draw_sprite(sprite, subimg, x, y)        // Draw specific sprite/frame
draw_sprite_ext(sprite, subimg, x, y,    // Draw with transforms
    xscale, yscale, rot, colour, alpha)

// Animation control
image_speed = 0.2;             // Animation speed multiplier
image_index = 0;               // Current frame (set or read)
sprite_index = spr_something;  // Change sprite resource

// Flipping
image_xscale = -1;             // Mirror horizontally (face left)
image_xscale = 1;              // Normal (face right)

Where to go from here

You've got sprites in GameMaker, animations running, collisions working, and pixels looking crisp. That covers about 90% of what most projects need.

For deeper dives:

Or just generate some sprites and start building. GameMaker's whole philosophy is about getting things running fast. Don't let setup perfectionism slow you down — get something on screen, then iterate.

We use cookies to enhance your experience. Essential cookies are required for the site to function. You can choose to accept all cookies or only essential ones.

Learn more