Jump to content
Search Community

dispatch random properties in arrays timeLine

jonForum test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

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 comment
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 comment
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 comment
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 comment
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 comment
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 comment
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.
×
×
  • Create New...