Author Topic: animate module  (Read 18346 times)

liquid8d

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 442
    • View Profile
animate module
« on: May 17, 2015, 12:34:10 PM »
I was previously working on a whole ExtendedObjects and Animate module. It got a bit overwhelming, and I really wanted the animation parts to be available to everyone, so I sort of rewrote from scratch a new "animate" module.

It's currently in my github for anyone that would like to test it out:
https://github.com/liquid8d/attract-extra/tree/master/modules/animate

There is also some sample layouts that show how to use different animations:
https://github.com/liquid8d/attract-extra/tree/master/layouts

There is still some buggy issues I need to work out, particularly centering objects properly (doesn't work with skew/pinch right now) and a bunch of misc. stuff, but hopefully this helps some people add some nice transition animations without having to write your own transition callbacks and handle everything.

An example of how easy this makes animations:

Code: [Select]
fe.load_module("animate/animate");

//property animation - can be used for any properties that has a numeric value
local logo = fe.add_image("default.png", 0, 100, 640, 360);
local alpha_cfg = {
    when = Transition.ToNewSelection,
    property = "alpha",
    start = 0,
    end = 255,
    time = 1000
}
animation.add( PropertyAnimation( logo, alpha_cfg ) );

//sprite animation - use a spritesheet to animate specific frames of the sprite sheet
local joystick = fe.add_image("joystick-move.png", (fe.layout.width / 2) - 296, fe.layout.height - 128, 128, 128);
local sprite_cfg = {
    when = When.Always,
    width = 128,
    frame = 0,
    time = 3000,
    order = [ 0, 3, 0, 3, 0, 4, 0, 4 ],
    loop = true
}
animation.add( SpriteAnimation( joystick, sprite_cfg ) );

//particle animation - create particle effects
local particle_cfg = {
    resources = [ "default.png" ],
    ppm = 60,
    x = 0,
    y = 0,
    width = fe.layout.width,
    speed = [ 100, 250 ],
    angle = [ 0, 180 ],
    startScale = [ 1, 2 ],
    gravity = 1,
    fade = 10000,
    lifespan = 10000
}
animation.add( ParticleAnimation( particle_cfg ) );


I should be able to work to improve this in the next couple weeks. I hope a few will test it out and provide any feedback. Once I can get some issues corrected, hopefully this module can be included in the next version of Attract Mode by default :)

omegaman

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 880
    • View Profile
Re: animate module
« Reply #1 on: May 17, 2015, 02:45:31 PM »
Liquid-

Good to see you're still active. I've been using your module in my layouts since Raygun included it in the last build. See my recent grey theme on how I am utilizing your module. Anyway, this looks very promising.   

liquid8d

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 442
    • View Profile
Re: animate module
« Reply #2 on: May 17, 2015, 03:28:08 PM »
Thanks! Glad to hear, I'll check it out. This module works a bit differently from the other, but it's not too drastic as far as animations go. Instead of it being a animate function on the object, you just use animation.add( Animation( obj, cfg ) ); - it's probable the two will conflict though, so if you get to try this one out, don't include both.

My plan is to separate the whole "ExtendedObjects" part, they could be used independently or together but I want to sort of get this stuff mostly finalized before I go diving back into ExtendedObjects stuff. It was too much too fast :)

Here's some videos of the sample layouts:

https://www.youtube.com/watch?v=aaZ_2aDxQZE
https://www.youtube.com/watch?v=6yE8S0PjPHw
https://www.youtube.com/watch?v=M2pc0crlrys
« Last Edit: May 17, 2015, 03:59:31 PM by liquid8d »

raygun

  • Administrator
  • Sr. Member
  • *****
  • Posts: 393
    • View Profile
Re: animate module
« Reply #3 on: May 20, 2015, 09:15:17 PM »
Looks good liquid8d.  Thanks for the update, I'll be sure to check it out.  I'm happy to add your work to Attract-Mode, just let me know when you think its ready!

playerzero

  • Jr. Member
  • **
  • Posts: 15
    • View Profile
Re: animate module
« Reply #4 on: May 24, 2015, 04:44:16 PM »
Hi Liquid

First let me say this is a great module, and it should make things a lot easier!

I have discovered a bug with the Properties module:

When operating on an artwork (I haven't tried it out on an image yet), if you don't set the height and width when declaring the artwork
--ie: if you use ("marquee", 10, 5) rather than ("marquee", 10, 5, 150, 50) --
it fails.
In my experience the artwork just disappears from the screen (it may be ending up at coordinates far off the screen).

I prefer not defining height and width, as this sticks with the original artwork sizes rather than resizing it, but your module is so great, I'm happy to work with what I have!

liquid8d

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 442
    • View Profile
Re: animate module
« Reply #5 on: May 24, 2015, 06:25:07 PM »
Thanks, I'll check that out. I think I had that working properly in my original module, but might not have done it properly for those functions.

Glad you like it.. if you have thoughts, suggestions or other bugs you find just let me know!

omegaman

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 880
    • View Profile
Re: animate module
« Reply #6 on: May 25, 2015, 06:42:25 AM »
Liquid-

I have another item that needs to be addressed and kind of expands on what playerzero highlighted. If an improper name definition is used in the fe.add_image() function using animation module it crashes AM. So, for example, if I use fe.add_image("mega.png", 0 ); and that image is not found it crashes the frontend.

Also, how to go about transitioning marquee art from offtop to top like with the old module? I tried to draw it off screen using start then end but I couldn't get the right results. Thanks for all your contributions...

liquid8d

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 442
    • View Profile
Re: animate module
« Reply #7 on: May 25, 2015, 08:19:57 AM »
Thanks, I'll check into non-existing filenames. Does AM usually just ignore it?

As for positions, yes - I know they were super handy, but since that was part of what I was doing for ExtendedObjects, it isn't included in the animate module currently for a few reasons. I will look into having set positions again for animate, but for now here's a list of the ones I had in there:

Code: [Select]
const OFFSCREEN = 20;
POSITIONS <- {
    centerX = function() { return fe.layout.width / 2; },
    centerY = function() { return fe.layout.height / 2; },
    screenPercentX = function(p) { return (p.tofloat() / 100) * fe.layout.width; },   
    screenPercentY = function(p) { return (p.tofloat() / 100) * fe.layout.height; },   
    start = function(o) { return [ o.config.start_x, o.config.start_y ]; },
    last = function(o) { if ("last_x" in o.config == false || "last_y" in o.config == false) return start(o); return [ o.config.last_x, o.config.last_y ]; },
    current = function(o) { return [ o.getX(), o.getY() ]; },
    center = function(o) { return [ centerX() - (o.width / 2), centerY() - (o.height / 2) ]; },
    top = function(o) { return [ centerX() - (o.width / 2), 0 ]; },
    left = function(o) { return [ 0, centerY() - (o.height / 2) ]; },
    bottom = function(o) { return [ centerX() - (o.width / 2), fe.layout.height - o.height ]; },
    right = function(o) { return [ fe.layout.width - o.width, centerY() - (o.height / 2) ]; },
    topleft = function(o) { return [ 0, 0 ]; },
    topright = function(o) { return [ fe.layout.width - o.width, 0 ]; },
    bottomleft = function(o) { return [ 0, fe.layout.height - o.height ]; },
    bottomright = function(o) { return [ fe.layout.width - o.width, fe.layout.height - o.height ]; },
    midtop = function(o) { return [ centerX() - (o.width / 2), (centerY() / 2) - (o.height / 2) ] },
    midbottom = function(o) { return [ centerX() - (o.width / 2), centerY() + (centerY() / 2) - (o.height / 2) ] },
    midleft = function(o) { return [ (centerX() / 2) - (o.width / 2), centerY() - (o.height / 2)  ] },
    midright = function(o) { return [ centerX() + (centerX() / 2) - (o.width / 2), centerY() - (o.height / 2) ] },
    midtopleft = function(o) { return [ (centerX() / 2) - (o.width / 2), (centerY() / 2) - (o.height / 2) ] },
    midbottomleft = function(o) { return [ (centerX() / 2) - (o.width / 2), centerY() + (centerY() / 2) - (o.height / 2) ] },
    midtopright = function(o) { return [ centerX() + (centerX() / 2) - (o.width / 2), (centerY() / 2) - (o.height / 2) ] },
    midbottomright = function(o) { return [ centerX() + (centerX() / 2) - (o.width / 2), centerY() + (centerY() / 2) - (o.height / 2) ] },
    offmidtopleftx = function(o) { return [ -o.width - OFFSCREEN, (centerY() / 2) - (o.height / 2) ] },
    offmidtoplefty = function(o) { return [ (centerX() / 2) - (o.width / 2), -o.height - OFFSCREEN ] },
    offmidbottomleftx = function(o) { return [ -o.width - OFFSCREEN, centerY() + (centerY() / 2) - (o.height / 2) ] },
    offmidbottomlefty = function(o) { return [ (centerX() / 2) - (o.width / 2), fe.layout.height + OFFSCREEN ] },
    offmidtoprightx = function(o) { return [ fe.layout.width + OFFSCREEN, (centerY() / 2) - (o.height / 2) ] },
    offmidtoprighty = function(o) { return [ centerX() + (centerX() / 2) - (o.width / 2),  -o.height - OFFSCREEN ] },
    offmidbottomrightx = function(o) { return [ fe.layout.width + OFFSCREEN, centerY() + (centerY() / 2) - (o.height / 2) ] },
    offmidbottomrighty = function(o) { return [ centerX() + (centerX() / 2) - (o.width / 2), fe.layout.height + OFFSCREEN ] },
    offtop = function(o) { return [ centerX() - (o.width / 2), -o.height - OFFSCREEN ]; },
    offbottom = function(o) { return [ centerX() - (o.width / 2), fe.layout.height + o.height + OFFSCREEN ]; },
    offleft = function(o) { return [ - o.width - OFFSCREEN, centerY() - (o.height / 2) ]; },
    offright = function(o) { return [ fe.layout.width + o.width + OFFSCREEN, centerY() - (o.height / 2) ]; },
    offtopleftx = function(o) { return [ - o.width - OFFSCREEN, 0 ]; },
    offtoplefty = function(o) { return [ 0, - o.height - OFFSCREEN ]; },
    offtopleft = function(o) { return [ - o.width - OFFSCREEN, - o.height - OFFSCREEN ]; },
    offtoprightx = function(o) { return [ fe.layout.width + OFFSCREEN, 0 ]; },
    offtoprighty = function(o) { return [ 0, - o.height - OFFSCREEN ]; },
    offtopright = function(o) { return [ fe.layout.width + OFFSCREEN, - o.height - OFFSCREEN ]; },
    offbottomleftx = function(o) { return [ - o.width - OFFSCREEN, 0 ]; },
    offbottomlefty = function(o) { return [ 0, fe.layout.height + OFFSCREEN ]; },
    offbottomleft = function(o) { return [ - o.width - OFFSCREEN, fe.layout.height + OFFSCREEN ]; },
    offbottomrightx = function(o) { return [ fe.layout.width + OFFSCREEN, 0 ]; },
    offbottomrighty = function(o) { return [ 0, fe.layout.height + OFFSCREEN ]; },
    offbottomright = function(o) { return [ fe.layout.width + OFFSCREEN, fe.layout.height + OFFSCREEN ]; }
}

Some of these position functions are trickier since they require the objects current position or the current layout width/height - or center of the current layout width/height :)

Because of that I had these functions where you just passed the object to the function to determine the coordinates. These are returning an array, so offtop would be offtop[0] (x) and offtop[1] (y), top would be top[0] (x) and top[1] (y)

You could technically include that in your layout if you use a lot of them, then for start end values, just pass it like:
Code: [Select]
   local start = { x = POSITIONS['offtop'][0], y = POSITIONS['offtop'][1] }
   local end = { x = POSITIONS['top'][0], y = POSITIONS['top'][1] }

If you just want to implement "offtop" and "top", you can set the start and end values like so:
Code: [Select]
  local OFFSCREEN = 20;
  local myObj = fe.add_text( 0, 0, 300, 30 );
  local offtop = [ fe.layout.width + myObj .width + OFFSCREEN, (fe.layout.height / 2) - (o.height / 2) ];
  local top = [ (fe.layout.width / 2) - (myObj.width / 2), 0 ];

  local config = {
     when = Transition.ToNewSelection,
     property  = "position",
     start = { x = offtop[0], y = offtop[1] }
     end = { x = top[0], y = top[1] }
  }
  animation.add( PropertyAnimation( myObj, config ) );

Hope that makes sense.. let me know if you have any issues.
« Last Edit: May 29, 2015, 11:56:55 AM by liquid8d »

omegaman

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 880
    • View Profile
Re: animate module
« Reply #8 on: May 25, 2015, 10:21:07 AM »
Liquid-

Yes, AM will just report the error once the front-end exits gracefully. Thanks for the info on how to position the marquee.

liquid8d

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 442
    • View Profile
Re: animate module
« Reply #9 on: June 02, 2015, 12:12:50 PM »
I finally made a proper full on "layout" tutorial that demonstrates the features of the animate module... :)

https://www.youtube.com/watch?v=blvbkHXvcYg

Working on a few oh the bugs mentioned in the module and some cleanup of these demo layouts and they will be available to show you how to use everything properly.

omegaman

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 880
    • View Profile
Re: animate module
« Reply #10 on: June 02, 2015, 03:02:13 PM »
Liquid8-

Fantastic job man, this is just what the doctor ordered. Hopefully, more members will start discovering how your awesome mod can enrich their layouts.

liquid8d

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 442
    • View Profile
Re: animate module
« Reply #11 on: June 02, 2015, 03:17:03 PM »
Liquid-

If an improper name definition is used in the fe.add_image() function using animation module it crashes AM. So, for example, if I use fe.add_image("mega.png", 0 ); and that image is not found it crashes the frontend.

I just tried this and didn't have any crashes. Can you confirm if you are using 1.5.2 / 1.5.3? Maybe something specific to what you were doing with that particular image crashed it. If you can give me an example layout or something, I can check it out.

liquid8d

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 442
    • View Profile
Re: animate module
« Reply #12 on: June 02, 2015, 04:06:11 PM »
When operating on an artwork (I haven't tried it out on an image yet), if you don't set the height and width when declaring the artwork
--ie: if you use ("marquee", 10, 5) rather than ("marquee", 10, 5, 150, 50) --
it fails.

I have a workaround for this and will be updating the animate module soon - but for now, you will not be able to use 'scale' and 'rotation' if the width and height are not set but any existing properties should work ok. Those need the width and height to work and that will be a little more complicated for me to implement using texture_width and texture_height :)

omegaman

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 880
    • View Profile
Re: animate module
« Reply #13 on: June 02, 2015, 08:29:55 PM »
Liquid8-

I am running v.1.5.2, don't use a duel monitor. Anyway, I can reproduce the error every time by changing the name from barrow.png to something that doesn't exist. See attached .nut as well. 

/sprite animation - use a spritesheet to animate specific frames of the sprite sheet
local pointer = fe.add_image("barrow.png", flx*0.46, fly*0.91, flw*0.1, flh*0.1);
pointer.rotation = 270;
local sprite_cfg = {
    when = When.Always,
    width = 100,
    frame = 0,
    time = 2000,
    order = [ 2, 4, 2, 4, ],
    loop = true
}

animation.add( SpriteAnimation( pointer, sprite_cfg ) );   

liquid8d

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 442
    • View Profile
Re: animate module
« Reply #14 on: June 02, 2015, 10:00:37 PM »
Ahhh, ok - I forgot to try sprite.. I just found what's causing it - it applies fix_masked_image() to the sprite.. and the non-existent object makes that function crash apparently.

Should be able to figure something out and have that fixed in the next update :)


Here's an arrow I worked up for testing, I used:
order = [ 0, 1, 2, 1, 0, 3, 4, 3 ]

:)
« Last Edit: June 02, 2015, 10:31:11 PM by liquid8d »