Fast Frame Swap
Socks
London, UK.Member Posts: 12,822
GameSalad's animation behaviour is a weird thing, not just because of its arbitrary frame rates (something that's hopefully been addressed in the nightly builds), but also its lack of control and features, especially given that it lives inside an application predominantly designed for game making.
So, with that in mind, I present . . . . . drum roll . . . . a faster frame swap, a replacement for the animation behaviour.
Advantages this has over the animation behaviour are . . .
. . . . .
1) Where the animation behaviour pauses/glitches when first played, this method plays straight away.
2) It is possible to get animations to speed up and slow down.
3) It can go (a lot) faster than the standard animation behaviour.
4) The frame rates are accurate, unlike the current animation behaviour.
5) It can play backwards as well as forwards.
6) Frame based sound sync stays locked in place regardless of frame rate.
7) When you drag a sequence into the animation behaviour the order often gets screwed up, so you have to manually reorder the frames, no big deal on a 21 frame walk cycle, but a nightmare when you are dealing with multiple long frame sequences, this method avoids all that frame wrangling.
. . . . .
It is also super simple to implement and is completely table, attribute and rule free.
Its basically works like this:
Constrain image to floor( game.Time *30)%21
30 is the frame rate you want.
21 is the length of your image sequence (assuming it loops)
. . . . .
Other notes:
► The above example assumes an image sequence starting on frame '0' and having no file name, just the numbers (so basically an image sequence going 0, 1, 2, 3, 4, 5 . . . etc [see attached file's image sequence for an example of this]). But If your frame doesn't start on 0, but instead starts on 1 then simply add 'plus 1' like this:
Constrain image to (floor( game.Time *30)%21)+1
► If your sequence isn't just numerals, but instead has an actual name (so basically an image sequence going Filename_0, Filename_1, Filename_2, Filename_3, Filename_4, Filename_5 . . . etc) then simply add it in like this:
Constrain image to "Filename_"..floor( game.Time *30)%21
► If you want your animation to run backwards, simply make the game.time multiplier negative, like this:
Constrain image to floor( game.Time *-30)%21
► Feel free to swap game.time for self.time - and even introduce offsets if you want or need your sequence to start on a particular frame.
For example, if you had an explosion, you'd want to use self.time rather than game.time - as you'd always want the explosion to start on the first frame (usually when the actor containing it is spawned), but if you had a spinning coin it wouldn't really matter on which frame it started.
. . . . .
Example files:
Frame rates: https://www.mediafire.com/?5y29l4g27u7gmr1
Speed up: https://www.mediafire.com/?dcj81y2qb679lyv
Backwards: https://www.mediafire.com/?1k91133bg4v8mup
The first example file ('frame rates') shows GameSalad's standard animation behaviour going as fast as it can (it's set on 30fps) alongside this new method - and you can really see how much faster this allows you to play animation sequences.
. . . . .
So, with that in mind, I present . . . . . drum roll . . . . a faster frame swap, a replacement for the animation behaviour.
Advantages this has over the animation behaviour are . . .
. . . . .
1) Where the animation behaviour pauses/glitches when first played, this method plays straight away.
2) It is possible to get animations to speed up and slow down.
3) It can go (a lot) faster than the standard animation behaviour.
4) The frame rates are accurate, unlike the current animation behaviour.
5) It can play backwards as well as forwards.
6) Frame based sound sync stays locked in place regardless of frame rate.
7) When you drag a sequence into the animation behaviour the order often gets screwed up, so you have to manually reorder the frames, no big deal on a 21 frame walk cycle, but a nightmare when you are dealing with multiple long frame sequences, this method avoids all that frame wrangling.
. . . . .
It is also super simple to implement and is completely table, attribute and rule free.
Its basically works like this:
Constrain image to floor( game.Time *30)%21
30 is the frame rate you want.
21 is the length of your image sequence (assuming it loops)
. . . . .
Other notes:
► The above example assumes an image sequence starting on frame '0' and having no file name, just the numbers (so basically an image sequence going 0, 1, 2, 3, 4, 5 . . . etc [see attached file's image sequence for an example of this]). But If your frame doesn't start on 0, but instead starts on 1 then simply add 'plus 1' like this:
Constrain image to (floor( game.Time *30)%21)+1
► If your sequence isn't just numerals, but instead has an actual name (so basically an image sequence going Filename_0, Filename_1, Filename_2, Filename_3, Filename_4, Filename_5 . . . etc) then simply add it in like this:
Constrain image to "Filename_"..floor( game.Time *30)%21
► If you want your animation to run backwards, simply make the game.time multiplier negative, like this:
Constrain image to floor( game.Time *-30)%21
► Feel free to swap game.time for self.time - and even introduce offsets if you want or need your sequence to start on a particular frame.
For example, if you had an explosion, you'd want to use self.time rather than game.time - as you'd always want the explosion to start on the first frame (usually when the actor containing it is spawned), but if you had a spinning coin it wouldn't really matter on which frame it started.
. . . . .
Example files:
Frame rates: https://www.mediafire.com/?5y29l4g27u7gmr1
Speed up: https://www.mediafire.com/?dcj81y2qb679lyv
Backwards: https://www.mediafire.com/?1k91133bg4v8mup
The first example file ('frame rates') shows GameSalad's standard animation behaviour going as fast as it can (it's set on 30fps) alongside this new method - and you can really see how much faster this allows you to play animation sequences.
. . . . .
Comments
Looking terrific, @Socks, I look forward to seeing your example files, as well as putting your concept into practice (One day... a particular project I have in mind won't see the light of day for quite some time... )
Anyhow, spot on! :-)
""You are in a maze of twisty passages, all alike." - Zork temp domain http://spidergriffin.wix.com/alphaghostapps
Play the linked file, see how there is a sound as each foot hits the ground, now go into the actor (there is only one) and change the frame rate, at the moment it is 25fps . . . floor( game.Time *25)%21 . . . change it to something else, let's use 40fps as an example, so it should now read . . .
floor( game.Time *40)%21
. . . now play this, notice that the footstep sound (basically a click) is still synced to the animation.
. . . . . .
Link: https://www.mediafire.com/?iovrqqwlpdraije
Cheers gyroscope, hopefully the idea, as simple as it is, will be useful to people.
Cheers wpaten.
MESSAGING, X-PLATFORM LEADERBOARDS, OFFLINE-TIMER, ANALYTICS and BACK-END CONTROL for your GameSalad projects
www.APPFORMATIVE.com
All my games on Google Play
http://jamie-cross.net/posts/ ✮ Udemy: Introduction to Mobile Games Development ✮ Learn Mobile Game Development in One Day Using Gamesalad ✮ My Patreon Page
I actually find it frustrating I'm not good enough to contribute something myself...
for example: attack, dead .. etc.
But maybe you guys have better idea
Zhong.
✮ FREE TEMPLATES, ANIMATIONS ✮ ✮ GAME PRO MARKET BUY & SELL ✮
My GameSalad Academy Courses! ◦ Check out my quality templates! ◦ Add me on Skype: braydon_sfx
So basically when the frame number is (in this example) 20 do nothing (i.e. stop) . . . but until we reach frame 20 then play through the image sequence.
You can use any frame number you like as the stop point.
@izam
@jamie_c
@kinzua
@darrelf
@GSAnimator.com
@BBEnk
@Braydon_SFX
@RThurman
Cheers !
>-
>-
>-
>-
>-
>-
>-
>-
>-
I remember pulling my hair out in the beginning with GS, looking for something like that without having to do everything with timers.
This is absolutely awesome. Thanks again Socks.
For example if you were to put a jump animation into the (currently empty) rules section in the above screen shot, the actor would run until it got to frame 20 then it would jump.
example: 29, 28, 27, 26, 25, 24, 23, 22 and 21fps all run at 20.1fps . . . 20fps runs at 16.5fps . . . 16, 17, 18 and 19 fps all run at 15.1fps . . . etc etc.
From what I hear these shaky frame rates are being dealt with, the new more accurate frame rates have made it into the Nightly Builds, and will, in time, come to the standard release.
So what that means is that when the frame rates are corrected and you open up a project you are working on that uses the animation behaviour, your animations will all speed up, some by as much as 9fps, this won't be an issue for most people, but if you have any time crucial animations (lip sync, animations that need to complete at reasonably precise points . . . and so on) then a sudden 20-30% speed increase might be an issue.
As the method in the OP is locked to the game.time (or self.time) it won't suffer from this issue.
I'll give it a whirl on a future game for sure, but one question!
How does this work if you have a looping animation?
Cheers!
QS =D
Dr. Sam Beckett never returned home...
Twitter: https://twitter.com/Quantum_Sheep
Web: https://quantumsheep.itch.io
Simple . . . it already loops ! In the following example it loops after 21 frames:
Constrain image to floor( game.Time *30)%21
Dr. Sam Beckett never returned home...
Twitter: https://twitter.com/Quantum_Sheep
Web: https://quantumsheep.itch.io
Download a couple of the demo files in the OP to see what I mean ! >-
As far as performance goes, do you think this will have much of an impact using all these constrains? The title I am working on will have around 10-20 animated actors on screen at once. I was already going to use tables/image names for the animations for better control, but I am hesitant on using the contrains. Obviously I will test it before finalizing, just didn't know if you had any preliminary data in regards to performance with a higher number of actors.
Thanks.
Use tables that have a list of animations with the following properties
baseName , FPS, maxFrames
and if you really want to get fancy: startFrame, endFrame instead of maxFrames
and even fancier, a column that says the animation loops or not.
I address this in my original post . . . Defining which frame the animation starts on is simple enough using an offset:
(floor(( self.Time *30)+19)%25)
This runs at 30 fps, it starts on frame 19 and the sequence/loop is 25 frames long.
. . . . . . . .
I also addressed this in my original post . . .
. . . . . . . .
I think a lot of what is attractive about using floor( game.Time *30)%21 is that it eschews all these tables and attributes and timers and rules - and is a simple one line animation driver that can do petty much everything you'd want to do with an animation and is trivially simple to set up and modify - and having no attributes or tables (etc) you can freely cut and paste it from one actor / project to another.
The constrain behaviour has no absolute fixed amount of 'strain' it puts on the processor, using constrain behaviour to track game.time and self.time and device.clock.xxx doesn't seem to be particularly taxing, but obviously if the constrain behaviour was constraining something's x position to . . .
40*sin( game.Time *100)+ 40*sin( 50*cos( 40*sin( game.Time *100)+ 40*cos( 50*sin( game.Time *100) *(3*sin( 50*cos( game.Time *100) *(3*cos( game.Time *200))*200))*100)+80*100) *(3*sin( 50*sin( game.Time *100) *(3*cos( game.Time *200))*200))*100)+80 . . . . etc etc
. . . then you wouldn't really want too many of them on the screen at once as that's a lot of calculation to crunch through.
So . . . everything in context.
Weirdly, you can dump the 'floor' function and this method still works just fine, I'm not 100% sure how or why, but it works.
Using game.time or self.time produces numbers with lots of decimal points, so my first instinct was to chop off the decimal points (using 'floor') so that you only got a whole number - which would match the whole numbers in the names of the frames in the image sequence . . .
My thinking was that if the constrain behaviour (using game.time) produced this:
Run_Cycle_Frame_17.6732
And the actual frame name was:
Run_Cycle_Frame_17
Then you would get a white box where the image should be as there is no such frame as Run_Cycle_Frame_17.6732 . . . but GameSalad seems to ignore the decimal places and quite happily displays Run_Cycle_Frame_17.
So, this method can be simplified even further and there is one less calculation for GS to do at run time (no need for each frame to be 'floor'ed).
So it can simply read . . . . (game.Time*30)%21
. . . . . . . . . . . . . . . . . . . .
So, what would happen if you had an image that was numbered with decimal points (for example - Run_Cycle_Frame_2.567) ?
And you asked GS to display Run_Cycle_Frame_2.567 ?
It behaves as expected and displays Run_Cycle_Frame_2.567.
But . . . . if you also have a file called Run_Cycle_Frame_2 in the same project . . . and you delete the image called Run_Cycle_Frame_2.567 then GameSalad will display Run_Cycle_Frame_2 !!?!??
So, GS will display two different images without you changing the code at all.
This is not really an issue in the real world, but interesting nonetheless (to me at least ! )
I have made the experience, that my iOS devices will calculate more accurate than the GS Viewer.
Your image constrain animation could be such a calculation which would run perfect (if simplified) in the viewer, but not in the adhoc. But I have not tried yet.
If you do not want use the floor function to round your values, you can also use the padReal or padInt functions to get rid off the decimal points.
I can imagine that they are less performance hungry.
The padInt will round the value down
- padInt(123.678,3) will return 123
- padInt(123.456,3) will return 123
The padReal will round values up or down
-padReal(123.678,3,0) will return 124
-padReal(123.456,3,0) will return 123