Jump to content
Search Community

A more selective alternative to exportRoot or the root timeline?

Topsy test
Moderator Tag

Recommended Posts

I was using exportRoot to pause/resume all my tweens, and it worked great! However, it is no longer desirable to pause ALL the running tweens. I need to pause some of them, but not all of them.

 

So I made a timeline and fed new tweens to it whenever they were created, so I could just pause/resume that timeline: great in theory, but not so simple in practice. First of all, just adding a new tween to the timeline requires calculating a start time to prevent independent tweens from just stacking up end-to-end. The big problem is that the timeline becomes inactive if nothing gets added to it for a while. Then when something does get added to it, it doesn't play immediately (or at all).

 

Is there a better way to duplicate the functionality of exportRoot more selectively? Can I create an alternative to the root timeline? Or does it just sound like my implementation is broken?

 

Link to comment
Share on other sites

Hi and welcome to the forums.

 

There isn't a more selective alternative to exportRoot(). Perhaps getTweensOf() will help.

As long as you track the objects that you want to stop animating (in an array), you could use getTweensOf to find all those tweens and then pause() them or perhaps even add them to another timeline. 

 

---

 

I'm a little curious about the behavior of the timelines becoming inactive and not working properly (or as expected). If you would like to provide a code sample or more info we will look into it further to see if there is something that needs fixing.

Link to comment
Share on other sites

Two more tips:

  1. Make sure you're using the latest version of the GSAP files
  2. You can use the [undocumented] rawTime() of timelines as the insertion point - that's just a way to get the raw time without any clipping that normally occurs. When I say "clipping", I mean that a timeline's "time" can never legally exceed its duration, otherwise it would be like moving the playhead to a place that doesn't exist. Imagine a 10-second timeline that's nested at the beginning of a 30-second timeline whose playhead is currently at the 15-second spot. Technically, that child timeline's playhead is at its very end (10-seconds) but the parent's playhead is 5 seconds beyond that. So rawTime() would return 15 instead of 10. You could leverage that as the insertion point of your new tweens so that they line up exactly with where the playhead currently is (in the parent). Like child.add( yourTween, child.rawTime());

Like Carl said, if you're having trouble with things acting strangely or you suspect there's a bug somewhere, please shoot us a simple set of files that we can take a peek at. 

  • Like 1
Link to comment
Share on other sites

Thank you, that will probably prove helpful.

 

I will describe the problem I am having and try to put together an isolated sample later. I create a timeline (frame-based) to hold my tweens for pausing, but I do not add any tweens to it immediately. At some point, an object is animated and the tween is created and added to the timeline. However, the tween does not play. The behavior was inconsistent; sometimes it would play late, sometimes it would not play at all, sometimes it did play correctly. I was adding the tween at the current time of the timeline. Something like this:

theTimeline.add( theTween, theTimeline.time() )

I will be digging in to this again tomorrow, and I will be back here if I cannot figure it out by myself.

Link to comment
Share on other sites

I have had some success, but it has not been so smooth and easy as exportRoot. I used exportRoot as the basis for my collecting as I do not understand all of the time properties involved. First I create timelines (one for frame-based and one for time-based, I am only including the time-based code):

tlTime = new TimelineLite( { autoRemoveChildren: true, smoothChildTiming: true } );
var rootTime :SimpleTimeline = tlTime._timeline,
rootTime._remove( tlTime, true);
tlTime._startTime = 0;
tlTime._rawPrevTime = tlTime._time = tlTime._totalTime = rootTime._time;
rootTime.add( tlTime,0 );

Then whenever I create a tween, I register it as follows (t is the incoming tween or timeline):

tlTime.add( t, tlTime.rawTime() - t._time);

The offset by '_time' is for tweens that do not start at zero-time (there a few oscillating tweens that must start in the middle).

So far so good. However, when I pause and resume repeatedly, I get very flaky behavior. Pausing and resuming is just:

tlTime.pause();
tlTime.play();

It appears that the "flaky behavior" is delayedCalls and onComplete callbacks not firing (though there are some mysterious disappearances whose cause I have not been able to nail down). I also had to wrap any repeating tweens into timelines before registering them though they worked fine on the root timeline.

 

So now I am just trying to restore stability as pausing/resuming can cause the game to enter a bad state. Is there something obvious I am missing with the above code?

Link to comment
Share on other sites

I'd like to mention a few things:

  1. In general, you should never mess with any properties/methods that start with an underscore ("_"), as those are intended for internal use only (private). That's why they're not in the docs either. It looks like you're doing quite a bit of monkeying with those :)
  2. If you noticed delayedCalls or onComplete callbacks aren't being fired, maybe it's because you're using seek() somewhere and you didn't set the "suppressEvents" parameter to false. Please see the docs. Those are purposely skipped by default, as it is generally considered the most intuitive behavior.
  3. I really didn't follow some of your logic or why you're writing the code the way you are. :(
  4. Maybe it would help if you just created a very simple demo that clearly shows the problem in the simplest way. It's very difficult to troubleshoot when we don't have something like that to look at.
  5. What version are you using? 
Link to comment
Share on other sites

1. I was monkeying with the internal properties because none of the external properties were working, and I could not find a general explanation in the docs of how timelines/tweens work with regards to the various time/delay properties and pausing and nesting and playheads and all, so I resorted to some trial and error and to looking at what exportRoot does.

 

2. I do not call seek() explicitly anywhere in my project. I do have some tweens that are instantiated and then set to a different time() or progress().

 

5. I'm running v12... I don't see a more specific release number in the source folder or changelog. Where might I find it?

 

3-4. Perhaps I should just restate my original situation/question. I have a game SWF that runs in a shell SWF. I was using exportRoot to pause my game, however this was interfering with tweens in the shell. I needed something that would only gather MY tweens. My solution was to collect all the tweens used in my game into a single timeline (like the root timeline) and then just pause/resume that timeline. I modified all my calls to pass any new tween instances to a collector to be added to a control timeline. This was complicated, and I could not get it to work. Is this approach sensible? How would you collect all tweens on a single control timeline (well two, one for frame-based one for time-based)?

 

Just using 'add()' on its own would not serve as that would append tweens to the end of the timeline. As a tween was made it needed to be added to the timeline *now* as though it were left on the root timeline. It was not clear how to achieve this, so I monkeyed with various timing properties until I got something that worked. However, I was still having problems with tweens not playing or playing at the wrong time or just disappearing (some tweened objects would go poof as though the tween had abruptly ended or reset or something) when I would pause/resume the control timeline.

 

I'm sorry I haven't had time to put together a sample that demonstrates my situation (I can't share the actual project, and I'm still too busy with it to build a demo). I ended up brute-forcing it by storing tweens/timelines in an array and then pausing/resuming them all. I used the '_gc' property to test if the tween was still valid and worth keeping in the array (naughty naughty).

Link to comment
Share on other sites

It sounds like you've been pretty busy ;) 

 

As far as the version, you could simply look at the ActionScript file (version is at the top) or trace(TweenLite.version);

 

I'm not sure I entirely understand your setup or goal (I know you're working on a sample which will be VERY helpful in terms of troubleshooting), but I'm pretty confident that all the "weirdness" you're experiencing is just caused by not understanding how things do (and should) work. I bet the light bulb will go on soon and all the behavior will make sense (or maybe not) :)

 

Did you try following my original suggestion?

timeline.add(yourTween, timeline.rawTime());

I don't think it should be as complicated as it seems you're describing. 

 

And again, please make sure you're using the latest version. 

Link to comment
Share on other sites

Looks like I'm still on 12.0.13. I'll pull .14 and put together a sample today.

 

I did try rawTime(), but again, it did not always put new tweens in the right place. For tweens that were offset (for example: progress changed), they would play normally when left alone, but when added to the collector timeline, they would jump to the wrong position.

 

As helpful as the docs are for using the tools (and greensock has excellent API documentation), I feel I could really use a more thorough explanation of the system to gain a better grasp of what I *should* be doing with the tools. For example, I don't really understand the notion of the playhead in greensock. Is there just one? Does each tween/timeline have its own? What happens to the playhead(s) when you nest animations in timelines? If you create a repeating tween and change its progress immediately, what is its starttime? How does an empty timeline behave if it is empty and something gets added to it in the future or the past? These are the sorts of questions that I don't see clear answers to in the docs. I could figure out the answers by reading the source or making lots of tests, but I don't have time for that just now. I simple diagram or two would probably go a long way. Is there such a thing anywhere? Am I just missing the right page?

 

I will see about a sample as long as there are no fires today.

Link to comment
Share on other sites

As for your other questions, yeah, it's a balancing act in the docs between providing detailed information and going way too deep and overwhelming people. We could write a book ;)

 

Every tween and timeline has a parent timeline (except the 2 root timelines - there's one for normal tweens and another for "useFrames" ones). In a sense, yes, they all have their own playheads (that's what its "time" refers to, or "totalTime" which is identical except that it includes repeats and repeatDelays) but generally they're not independent because they're sitting on a timeline whose playhead moves. When the parent's playhead moves to a new position, it updates the childrens' too. 

 

When a timeline renders at a particular time, it loops through its children and says "okay, you should render as if your playhead is at ____" and if that child is a timeline with children, it does the same to its children, right on down the line. 

 

The exception is if the tween/timeline is paused in which case its internal playhead acts like it's "locked". So in that case, it's possible (likely in fact) that the child's playhead would not be synced with the parent's. When you unpause it (resume()), it essentially picks it up and moves it so that its internal playhead is synchronized with wherever the parent's playhead is at that moment, thus things play perfectly smoothly. That is, unless the timeline's smoothChildTiming is to false in which case it won't move - its startTime will remain locked to where it was. 

 

So basically, when smoothChildTiming is true, the engine will rearrange things on the fly to ensure the playheads line up so that playback is seamless and smooth. Same for when you reverse() or alter the timeScale, etc. But sometimes you might not want that behavior - you prefer to have tight control over exactly where your tweens line up in the timeline - that's when smoothChildTiming:false is handy. 

 

One more example: let's say you've got a 10-second tween that's just sitting on the root timeline and you're 2-seconds into the tween. Let's assume it started at exactly 0 on the root to make this easy, and then when it's at 2-seconds, you do tween.seek(5). The playhead of the root isn't affected - it keeps going exactly as it always did, but in order to make that tween jump to 5 seconds and play appropriately, the tween's startTime gets changed to -3. That way, the tween's playhead and the root playhead are perfectly aligned. 

 

Does that help?

  • Like 1
Link to comment
Share on other sites

That's super-excellent and only ever-so-slightly less useful than a purty little diagram with circles and arrows. Thank you.

 

I will try the v.15 preview, and I will also beef up the sample to see if I can get it to reproduce some of the other issues in case there is something else going on.

 

It was a bit frustrating when 'exportRoot' just worked, but doing the same thing for a selected set of tweens did not.

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