Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
jonForum

dispatch random properties in arrays timeLine

Recommended Posts

 

hi guys , what the good way to do this in a timeline ?

 

.from([item1,item2,item3], 1, {rotation:Math.randomFrom(1,4), ease: Power4.easeOut },'#item')

 

My arrays items are dynamic and never same, and i want to dispatch the random value in properties for each items in the array ?

what the best way to proceed and for keep a good readable structure in the timeline.

 

I can maybe do something like this , but it kind weird ! and ugly code.

 

tl.call(() => { items.forEach(it => {tl.from(it, 0.2, {rotation:Math.randomFrom(1,4), ease: Power4.easeOut },'#item') }) },null,null,'#item')

 

If you have some suggest, i take it :)

Link to post
Share on other sites

What about a simple function-based value?

 

.from([item1,item2,item3], 1, {
    rotation: function() {
        return Math.randomFrom(1,4);
    }, 
    ease: Power4.easeOut 
}, '#item')

 

  • Like 2
Link to post
Share on other sites
23 hours ago, GreenSock said:

What about a simple function-based value?

 

 

 

other question ,it also possible to do this with duration?

It work fine for properties but if i also want compute a random durations for each arrays instance
ex :

tl.to(items, ()=>Math.randomFrom(0.8, 1.2),  // function duration not work
{x:'+=180',y:(i,it)=>`-=${100+((it.height/2)*i)}`, ease: Back.easeOut.config(1.4) },'#item')

and i also try pass a array buffer with random value, but array seem no take in count.

hum..

 

let durations = Array.from({length:items.length},()=>Math.randomFrom(0.8, 1.2) );
tl.to(items, durations, // array durations not work
{x:'+=180',y:(i,it)=>`-=${100+((it.height/2)*i)}`, ease: Back.easeOut.config(1.4) },'#item')

 

 

Link to post
Share on other sites

No, that wouldn't make sense because a .to() animation creates a single tween instance which of course can't have multiple durations. If you need different durations for each element, then just loop through your array and create a different tween instance for each. That should be pretty straightforward, but let us know if you need help with that. 

 

Happy tweening!

  • Thanks 1
Link to post
Share on other sites

ok thank you, that makes sense to me.
And It fine not need help for thats you explained me well. :)

Link to post
Share on other sites

I was using the loop for my first experience, but I just wanted to know if I could further reduce the code to avoid that.
But I'm fine, I think I do not have a choice, but my animation is complex and merges with the animation of the spine2D API.
It can be difficult to read code that is too complex.
I was looking for some technical pro to minimize the readability of your API.

i just also found the tricks with addLabel thats help a lot i make more readable the animation for me

        const tl = new TimelineLite({paused:true});
        const speed = 1; //? need sync with spine2d need study?
        if(items){
            tl.addLabel('#item', 0 ) // start item move to player glove
            .addLabel( '#Hit1', 0.4 ) // source hit items and project to target
            for (let i=0, l=items.length; i<l; i++) {
                const it = items[i]; //TODO: ADDlABELS method avant serait plus simple ?
                tl.to(it, 0.5, {x:'+=150',y:`-=${100+((it.height/2)*i)}`, ease: Back.easeOut.config(1.4) },'#item')
                .from(it, Math.randomFrom(1,2), {rotation:Math.randomFrom(Math.PI,Math.PI*3), ease: Power4.easeOut } ,'#item')
                .to(it.scale, 0.2, {x:0.8,y:0.8, ease: Power4.easeOut },'#item')
                .from(it.scale, 0.3, {x:1.4,y:1.4, ease: Back.easeOut.config(4) },'#Hit1')
                .to(it.position, 0.12, {x:target.p.x , y:target.p.y-(target.p.height/2), zIndex:target.p.y+1, ease: Back.easeIn.config(1) },'#Hit1+=0.15' )
            };
            tl.call( () => { $player.spine.s.state.setAnimation(3, "atk2", false); },null,null,'#item+=0.15') // hit
            .call(() => { $camera.moveToTarget(target,7,1,Power4.easeOut); },null,null,'#Hit1+=0.1') // hit
        }
        tl.play();

 

Link to post
Share on other sites

You could wrap some of the logic in a function that returns a timeline, just to modularize things a bit. For example (and this is rough): 

const tl = new TimelineLite({paused:true});
const speed = 1; //? need sync with spine2d need study?
if(items){
    tl.addLabel('#item', 0 ) // start item move to player glove
    .addLabel( '#Hit1', 0.4 ) // source hit items and project to target
    for (let i=0, l=items.length; i<l; i++) {
        tl.add(animateItem(items[i], target), "#item");
    };
    tl.call( () => { $player.spine.s.state.setAnimation(3, "atk2", false); },null,null,'#item+=0.15') // hit
    .call(() => { $camera.moveToTarget(target,7,1,Power4.easeOut); },null,null,'#Hit1+=0.1') // hit
}
tl.play();

function animateItem(it, target) {
    var tl = new TimelineLite();
    tl.to(it, 0.5, {x:'+=150',y:`-=${100+((it.height/2)*i)}`, ease: Back.easeOut.config(1.4) },0)
        .from(it, Math.randomFrom(1,2), {rotation:Math.randomFrom(Math.PI,Math.PI*3), ease: Power4.easeOut }, 0)
        .to(it.scale, 0.2, {x:0.8,y:0.8, ease: Power4.easeOut }, 0)
        .from(it.scale, 0.3, {x:1.4,y:1.4, ease: Back.easeOut.config(4) }, 0.4)
        .to(it.position, 0.12, {x:target.p.x , y:target.p.y-(target.p.height/2), zIndex:target.p.y+1, ease: Back.easeIn.config(1) }, 0.55);
    return tl;
}

 

  • Like 1
  • Thanks 1
Link to post
Share on other sites

yep thanks , i choose a hybride way with forEach
am no fan about scope function in method.


I was able thanks to the system of Label i n your engine, well structure my animations.
being alone I sometimes come back several weeks on codes structure, i just wanted sela remains readable and easy to debug.

From my point of view it satisfies me and seems to me to be easy to read and to interpret the timeLine with addLabel,
And i also solve my fake physic item on the grounds with a forEach.
I will keep this system, thank you to guide me to the right track.

    /** Execute une Action de type attack avec ces configuration options */
    actionPlay_attack(options){
        const items = options.items && $huds.combats.addItemSlotToRegisterMap(options.source);
        const source = options.source;
        const target = options.target;
        const tCollide = ((target.p.width/2)+(source.p.width/2))*(source.p.x<target.p.x?-1:1); // collid restriction with reverse ?
        source.p.position.zeroApply();//zero position de retour
        $camera.moveToTarget(target,8,5);
        //!Step:ANIMATION FOR ITEMS MODE
        const tl = new TimelineLite({paused:true});
        const speed = 1; //? need sync with spine2d need study?
        if(items){
            const ih = 75; // constante items height from size : help math performance 
            tl.addLabel('#itemFocus', 0 ) // start item move and focus to source
            .addLabel( '#HitItem', 0.6 ) // source hit items and project to target
            .addLabel( '#TargetHitItem', 0.7 ) // target Hit by items
            .addLabel( '#ItemFall', 1 ) // items start falling
            .addLabel( '#ItemHitGround', 2 ) // items hits grounds and bouncing
            tl.call(() => { source.s.state.setAnimation(3, "atk2", false) })
            .to(items.map(it => it.position), 0.5, {x:'+=150', y:(i,it)=>`-=${100+ih*i}`, ease: Back.easeOut.config(1.4) },'#itemFocus')
            .to(items.map(it => it.scale), 0.5, {x:'+=1', y:'+=1', ease: Back.easeOut.config(1.4) },'#itemFocus')
            .to(items.map(it => it.scale), 0.3, {x:1, y:1, ease: Back.easeOut.config(4) })
            .fromTo(items, 1, {rotation:Math.PI*2},{rotation:()=>Math.randomFrom(0,2,2), ease: Back.easeOut.config(1.4) },'#itemFocus')
            //HitItem
            .call(() => { target.s.state.setAnimation(3, "hit0", false) },null,null,'#TargetHitItem') 
            .to(items.map(it => it), 0.1, {x:target.p.x ,y:target.p.y-(target.p.height),zIndex:target.p.y+1, ease: Back.easeIn.config(1) },'#HitItem' ) // projet vers target
            .to(items.map(it => it.scale), 1, {x:'+=1' ,y:'+=1', ease: Elastic.easeOut.config(1, 0.3) },'#TargetHitItem' )
            .to(items.map(it => it.position), 1, {x:(i)=>`-=${tCollide/2-ih*i}`, y:`-=${target.p.height}`, ease: Expo.easeOut },'#TargetHitItem+=0.1' )
            .to(items.map(it => it.scale), 1, {x:1 ,y:1, ease: Expo.easeIn },'#ItemFall' )
            .to(items.map(it => it.position), 1, {y:target.p.y, ease: Expo.easeIn },'#ItemFall' ) // fall down
            // bouncing ground
            items.forEach(it => {
                const rx = Math.randomFrom(-20,50);
                const rr = Math.randomFrom(1,4,2);
                tl.to(items, 1, {rotation:()=>`+=${rr}`, ease: Expo.easeIn },'#ItemFall' ) // when fall from ran rotation, hit with *-1
                tl.to(items, 1, {rotation:()=>`+=${rr*-1}`, ease: Power2.easeOut },'#ItemHitGround' ) // when fall from ran rotation, hit with *-1
                tl.to(it.position, 0.3, {x:(i)=>`+=${rx}`, y:'-=50', ease: Power2.easeOut } ,'#ItemHitGround' ) // items hit gound and start fake Physic
                .to(it.position, 0.6, {y:target.p.y, ease: Bounce.easeOut },'#ItemHitGround+=0.3' ) // Y
                .to(it.position, 1, {x:`+=${rx*0.6}`,ease: Power2.easeOut },'#ItemHitGround' ) // X 
            });
        };
        //!Step: ANIMATION FOR PHYSICS
        const timeA = items&&2.1||0;
        tl.addLabel('#physicBack', timeA ) // start physic attaque from 0 or 3 if items
        tl.addLabel('#physicAttack', timeA+0.6 ) // start physic attaque from 0 or 3 if items
        tl.addLabel('#physicHit', timeA+0.6+0.2 ) // start physic attaque from 0 or 3 if items
        tl.addLabel('#backToCase', timeA+0.6+0.2+0.6 ) // start physic attaque from 0 or 3 if items
        .to(source.p.position, 0.2, {x:'-=100', ease: Back.easeIn.config(1) },'#physicBack' )
        .call(() => { source.s.state.setAnimation(3, "preparAtk", false) },null,null,'#physicBack') 
        .call(() => { $camera.moveToTarget(source,8,1, SlowMo.ease.config(0.5, 0.7, false) ) },null,null,'#ItemHitGround')
        tl.call(() => { source.s.state.setAnimation(3, "atk1", false) },null,null,'#physicAttack')
        .to(source.p, 0.2, {x:target.p.x+tCollide, y:target.p.y, zIndex:target.p.y+1, ease: Power4.easeOut },'#physicAttack' )
        .call(() => {  $camera.moveToTarget(target,7,1,Power4.easeOut); },null,null,'#physicAttack')
        .call(() => { target.s.state.setAnimation(3, "hit1", false) },null,null,'#physicHit') // hit
        tl.to(source.p, 1.2, {x:source.p.position.zero.x ,y:source.p.position.zero.y, zIndex:source.p.position.zero.y, ease: Power4.easeOut },'#backToCase' )
        .call(() => {
            source.s.state.setAnimation(3, "backAfterAtk", false); //FIXME: moteur spine plus simple pour animation baser sur $player
            source.s.state.addEmptyAnimation(3, 0.3 );
            target.s.state.addEmptyAnimation(3, 0.3)
        } ,null,null,'#backToCase')
        .call(() => { $camera.moveToTarget(source.inCase,7,3); } ,null,null,'#backToCase+=0.1')
        .call(() => { this.endTurn() } ,null,null,'#backToCase+=2'); //! end turn
        tl.play();

        //DELETEME 
       this.actionsTimeLine = null;
       this._busy = false;

    };

 

The general idea it to have one universal method to manage my combat engine for all character.
YOuVTzIA_o.gif

 

Thank all for you help 

Link to post
Share on other sites

Very glad to hear you got things working and you're happy with it. 

 

Labels can definitely be helpful, but I'd strongly recommend reading this article because I personally think the modular function-based approach is even more flexible and powerful: https://css-tricks.com/writing-smarter-animation-code/

 

Happy tweening!

  • Thanks 1
Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×