Animation Tips and Tricks
On this page you will find a bunch of different tips & tricks that you can apply to animations that you have imported into the animation frame sequencer; some of these tips & tricks might be applicable to Spine sprite part animation models & 3D character models.
The whole point in this page is give you ideas on how you can optimize your animations & your game overall by reducing the amount of animation frames needed to create smooth looking animations.
Anyway, let's crack on...
What is the Animation Frame Sequencer?
I'm just going to assume that most of you already know what it is, but just in case you don't, it's the animation form you can find around various sections of the Visionaire Studio editor that let's you import or batch import animation frame images into the engine. By default you can control the global duration of the frames, the duration of individual frames, the playback mode of the frames, & the amount of loops the animation should perform - however, we can get a lot more creative with what's possible via action parts, scripting, & some clever edits to the duration of individual frames.
Getting Started
Now before I go over the various animation tips & tricks, we need to setup a few things first that we will need further down the road for some of the methods listed below. This involves a bit of scripting, but don't worry it's nothing complicated. I just need you to navigate to the script section of the Visionaire Studio editor, create a new definition type script, rename it to workflow_functions, & then paste the code below into it.
math.randomseed( os.time() ) -- init math.random (make sure math.random is actually random each session)
math.random(); math.random(); math.random() -- shake things up a bit & make sure it is actually random
-- * function used to force animation frame range; i.e: frame 2 to 4 or frame 1 to 1, etc. * --
function setAnimFrames(anim, f, t) -- syntax: setAnimFrames(animation name, from, to)
t = t or f -- fallback in case t equals nil
if f > t then f = t end -- fallback in case f is greater than t
ActiveAnimations[anim].FirstFrame = f -- update from animation frame range
ActiveAnimations[anim].LastFrame = t -- update to animation frame range
end
Quick note: Not everything on this animation tips & tricks wiki page contains in-depth step by step guides. To be honest some of the methods are complicated & are very difficult to explain in small steps in layman terms that everyone should be able to understand & thus are just short summaries containing images or diagrams. However, I have created & shared a ved project file in the resources section that contains working examples of almost everything I have mentioned on this page. |
Individual Frame Duration
By default animations will automatically use the global pause (duration) value specified in the properties section for the animation, however you can enable the option set pause for each frame, which will allow you to specify a unique duration value for each animation frame. Only frames that have a value other than -1 will be affected by this option. All frames that contain a value of -1 will use the global pause (duration) value.
Using this option lets you create dynamic looking animations where you can give your animations the appearance that they have some weight behind them. It's also a useful method for reducing the amount of animation frames you need to use for an animation, for example... let's say that you want a specific frame to play 3 times in a row, well in other programs you might need to import the same image 3 times to do that, but in Visionaire you can just adjust the duration of that specific animation to last 3x the global pause (duration) value.
Dynamic Frame Duration
This next tip is a bit of a tricky one, but it's one of my favorite methods for turn borning repetitive animations into animations that feel & look more natural by applying a dynamically generated duration value between specific animation frames - it also works a treat for adding a dynamic delay between animation loops.
1. Select the animation frame you want to apply a dynamic duration to. Edit the animation frame via & open up the action modal box via .
2. Inside of the action modal box create a new action via & then create a new execute a script action part & add something along the lines of this into it...
Animations["example"].Pause = math.random(1000, 3000) -- set dynamic duration of frame between 1 & 3 seconds
3. Close the action modal box & the animation frame editor modal box & then select the animation to the right of the one you have just edited & repeat the same steps, except in the execute a script action part you want to reset the pause value back to whatever the global pause (duration) value is that you specified inside of the properties for the animation, which should look like something along the lines of this...
Animations["example"].Pause = 40 -- change frame duration back to global pause (duration) value
& that's it. You can use this method on multiple animation frames or even specific ranges of animation frames. Have fun experimenting with dynamic frame durations & don't be afraid to get creative.
Animation Frame Range
With a little bit of scripting magic we can force the engine to loop the animation between a specific range of animation frames or even loop a single frame. This can be useful for controling states, such as: door closed vs door open, etc. though you can alternatively do this via multiple scene objects & linking a condition or value to them to determine which object should be active/visible.
Quick note #1: This method will only work on animations that are set to loop infinitely, because non-looping & limited-loop animations are hidden after they have finished their specified loop amount. |
Quick note #2: We will be using the setAnimFrames() function that I shared with you earlier in Getting Started. |
Quick note #3: Animations have to be already playing/active for this method to work. |
To loop a single frame you can do something along the lines of this...
setAnimFrames("example", 1) -- loop the 1st frame in the animation "example"
Or to loop a specific range of animation frames you can do something along the lines of this...
setAnimFrames("example", 2, 4) -- loop between the 2nd & 4th animation frame in the animation "example"
& just to show you how it can be done without the setAnimFrames() workflow function...
-- loop the 1st frame belonging to the animation "example"
ActiveAnimations["example"].FirstFrame = 1
ActiveAnimations["example"].LastFrame = 1
Animation Playback Order
Animations can be played forwards, backwards, or the animation frames can be played in a random order. Taking that into consideration it's possible to create pendulum animations that play in one direction then reverse back in the other direction, however we will be saving that for the next section of this tips & tricks guide.
You can specify the default playback direction/order inside of the animation properties. Forwards will play the animation in the order it was created in. Backwards will play the animation from the last frame back to the first frame. Random will play the animation frames in a random order, which can be really useful for creating dynamic looking animations or for mixing up talk animations so they are less boring to look at if you aren't planning on adding lip sync to your game.
You can change the playback direction of any active/playing animation during runtime with a line of code that looks like something along the lines of this...
ActiveAnimations["example"].PlayOppositeDirection = true -- true = inverse direction; false = default direction
Pendulum Loop
What is a pendulum loop? A pendulum loop is when you play an animation in one direction & then play it back in the opposite direction.
There are multiple ways you could achieve this.
1. You could animate the entire thing, but this is bad in terms of optimization.
2. You could call a called by other action action via the execute action when animation ends option that's found inside of the animation properties.
3. You could do this with the play animation action part, by setting it to play in one direction & wait, then same again but in the opposite direction & wait, & then you would jump back to the initial action part via the jump to action part #? action part to create a loop; providing you want it to loop, of course.
4a. You could insert a line of code into the first frame of the animation, which would be something along the lines of this...
ActiveAnimations["example"].PlayOppositeDirection = false -- play default direction
4b. & then the same again with the final frame of the animation with a line of code that is something along the lines of this...
ActiveAnimations["example"].PlayOppositeDirection = true -- play inverse direction
Move Animation
How can you make your animations move across the screen? Well besides the obvious answer of animating the movement inside of the animation itself, there's actually a few other options you can use for making your animations dance across the across the screen.
The Move Object Action Part
There's technically 2 move object action parts, but we are going to ignore move object as that one is based on relative offset from the default position, & we are instead going to be using move object to as that one uses absolute positioning, which makes things a lot simpler.
Anyway, this one is simple to use, just create a move object to action part, link it to an object then tell it where to go & specify a duration of how long it should take to get from starting position to the target position.
The Tweening Function
The tweening function aka the to() function is very useful for creating transitions from the current state of an object/animation/etc to another state, which could be a new position, a new transparency value, or a new scale value, etc. It can take multiple arguments & anything that requires an integer or float number input can be manipulated by it. Here is the syntax for it...
to(duration, {arguments}, easing, loop, pendulum)
& here is an example of how to move an animation from its current position to a new position...
ActiveAnimations["example"]:to(2500, { CurrentPosition = {x = 500, y = 700} }, easeQuintInOut) -- move animation "example" over 2.5 seconds from starting position to 500 by 700 with a slow build up & ending
Quick note: Check out this [Here is a list of available page for a list of available easing options. |
The Curve System
The bézier curve system is really useful for creating smooth &/or complex paths. It's really great for simulating a bird swooping down into the scene & then back up & out of the scene. You could also use it to control falling snowflakes or leaves, etc.
There are 3 available types of curves in Visionaire Studio that you can use & they are...
Curve
This curve mode will allow you to draw a curve that has a starting point & an end point. You can add as many node points as you like & drag them around to manipulate the curve until you end up with something you like.
Continuous Curve
This curve mode will allow you to create one massive curve that you connect back to the first curve node to create a loop. Have fun creating infinity symbols & snakes (ouroboros) eating their own tales.
Curve Via Control Points
This curve mode will let you create a single really smooth curve that you can adjust after creating by dragging the 2 outer most nodes around. Once you create the initial shape all but 4 of the nodes will be automatically hidden. I'm not really sure what use this curve mode is as you can do the same thing with the first curve option, however this curve mode allows you to create smoother curves overall.
Finally in regards to curves I would like to point out that they are an advanced mechanic & currently there's no way other than scripting available for linking them to scene objects, animations, interfaces, particle systems, etc. If you want to see some curves in action then I would recommend downloading the ved & resource file linked down at the bottom of this page, but just in case you don't want to do that, here's the syntax...
startCallbackTween(duration, function(x), easing, loop, pendulum)
& here's an example script...
local n = "curve_example" -- variable containing curve name
-- * move animation along curve over 10 seconds with rotation of parent scene object enabled * --
startCallbackTween(10000, function(x) -- init curve loop function
local pos = game.CurrentScene.Curves[n]:curveAt(x) -- calculate current curve position
local direction = game.CurrentScene.Curves[n]:curveDirection(x) -- calculate rotation based on curve position
game.CurrentScene.Objects["obj_example"].Rotation = direction -- rotates scene object with curve
ActiveAnimations["anim_example"].CurrentPosition = {x = pos.x, y = pos.y} -- update position of the animation
end, easeLinearIn, true, false)
Rotation
Ideally rotation works best when the image/animation is flat to the screen as opposed skewed. Anyway, you can rotate objects with a line of code that looks something like this...
-- syntax: to(duration, {arguments}, easing, loop, pendulum)
game.CurrentScene.Objects["example"]:to(5000, {Rotation = math.rad(360)}, easeLinearInOut, true) -- rotate 360º over 5 seconds & loop
Pinned Rotation
This one is different from rotation. This allows you to pin a point of an image/animation & then morph rotate the rest of the image/animation. The best way I can think of to describe exactly what this feature does would be to tell you to imagine a flower or a tree that's swaying about in the wind.
I'm not going to provide you with a tutorial of how to do this, but I will link you to the luadocs page where you need to download & include the script found on the page I've linked to as a definition type script inside of your project. It also contains examples of usage too, so hopefully you will be able to figure it out, but if not you can check the reference ved & resource files I have included at the bottom of this page, which also contains examples of everything else I've mentioned on this wiki page.
Scale x Size
There are multiple methods you can use for changing the size of animations & images during runtime, which might be useful in some situations for creating the illusion of depth or purely for the purpose of scaling up or down.
Object Scaling
You can scale scene objects (which includes the images/animations linked to them) up & down with a line of code along the lines of this...
game.CurrentScene.Objects["example"].Scale = 0.5 -- immediately scale object "example" down to 50%
or if you want to tween the object scale from the current scale value to another one then you can do it like so...
game.CurrentScene.Objects["example"]:to(250, {Scale = 0.5}) -- scale object "example" down to 50% over 250ms
Animation Size
You can scale animations up & down with a line of code along the lines of this...
ActiveAnimations["example"].Size = 50 -- immediately scale animation "example" down to 50%
or if you want to tween the animation size from the current scale value to another one then you can do it like so...
ActiveAnimations["example"]:to(250, {Size = 50}) -- scale animation "example" down to 50% over 250ms
ScaleXYZ
Actually it's just X & Y, but I felt like completing the alphabet. Anyway, you can use scaleX & scaleY to flip any image or animation that's linked to a scene object or interface button.
Here's a quick scripting example of how to horizontally flip the image/animation belonging to a scene object...
game.CurrentScene.Objects["example"].ScaleX = -1 -- default = 1
& here's how to vertically flip an image/animation belonging to a scene object...
game.CurrentScene.Objects["example"].ScaleY = -1 -- default = 1
Final Notes
I know I haven't covered all methods as there are other features you can use such as the action part plugin system, or components, or behaviours that you can create via the visual scripting system, but I've never used the visual scripting system before & wouldn't know where to start. Anyway, if anyone has any other tips & tricks they want to include then please let me (AFRLme) know on our discord server.
Resources
Name | Description |
---|---|
animation_tnt_v2.zip | A working .ved file, complete with resources. Check out the readme.txt file for instructions. Visonaire Studio 5.1.9.1+ required. |