Jump to content
Search Community

How to control and switch between multiple timelines?

Johan ⚡️ Nerdmanship test
Moderator Tag

Go to solution Solved by Dipscom,

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

While learning GSAP and Js, I'm experimenting with this Crab character – Bob. He can do a bunch of different poses which are specified in different timelines, in separate projects. My end goal is to have one dynamic composition with a bunch of ways to interact with Bob; move him, scare him, flatter him, etc, but I'm having some trouble with the logics beyond making a fun timeline. My Js experience is limited so please bare with me.

 

I've created this simplified pen, without Bob, to explain my challenge: 

 

Basically, what I'm trying to solve is this:

If a user clicks "left", Bob can walk left – no problem. But if Bob is walking left and the user clicks right, then Bob must first quit walking left and seamlessly transition to a new pose before he starts walking right. My animations are quite granular so I want full control over such transition animations too. So I need to write a little script.

 

My approach to the problem:

  • All poses are animations that should start and finish in the set start values
  • There are three poses in the example: idle, move left and move right
  • Each pose have three parts; "entry", "loop" and "exit"
  • "Entry" animates the character from start values into the "loop"
  • "Loop" is the main animation, i.e. "continuously walk left"
  • "Exit" animates the character form the "loop" back to start values
  • The "loop" is set to infinite repeat, which intentionally hinder the timeline to reach the "exit"
  • To seamlessly transition from one pose to another, the current pose must end before the next pose begins
  • To end the current pose I want to remove "repeat: -1" and allow the timeline to finish and the use a callback to start the next
  • After "repeat: -1" been removed I need to add it again, to make a pose reusable

 

This code doesn't work, but I included it to show you what I'm trying to achieve and how:

// CLICK-A-BUTTON LOGICS

$("button").click(function(){

  // these values are strings, but I need to reference the objects
  nextPose = "tlPose" + this.dataset.tl;
  nextLoop = "tlLoop" + this.dataset.tl;
  
  // disable looping to reach "exit" label of currentPose
  TweenMax.set(currentLoop, {repeat:1});
  // and re-enable it so it's looping next time it's used
  TweenMax.set(currentLoop, {repeat:-1});

  // when currentPose is complete, update the current pose and play it
  currentPose.onComplete(function(){
    currentPose = nextPose;
    currentPose.seek("entry").play();
  });
}); 

Is the approach to this problem ok or should I try something else?

When I'm defining newPose and newLoop, how can I make those values to be tlPose1 and not a string like so, "tlPose1"?

How do I change the repeat value of a timeline?

 

I'm very open to other suggestions and feedback! Thank you so much for helping me and Bob move forward! :)

 

--

 

I struggled so with setting a descriptive topic to this post! Any conventions?

See the Pen YqMJEe?editors=0011 by stromqvist (@stromqvist) on CodePen

Link to comment
Share on other sites

Thanks for the demo and description. 

Unfortunately I can't really decipher what all the code is doing or supposed to do. 

Couldn't tell anything changing when i hit the different buttons.

 

In general I think you might want to try the following approach.

 

Whenever you need to change the animation cycle:

1: use a variable like "nextPose" to store the name a function that will generate a timeline for the next pose.

2: call a function that creates a timeline that returns all the elements to a neutral state. So perhaps you call a funciton that generates a timeline that sets the rotation of all the legs to 0

3: give that  timeline an onComplete callback which is a function that generates a timeline for the next pose

 

sort of like

var nextPose;

function goLeft() {
var tl = new TimelineLite();
tl.to(crab, 1, {x:"+=100"});

}

moveLeft.click(function() {

nextPose = goLeft;
goNeutral();

})

function goNeutral() {
var tl = new TimelineLite({onComplete:runNextPose});
tl.to(legs, 1, {rotation:0});
}


  • Like 4
Link to comment
Share on other sites

Thanks for taking the time, Carl!

 

Sorry for being unclear! I'll try to isolate my problems in the future.

 

I like and understand your suggested approach, but I don't think it solves my problem. I need a timeline to finish before it stops.

 

Here's a very simplified one: 

See the Pen VaorOG?editors=0011 by stromqvist (@stromqvist) on CodePen

 

When I click the button, I want the timeline to stop repeating.

However, I want it to finish, not snap back to first position.

var tl = new TimelineMax({repeat:-1, yoyo:true});

tl.to("rect", 1, {x: 100});


// When the button is clicked, the timeline should stop repeating

$("button").click(function(){
 
  tl.repeat(1);

});

This would make sense to me, and works if the button is clicked during the first repetition.

But if the button is clicked after the first repetition, the timeline just snaps back.

Link to comment
Share on other sites

That worked really well!

 

This is how I applied it: 

See the Pen vGoQar?editors=0010 by stromqvist (@stromqvist) on CodePen

 

But of course, new questions arise... I couldn't figure out how to use yoyo() in this approach, so I tried a workaround inspired by other examples I've seen. It works well, but I have a few questions.

 

  1. Could I use the yoyo method with this approach? If so, how?
  2. I've seen similar solutions with onComplete and onReverseComplete, but mine doesn't look the same. I tried finding these methods in the docs, but failed. Is there a more straight forward way of using onComplete to reverse the timeline without declaring a function such as "reverseTl"?
var tl = new TimelineMax({onComplete:reverseTl, onReverseComplete: shouldRepeat}),
    isPlaying = true;

tl.to("rect", 1, {x: 100});


// When the button is clicked, the timeline should toggle repeat

$("button").click(function(){ // when the button is clicked
  if (isPlaying==true){       // if the timeline is playing
   isPlaying = false;         // set it to off
  } else {                    // if it's not playing
    isPlaying = true;         // set it to on
    tl.resume(tl.progress()); // and keep playing from where the playhead currently is, just in case the user clicks the button twice
  }
});

function shouldRepeat() {
  if(isPlaying==true) {
    tl.play(0);
  } else {
    return;
  }
}

function reverseTl() {
  tl.reverse();
}

edit: updated the pen

Link to comment
Share on other sites

Oh wow, that's embarrassing... I actually read that post not long ago.

 

Thank you for a great reply, Pedro! It think it will solve my problem. I'll try it out and then hopefully mark this one solved.

 

Memory is such a fickle thing... I would not worry about that so much.

 

As for your current question. I'd use the same logic as in the previous issue:

 

----

 

TL: play();

 

TL end: What should I do()?

 

- Am I to stop()?

-- Yes.

--- Stay put();

 

-- No.

--- Play again();

 

Hang on. Before I start....

---- Am I reversed()?

------ Yes.

------- Play forwards();

 

------ No.

------- Play backwards();

 

Here's your pen with the above in JS ;)

 

See the Pen pyMqeR?editors=0010 by dipscom (@dipscom) on CodePen

  • Like 2
Link to comment
Share on other sites

Ah, but you only need one sock-puppet internalising the meaning of his own existence.

 

:D

 

But I guess, looking at it again, you could also accomplish an interesting level of drama with two of them. If you make the second one "the devil".

Link to comment
Share on other sites

  • 2 weeks later...

Thought I would share the final result based on my initial goal:

 

 

Basically, what I'm trying to solve is this:

If a user clicks "left", Bob can walk left – no problem. But if Bob is walking left and the user clicks right, then Bob must first quit walking left and seamlessly transition to a new pose before he starts walking right. My animations are quite granular so I want full control over such transition animations too. So I need to write a little script.

 

My approach to the problem:

  • All poses are animations that should start and finish in the set start values
  • There are three poses in the example: idle, move left and move right
  • Each pose have three parts; "entry", "loop" and "exit"
  • "Entry" animates the character from start values into the "loop"
  • "Loop" is the main animation, i.e. "continuously walk left"
  • "Exit" animates the character form the "loop" back to start values
  • The "loop" is set to infinite repeat, which intentionally hinder the timeline to reach the "exit"
  • To seamlessly transition from one pose to another, the current pose must end before the next pose begins
  • To end the current pose I want to remove "repeat: -1" and allow the timeline to finish and the use a callback to start the next
  • After "repeat: -1" been removed I need to add it again, to make a pose reusable

 

See the Pen yJLxjJ by stromqvist (@stromqvist) on CodePen

 

Credit where credit is due in the description. Thanks GSAP, Carl and Dipscom – I learned lots in this exploration!

 

I want to learn how to write smart, consise and readable code – so any critique is appreciated!

  • Like 1
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...