Sprite+ | An AnimationTrack-style 2d Spritesheet animator

Introduction

Hallo! This is a Sprite class for animating 2d spritesheets that mirrors the syntax for Roblox’s native Animation and AnimationTrack API.

From my past experience, animating 2d spritesheets has always been a bit of a hassle. Though there are some already-existing Sprite classes out there, the workflow wasn’t much of what I was used to. What I needed was something that was similar to Roblox’s way of animating 3D models in code.

If you’d like to animate 2d sprites and you’re already used to how Roblox handles Animations, this is the module for you!

Get Sprite+ here.

How To Use

Make sure you have your spritesheet uploaded to Roblox. Don’t upload anything over 1024x1024 pixels large as Roblox will compress the image.
Also note your spritesheet’s:

  • Number of columns
  • Number of sprites in total (SpriteCount)
  • Framerate
  • Size of an individual sprite in pixels (SpriteSize)

These are mandatory properties that you must define when creating AnimationTracks later on.

Creating a Sprite Object

Sprite+ is recommended to be used on the client as to prevent stress on the server, however it can be used either way.

First, define your sprite adornee (the surface you’d like to animate on) and create a new Sprite object.
As of now, you may only animate on ImageLabels and ImageButtons.

local Sprite = require(...) -- put your Sprite module's path here
local adornee : Sprite.AdorneeType = ... -- put your adornee's path here

local newSprite = Sprite.new(adornee)

Creating AnimationTracks

There are two ways to load animations in your game. You can either pass in an ArrayConfig with all of the properties of your spritesheet (ImageID, SpriteSize, SpriteCount, etc.)

local newAnimationTrack = newSprite:LoadAnimation({
	Spritesheet = "rbxassetid://...",
	SpriteSize 	= Vector2.new(128, 128),
	Columns 	= 5,
	SpriteCount = 20,
	Framerate 	= 12,
	Looped		= true
})

Or, you can load an animation through an InstanceConfig. In the module, there is an instance called spritetemplate, which you can pass in to load your animation.

First, define your image in the Image property of the spritetemplate. Then, in the attributes section, you can set all your spritesheet properties.

Now you can reference it in your code and pass it through LoadAnimation() to create an animation track.

local spritesheet = ... -- put spritesheet path here
local newAnimationTrack = newSprite:LoadAnimation(spritesheet)

You can now play your animation by calling :Play().

newAnimationTrack:Play() -- this should play your animation! :-)

Other Features

Priority

This class supports Priority! AnimationTracks with a higher priority will be drawn on top of AnimationTracks with lesser priority. You can set the priority like this:

local newAnimationTrack = newSprite:LoadAnimation({
	Priority = 2 -- (or whatever number you like :)
})

Design Notes

  • If two animation tracks with the same priority are playing simultaneously, the one that has a sooner starting time will be drawn first.
  • AnimationTracks with a lesser priority will still update when played.
Animation Markers

This class supports animation markers! You can assign markers to specific frames and connect when an animation has reached a specific marker using GetMarkerReachedSignal().

ArrayConfig Setup

You can define markers in an ArrayConfig like this:

self:LoadAnimation({
	Markers = {
		[1] = {
			Name = "Test",
		},

		[3] = {
			Name = "DamageEnemy",
			Parameter = 5
		}
	}
})

The marker’s corresponding frame is decided by the key. In this example I created two markers on frame one and three. Then, name the marker, and also optionally pass in an extra parameter.

InstanceConfig Setup

For an InstanceConfig, you can define markers using IntValues.

Parent an IntValue to your spritesheet, and set the value to the frame you want the marker on. The name of the IntValue is the name of your marker. You can also set a custom parameter by defining it in the Attributes section.

Example, mirroring the ArrayConfig:

GetMarkerReachedSignal()

In code, the syntax is exactly the same as Roblox’s native API.
Finishing the DamageEnemy example from earlier, we can hook it up in code like this!

newAnimationTrack:GetMarkerReachedSignal("DamageEnemy"):Connect(function(damage : number)
	enemy:TakeDamage(damage)
end)
FreezesOnEnd

This class has a unique property for spritesheets called FreezesOnEnd. When the animation ends and FreezesOnEnd is set to true, the animation will stop at the last frame and not fire the Stop event.

Keep in mind that if you’d like to get rid of the animation, you must manually call :Stop(). or :Destroy().

DebugId

You can assign DebugIds to AnimationTracks. When using an InstanceConfig, the DebugId will automatically be added as the name of the instance.

Examples

testplace.rbxl (76.3 KB)

Example Video from Test Place

Code from Test Place

(Inside workspace.Part)

------------------------- SERVICES -------------------------
local ReplicatedStorage = game:GetService("ReplicatedStorage")

------------------------- REFERENCES -------------------------
local Sprite = require(ReplicatedStorage.Modules.Sprite)

local animations = script.Animations
local spritePart = script.Parent
local adornee = spritePart.SurfaceGui:WaitForChild("Adornee")

local sprite = Sprite.new(adornee)

------------------------- MAIN CODE -------------------------
local idleAnimation = sprite:LoadAnimation(animations.idle)
idleAnimation:Play()

task.wait(5)

local hurtAnimation = sprite:LoadAnimation(animations.hurt)
hurtAnimation:Play()

hurtAnimation.Stopped:Connect(function()
	sprite:StopAllAnimations()
end)

Limitations

  • Adornees are only limited to ImageLabels and ImageButtons
  • Only one Sprite for each adornee
  • Spritesheets may not have any row or column padding.
  • Spritesheets may not have a size over 1024x1024 due to Roblox compression
  • You may not loop through only a specific part of your spritesheet

Final Notes

I don’t exactly know how performant this is, so I’d say it’s best to use Sprites sparingly. If you find any bugs or want to request a feature, feel free to report it in this topic. Thank you!

7 Likes

And by Sprite, you mean this kind of Sprite?

This is a really cool resource for other people to use for their own projects and stuff like animations for roleplaying in stories.

3 Likes

amazing module, this will be incredibly useful for me. keep up the great work! :heart:

1 Like