Advanced Sprite Handler (RoA Workshop)

Dec 17th, 2019
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!


This template handles easy animation swapping, primarily useful for alternate skins or transformations with different animations or sprites.

It stores every sprite used by the character in a variable called spr_something. This variable can be set on-the-fly to any sprite_get(), and the code in this template will make sure that the sprite gets used whenever appropriate - based on sprite, not state. For example, it will use the correct hurt sprite despite them all using the PS_HURT state, based on whichever sprite is assigned by the game engine.

Not only this, but it's also convenient to use these variables elsewhere in the code, in place of sprite_get(). For example, you can have articles set their sprite using sprite_index = player_id.spr_something;, and it will change using the system.


In init.gml, we will define the sprite variables. Paste this into your code:

useskins = false;

spr_idle = sprite_get("idle");
spr_crouch = sprite_get("crouch");
spr_walk = sprite_get("walk");
spr_walkturn = sprite_get("walkturn");
spr_dash = sprite_get("dash");
spr_dashstart = sprite_get("dashstart");
spr_dashstop = sprite_get("dashstop");
spr_dashturn = sprite_get("dashturn");

spr_jumpstart = sprite_get("jumpstart");
spr_jump = sprite_get("jump");
spr_doublejump = sprite_get("doublejump");
spr_walljump = sprite_get("walljump");
spr_pratfall = sprite_get("pratfall");
spr_land = sprite_get("land");
spr_landinglag = sprite_get("landinglag");

spr_parry = sprite_get("parry");
spr_roll_forward = sprite_get("roll_forward");
spr_roll_backward = sprite_get("roll_backward");
spr_airdodge = sprite_get("airdodge");
spr_airdodge_waveland = sprite_get("waveland");
spr_tech = sprite_get("tech");

spr_hurt = sprite_get("hurt");
spr_bighurt = sprite_get("bighurt");
spr_hurtground = sprite_get("hurtground");
spr_uphurt = sprite_get("uphurt");
spr_downhurt = sprite_get("downhurt");
spr_bouncehurt = sprite_get("bouncehurt");
spr_spinhurt = sprite_get("spinhurt");

spr_jab = sprite_get("jab");
spr_dattack = sprite_get("dattack");
spr_ftilt = sprite_get("ftilt");
spr_dtilt = sprite_get("dtilt");
spr_utilt = sprite_get("utilt");
spr_nair = sprite_get("nair");
spr_fair = sprite_get("fair");
spr_bair = sprite_get("bair");
spr_uair = sprite_get("uair");
spr_dair = sprite_get("dair");
spr_fstrong = sprite_get("fstrong");
spr_ustrong = sprite_get("ustrong");
spr_dstrong = sprite_get("dstrong");
spr_nspecial = sprite_get("nspecial");
spr_fspecial = sprite_get("fspecial");
spr_uspecial = sprite_get("uspecial");
spr_dspecial = sprite_get("dspecial");
spr_taunt = sprite_get("taunt");

spr_plat = sprite_get("plat");

These are some of the "bare minimum" sprites that a character will typically have. You can remove any that your character/costumes will not use, and you can add any that are missing. For example, add spr_nspecial_air = sprite_get("nspecial_air"); if your character uses the nspecial_air sprite and you want to be able to swap it on the fly. You should also add any non-character sprites, such as article sprites. For Trummel & Alto, I have a long list of extra sprites here for things such as the clouds.

useskins is a true/false variable which controls part of the next section's code.


In animation.gml, we will handle the automatic swapping out of the character sprites. Paste this at the bottom of the script (but above all #defines if you have any already):

if useskins{
    changeAnim(spr_idle, sprite_get("idle"));
    changeAnim(spr_crouch, sprite_get("crouch"));
    changeAnim(spr_walk, sprite_get("walk"));
    changeAnim(spr_walkturn, sprite_get("walkturn"));
    changeAnim(spr_dash, sprite_get("dash"));
    changeAnim(spr_dashstart, sprite_get("dashstart"));
    changeAnim(spr_dashstop, sprite_get("dashstop"));
    changeAnim(spr_dashturn, sprite_get("dashturn"));

    changeAnim(spr_jumpstart, sprite_get("jumpstart"));
    changeAnim(spr_jump, sprite_get("jump"));
    changeAnim(spr_doublejump, sprite_get("doublejump"));
    changeAnim(spr_walljump, sprite_get("walljump"));
    changeAnim(spr_pratfall, sprite_get("pratfall"));
    changeAnim(spr_land, sprite_get("land"));
    changeAnim(spr_landinglag, sprite_get("landinglag"));

    changeAnim(spr_parry, sprite_get("parry"));
    changeAnim(spr_roll_forward, sprite_get("roll_forward"));
    changeAnim(spr_roll_backward, sprite_get("roll_backward"));
    changeAnim(spr_airdodge, sprite_get("airdodge"));
    changeAnim(spr_airdodge_waveland, sprite_get("waveland"));
    changeAnim(spr_tech, sprite_get("tech"));

    changeAnim(spr_hurt, sprite_get("hurt"));
    changeAnim(spr_bighurt, sprite_get("bighurt"));
    changeAnim(spr_hurtground, sprite_get("hurtground"));
    changeAnim(spr_uphurt, sprite_get("uphurt"));
    changeAnim(spr_downhurt, sprite_get("downhurt"));
    changeAnim(spr_bouncehurt, sprite_get("bouncehurt"));
    changeAnim(spr_spinhurt, sprite_get("spinhurt"));

    changeAnim(spr_jab, sprite_get("jab"));
    changeAnim(spr_dattack, sprite_get("dattack"));
    changeAnim(spr_ftilt, sprite_get("ftilt"));
    changeAnim(spr_dtilt, sprite_get("dtilt"));
    changeAnim(spr_utilt, sprite_get("utilt"));
    changeAnim(spr_nair, sprite_get("nair"));
    changeAnim(spr_fair, sprite_get("fair"));
    changeAnim(spr_bair, sprite_get("bair"));
    changeAnim(spr_uair, sprite_get("uair"));
    changeAnim(spr_dair, sprite_get("dair"));
    changeAnim(spr_fstrong, sprite_get("fstrong"));
    changeAnim(spr_ustrong, sprite_get("ustrong"));
    changeAnim(spr_dstrong, sprite_get("dstrong"));
    changeAnim(spr_nspecial, sprite_get("nspecial"));
    changeAnim(spr_fspecial, sprite_get("fspecial"));
    changeAnim(spr_uspecial, sprite_get("uspecial"));
    changeAnim(spr_dspecial, sprite_get("dspecial"));
    changeAnim(spr_taunt, sprite_get("taunt"));

//Handle certain looping animations
if (sprite_index == spr_idle){
    var frames = 6;
    var frame_dur = 8;
    image_index = floor((state_timer mod (frames * frame_dur)) / frame_dur);
if (sprite_index == spr_walk){
    var frames = 6;
    var frame_dur = 8;
    image_index = floor((state_timer mod (frames * frame_dur)) / frame_dur);
if (sprite_index == spr_dash){
    var frames = 6;
    var frame_dur = 4;
    image_index = floor((state_timer mod (frames * frame_dur)) / frame_dur);

#define changeAnim

var old_spr = argument[1];
var new_spr = argument[0];

if (sprite_index == old_spr && old_spr != new_spr){
    sprite_index = new_spr;

changeAnim() is a function which takes its second argument, checks if the character is using that sprite, and if so, switches the sprite to the first argument. For example, if the character is currently using the regular idle_stripX sprite, the animation handler will switch it over to whichever sprite is stored in spr_idle. This is how the system manages to cope with things such as the various hurt sprites - it checks directly for which sprite has been assigned by the game engine, not just which state the character is in.

By running changeAnim() for each character animation, we handle all of these sprite changes when needed. As before, you should add any missing sprites, and you MUST remove anything that you removed from the init.gml section. Keep in mind that, since this is only used by the character itself, you do not need to add sprites that are to be used by articles and the like. If useskins is false, this chunk of code will not run, just to maximize performance.

Lastly, the middle section is to handle certain animations which would normally be handled by the game via idle_anim_speed and so on... but break if it's not using the file named idle_stripX.png etc. If you exclude this bit of code and replace the idle/walk/dash sprites using this system, the animation won't work. For each of these blocks of code, frames is the number of frames in the sprite, while frame_dur is the amount of time each frame should last. Incidentally, you can use this same bit of code to give a looping animation to any other sprites that need it, such as pratfall (which I did for Trummel & Alto).


Now that this has been added to your character, let's make it actually useful. (It doesn't accomplish much on its own, especially because useskins is false by default; luckily, the below examples set it to true when necessary)

Here's a script to change things based on the player's alternate costume, placed immediately after the init.gml code found above:

    case 6: //Skin Slot 7
        spr_idle = sprite_get("my_cool_costume_idle");
        spr_taunt = sprite_get("my_cool_costume_taunt");
        useskins = true;
    case 7: //Skin Slot 8
        spr_idle = sprite_get("my_cooler_costume_idle");
        spr_taunt = sprite_get("my_cooler_costume_taunt");
        useskins = true;

These extra sprites should be stored in the sprites folder with all the others.

To change sprites on the fly rather than via costume, simply put spr_idle = sprite_get("my_second_idle"); anywhere in your character's code. To change back to default, put spr_idle = sprite_get("idle"); (and so on for other sprites). For example:

if character_is_transformed{
    spr_idle = sprite_get("transformed_idle");
    spr_taunt = sprite_get("transformed_taunt");
    useskins = true;
    spr_idle = sprite_get("idle");
    spr_taunt = sprite_get("taunt");
    useskins = false;

To reference the sprites for use outside of character animations, simply use the spr_something instead of sprite_get(). For example, use draw_sprite(spr_my_cool_hud_element, 0, x, y);. For articles and projectiles, remember to use player_id.spr_something.

One last, important step: add all new alt. sprites to load.gml and set their offsets accordingly!

Known Engine Quirks

I will add to the list below as I find additional caveats to this system.

The animation for the jump and doublejump sprites is based on the frame count of jump_stripX.png and doublejump_stripX.png. This means that, for the animation to play correctly, the frame count of these animations should stay the same for each alternate version of the sprites. (e.g. jump_strip9.png, doublejump_strip3.png, costume_jump_strip9.png, costume_doublejump_strip3.png)

RAW Paste Data