Jump to content
Search Community

Memory issue with TimelineMax(paused:true)

Polarathene test
Moderator Tag

Recommended Posts

I'm putting together an animation in starling/feathers that scales a sprite from scale x/y values of 0 to 1, same with alpha property. I use a timelinemax instance to sequence a series of the same animation on different sprites staggering them by 0.3. I also created another timelinemax instance with a stagger of 1 with labels to manually progress through the animation one animated sprite at a time using buttons.

 

This is being developed in AIR so I have access to System.gc(), I've noticed that if I run the code that creates all the tweens and sprites(card graphics which will be different each time based on shuffled deck input) when using System.gc() garbage collection works fine, but only if I don't create my timelinemax instances paused.

 

I've also read over quite a few threads on this forum to see if anyone had memory issues with greensock classes but constantly see reassurance that is highly unlikely. Where I'm confused is that when creating the sequence, if I instead provide an array with exactly the same tween code to the same target with the same tweenmaxvars objects the memory continues to rise.

 

Without any tweenmax calls using the sprites as targets, over a loop of the creation function 5,000 times I have only 16mb memory usage. When I add just one tweenmax call 383mb that the gc doesn't want to remove unless the timeline is unpaused, the sprites must be referenced by the timeline in some way as without creating tweenmax instances that target them they gc perfectly. I copy/pasted the tweenmax line 4 more times and added that as an array of tweens to the timeline, this gave 500mb+ in memory. Is all that extra memory only tweenmax related or is it holding/duplicating other information? I also gave it a stock starling new Sprite() instead of my card sprite and got 200mb from the loop.

 

This is my tweenMaxVars and the tweenMax code(not actual function, though can try provide condense/isolated version if needed).


 

private var tweenMaxVars_alphaFrom:TweenMaxVars = new TweenMaxVars( { alpha:0 } )
private var tweenMaxVars_alphaTo:TweenMaxVars = new TweenMaxVars( { alpha:1, immediateRender:true, ease:Power1.easeOut } )
            
private var tweenMaxVars_scaleFrom:TweenMaxVars = new TweenMaxVars( { scaleX:0, scaleY:0 } )
private var tweenMaxVars_scaleTo:TweenMaxVars = new TweenMaxVars( { scaleX:1, scaleY:1, immediateRender:true, ease:Back.easeOut } )

TweenMax.fromTo(cardArray[i], 0.5, tweenMaxVars_alphaFrom, tweenMaxVars_alphaTo )
TweenMax.fromTo(cardArray[i], 0.5, tweenMaxVars_scaleFrom, tweenMaxVars_scaleTo )

 

 

So is this sort of behaviour correct? I don't intend to use System.gc() intentionally, I just wanted to make sure that when flash calls it on it's own that there are no issues like the one described above where data is not removed from memory.

 

 

One last thing, I noticed how much faster tweenNano is compared to lite and max at least with my situation. My tweens aren't overly complicated but I use "fromTo", is there anyway to get that functionality working with tweenNano or is it omitted for performance cost compared to the "to" and "from" functions?

 

Link to comment
Share on other sites

While typing out the post I realised that I was creating a new timeline each time I ran the function through the loop. Although I had it assigned to a variable, and thought that when instancing a new one the previous would be released for garbage collection. I can now perform a clear() on the timeline prior to doing anything else within the sequence building function. I also create the first and only instance of the timeline in my init rather than the function building the sequence.

 

If you don't mind, is there a better way to go about building a tween sequence like this? I am tweening the same object but with two different duration/ease combinations, from what I understand I can't add multi-dimensional arrays to a timeline so I added the tweens to another timeline instance, this way it staggers the sequence correctly and labels are placed alongside the pair of tweens.

private function buildTween(_mainTimeLine:TimelineMax, _stagger:int):void
{
 tempArray = []
 labelArray = []
 cardArrayLength = cardArray.length
 for(i=0;i<cardArrayLength;i++)
 {
  var tempTimeLine:TimelineMax = new TimelineMax()
  tempTimeLine.add
   ([    
   TweenMax.fromTo(cardArray[abc], 0.5, tweenMaxVars_alphaFrom, tweenMaxVars_alphaTo ),
   TweenMax.fromTo(cardArray[abc], 0.5, tweenMaxVars_scaleFrom, tweenMaxVars_scaleTo )
   ])
  tempArray.push(tempTimeline)
  labelArray.push(String(i))
 }
 _mainTimeLine.add(tempArray,0,"start",_stagger)
 _mainTimeLine.add(labelArray,0,"start",_stagger)
 _mainTimeLine.invalidate()
}

 

 

The opening post however I was working with a different approach to skip the extra set of timelines which is probably a better choice:
 

private function buildTween(_mainTimeLine:TimelineMax, _stagger:int):void
{
 tempArray = []
 labelArray = []
 cardArrayLength = cardArray.length
 for(i=0;i<cardArrayLength;i++)
 {
  _mainTimeLine.add
   ([    
   TweenMax.fromTo(cardArray[abc], 0.5, tweenMaxVars_alphaFrom, tweenMaxVars_alphaTo ),
   TweenMax.fromTo(cardArray[abc], 0.5, tweenMaxVars_scaleFrom, tweenMaxVars_scaleTo )
   ], i*_stagger)
  _mainTimeLine.addLabel(String(i), i*_stagger)
 }
 _mainTimeLine.invalidate()
}
Link to comment
Share on other sites

Something sounds very strange. I cannot fathom how some TweenMax or TimelineMax instances could possibly take up that much memory unless you're creating millions of instances simultaneously. Nor can I think of a reason why having a timeline paused vs. unpaused would cause a massive increase in memory. It's literally just a flag inside the engine - pausing an instance doesn't suddenly make it store a bunch of stuff in memory or create extra references. I'd be very curious to see your files and publish them on my end to see what's happening.

 

Also, are you using the latest version of the GSAP files? I'd strongly recommend that too. 

 

Another strange thing you mentioned is that TweenNano is performing much better for you than TweenLite (and TweenMax)? I'm having a tough time imagining why unless you're creating an insane amount of instances and therefore the smaller memory footprint of TweenNano is paying dividends, but raw execution speed of the code should be almost identical between TweenNano and TweenLite (TweenMax is slightly slower due to having to accommodate repeat/yoyo/repeatDelay in a very precise way inside the rendering loop, but real-world performance should be virtually indistinguishable). 

 

Have you profiled your app to see how many tween (or timeline) instances you're creating? I wonder if you've got some runaway loops in your code somewhere. 

 

Tweens do, of course, have a reference to the target instance, so if you're expecting to gc targets who are referenced inside of tweens that you're keeping around (either by maintaining a reference yourself or putting them inside a timeline that you keep a reference to), that can't happen (nor should it). 

 

I'm wondering why you invalidate the timeline right after you create it. Seems pretty wasteful, but maybe I'm missing something that you're trying to achieve.

 

As for your code example, I didn't quite follow where you're declaring certain variables like abc or cardArrayLength, etc. I also don't know why you're creating tempArray and labelArray in your 2nd example but then never using them. You could make your slightly more efficient like this (assuming you don't need any TweenMax-specific features):

 

private function buildTween(_mainTimeLine:TimelineMax, _stagger:int):void {
    var l:int = cardArray.length;
    for(i=0; i < l; i++) {
        _mainTimeLine.add(String(i), i * _stagger)
            .fromTo(cardArray[i], 0.5, tweenMaxVars_alphaFrom, tweenMaxVars_alphaTo, i*_stagger)
            .fromTo(cardArray[abc], 0.5, tweenMaxVars_scaleFrom, tweenMaxVars_scaleTo), i*_stagger);
    }
}

I'd definitely recommend checking how many instances you're creating and then if you're still having any trouble, please send us a sample set of files that clearly demonstrate the memory issues and we'd be happy to take a peek. 

Link to comment
Share on other sites

Oh sorry, I was terribly tired up late trying to suss out what was going on, my code is in a bit of a commented out mess at the moment where I'm building the timeline, the abc value is equivalent to i, I meant to replace abc with i but must have missed it. The 2nd example didn't need either of those arrays, again my mistake from tiredness.

 

I used a trace for each loop to trace the iteration number "trace(iteration++)" Just so I could visually see the progress before anything would display on the stage. With TweenNano it took alot less time to go through 5,000 loops than tween Lite or Max, I have no idea about actual performance.

 

I invalidated to set the targets properties to the starting scale/alpha values, though if invalidate does more than that and it's better to set those directly prior I can change the code, figured it was more easier to tweak the tweenMaxVars. The variables that weren't declared in the examples were declared outside of the function I was looping, perhaps I've misunderstood performance optimization with looping:

 

var arrLength:int
var i:int
var j:int

private function startLoop():void
{
 for(i=0;i<5000;i++)
  {
   functionToLoop()
  }
}

private function functionToLoop():void
 {
 arrLength = arr.length
 for(j=0;j<arrLength;j++)
  {
   //do something
  }
 }

 

Is it the same just to declare var arrLength = arr.length inside the loop function? That'd be creating a new object wouldn't it? Whereas having the var outside of my functions would just update the value to the same object.

 

I think the problem came from assuming the same when I did this loop I was performing "myTimeLine = new TimelineMax(paused:true)", in doing so the previous instance if paused was true would keep it in memory, though later I found that if I perform clear() on the timeline prior to replacing it with a new instance it gc's perfectly. I later removed creating a new instance in the function loop and just cleared the same timeline instance, which also gc's fine.

 

I don't expect the user to ever go through 5,000 hands, though they might, it's a training app for casino staff and is intended for mobile deployment. The problem is solved with clear(), I just found it very odd how copy/pasting the same tweenmax lines so that it would add the two tweens say 2-3 times that belong to that same target was causing a large memory increase, the amount did change based on the target however as I mentioned I switched my card sprite for an empty sprite(starling sprites mind you). So I can only assume it's holding the targets in memory, but why would the memory increase if the tweens are exactly the same to the same target? A tween itself shouldn't have that much of a memory footprint right?

 

 

Tweens do, of course, have a reference to the target instance, so if you're expecting to gc targets who are referenced inside of tweens that you're keeping around (either by maintaining a reference yourself or putting them inside a timeline that you keep a reference to), that can't happen (nor should it). 

 

As far as I know all references were cleared. And that simply turning paused from true to false at the start of the loop caused gc to work fine. Again the amount of instances in this case is intentionally high from doing a loop 5,000 times where each loop can add up to 12 tweens per timeline (of which there are two). If I could restart individual tweens without causing other tweens on the timeline to play with it I think I could use just a single timeline.

 

My GSAP files were downloaded roughly a month ago, I could download again and see if the problem persists, although I have a working solution now if you like I can try sort you out an isolated project that demonstrates the issue. 

Link to comment
Share on other sites

There's a lot here that I'm still scratching my head about, and it's tough to diagnose without seeing your FLA but let me try to address a few things...

 

You said "I invalidated to set the targets properties to the starting scale/alpha values" but I think you're misunderstanding what invalidate() does. Actually, let me take a step back...when a tween renders for the first time, it records the starting and ending values so that it can interpolate between then during the tween. And of course it must remember the starting value so that if you restart() or jump to an earlier spot, it knows where to go. Sometimes, however, a developer manually changes a value and wants to run the tween again, but have it start fresh, like:

 

//start at x:0
mc.x = 0;
//now tween to x:100
var tween:TweenLite = TweenLite.to(mc, 1, {x:100});
//then later, after the tween completes, we'll move mc.x to 500
mc.x = 500;
//now if we simply restart() the tween, it'll jump back to 0 and animate to 100 again
tween.restart();
//but if we invalidate() first, the tween flushes the recorded starting values and will tween from wherever it is now (500) to the destination (100)
mc.x = 500;
tween.invalidate();
tween.restart();

It sounded like you thought invalidating a tween caused it to render its starting values or something. It does nothing of the sort - it just flushes recorded values (and doesn't even render). It waits until the tween is asked to render again (maybe because of a restart() or a seek() or whatever) and then it'll record the starting values. 

 

--

 

As far as your performance optimization with the loop, no, I think you actually degraded performance. Function calls are on of the most expensive operations in ActionScript and you should avoid them if you can. Putting a function call inside of a 5000-iteration loop is generally not a good idea if there's any way you can inline that code. 

 

Also, declaring your variables outside the function makes them slightly slower to access because local variables are always fastest. Sure, you're technically creating a temporary spot in memory for that local variable, but it gets flushed as soon as the function is done running (virtually inconsequential). 

 

--

 

It sounds like maybe one of the issues had to do with the fact that you were creating 50,000+ tweens that referenced as many Sprites, and if the tween (or their parent timelines) were paused, they didn't have a chance to complete and thus become available for garbage collection. That's the correct behavior, by the way - you wouldn't want your tweens/timelines getting gc'd from under you. Adobe's Tween class has that problem and I can't tell you how many people ran amuck because of that (their tweens would literally just stop randomly because they got gc'd). And of course if the tweens are referencing Sprites, the Sprites can't be gc'd either (again, the correct behavior). 

 

You said that calling clear() on the timelines solved the problem for you which seems to confirm what I'm saying here - that you had a bunch of tweens referencing Sprites that you wanted gc'd but you never let the tweens run and expire and become available for gc, but clearing them manually accomplished exactly that. 

 

And no, tweens themselves wouldn't take up nearly that much memory (although it does sound like you were creating a pretty crazy number of instances, so there's surely a memory hit there). Another reason TweenNano took less time to create in your loops is because you weren't creating TimelineMax instances either and dropping them into those. You were likely creating half as many instances overall. Plus you weren't using TweenMaxVars for every one either. 

 

--

 

You said "If I could restart individual tweens without causing other tweens on the timeline to play with it I think I could use just a single timeline." Did you think that restarting one tween would cause others to play? If so, that's not true. 

 

Does that help clear things up? If you still think there's a problem with GSAP, I'd definitely like to see a sample FLA that we can publish on our end to see the problem. We're eager to squash any bugs that exist as quickly as possible. 

Link to comment
Share on other sites

I guess I misunderstood invalidate(), I've removed it but noticed I'm getting an issue if I interrupt the timeline.

 

First I'll bring up again that I'm not doing a for loop on a function 5,000 times design wise, I have a newGame() function that resets variables to starting values and builds the tweens on the timeline. To check that I had no memory issues I added the for loop and ran the function 5,000 times to avoid clicking a button that triggers newGame() manually.

 

If I comment out the invalidate() line, when I run my  code I see the animation play perfectly fine, if I press the button that runs newGame() while a tween is running on the timeline, when the timeline is cleared and the new tweens added for the next set of cards to animate that specific point in time where the previous tween was interrupted, the new tween in it's place does not seem to appear, but every other tween in the sequence worked fine. I tried this with different parts of the sequence and it was always missing the tween where I interrupted previously. Perhaps the alpha or scale value for that tween was at 0 and didn't tween to 1 when newGame() cleared the timeline and added a set of new tweens for the new sprite graphics. So I'm not sure what invalidate() does in this case that avoids that visual error, but it works and if that avoids any visual error I'm all for it.

 

The newGame() function clears both timelines(autoTimeLine with a stagger of 0.3 and controlledTimeLine with a stagger of 1), it also performs removeChildren(0,-1,true) on the container sprite for my card graphics, in starling this is meant to perform dispose on the graphics which should free them up for gc, I also null the array and create a new one with "cardArray=[]" that stores the graphics that buildTween() uses to provide tween targets. There is a TweenMax.killAll() in there as well, though since I am no longer using tweenMax perhaps that is now useless.

 

I've just added to newGame() after the timeline.clear() timeline = new timelineMax({paused:true}). This also fixes the issue like invalidate() was doing. Perhaps you can provide some more insight, still more than happy to put together an isolated example and if it reproduces the problem send it off to you. I know that I previously encountered an issue with restart() on a tween if it had a delay where the tween only moved back a few frames/moment in time rather than restarting completely. I tested it on a non-starling project and didn't encounter the error so it's possible any other issues I'm experiencing could be due to my use of starling/feathers/stage3D?

 

As for the first issue we were discussing, it definitely seems like the starling sprites were the cause of the bulk of memory and weren't able to be gc'd due to the orphaned paused timelines that still had tweens targeting them. I just found it odd that if I copy/pasted the same line that created a tween with the same target, that the size continued to go up, as if it was adding a copy of the sprite or something else was going on that was increasing the memory.

 

5,000 iteration loop aside, I'll move the variables that are only used by my buildTween function into the function. I'm still pretty new to how to optimize code.

 

Is there a better solution to restarting individual tweens than using a dictionary? Each newGame() will create 4-6 card graphics to be tweened based on the top 6 card values of a deck. At the moment I'm using:
 

tweenLiteInstance = controlledTimeline.seek(drawCount).tweenFromTo(controlledTimeline.time(), controlledTimeline.getLabelAfter())
drawCount++

 

The sequence will always be drawn in the order it was built, for that timeline the tweens are 0.5 and have been staggered by 1 second, the label is just a string of the iteration in the buildTween() loop as provided above. Though using that code on the autoTimeLine with the stagger of 0.3 would cause other tweens to popup as they overlap and if taking manual input should only display one at a time. Using a dictionary I could just use:

tweenDictionary[String(drawCount)].restart()
drawCount++

 

The only problem I have with that is that each card graphic has two tweens as my alpha and scale have different eases(wanting alpha to be 1 before the bounce of the back ease on scale happens).

 

Sorry about the huge amount of text, I really appreciate your support and hope to purchase a greensock license later in the year. If you need an example for any of the discussed issues, I work solely in FlashDevelop so I have no .fla file, I could provide a .zip of a project folder instead?

Link to comment
Share on other sites

Just in case you're wondering why I set tweenLiteInstance to the timeline animation call, from what I understand the fromTo creates a tweenLite instance and I was experiencing a problem where I was getting unintended animation on my sprite graphics while another timeline was running, storing the instance and killing it fixed the issue.

Link to comment
Share on other sites

Yeah, I'm having a really hard time understanding these text descriptions of things (sorry - could just be my foggy brain lately). Please do create a very simple example and post it here so that I can publish on my end and see exactly what's happening. Comments in the code would be great too so that I can get acclimated. Please include all dependencies (including starling if you're using it) so that I can just crack it open and hit publish.

 

Thanks!

Link to comment
Share on other sites

Ok have put together a sample file that demonstrates the issues we've talked about. It's the full project folder for flashdevelop though perhaps all you need is the src folder. Startup is the document class.

 

http://www.filedropper.com/greensockexample

 

So the original problem was just caused by timeline = new timelinemax({paused:true}) where the previous was still paused and had no variable name referencing it but held references to the tween targets as you mentioned earlier. So that is sorted by using clear() instead of creating a new timeline instance.

 

There is an example of the visual error I experience if I don't use invalidate() and another of memory increase when I repeatedly add the same tween/tween target. Code has plenty of comments, if you could explain the issue I have if I don't invalidate() that'd be great. I'm pretty sure it has something to do with having two timelines, where one has the tween targets active and the other has the same tween targets but paused.

Link to comment
Share on other sites

Thanks for creating the sample file(s). I can see better what's happening.

 

The memory increase looks very normal to me, and it was caused by the way you set things up. In your master loop (mainFunction()), you were calling a function 500 times, and each time through that function would create 3 Quads and then create up to 9 tweens for each of those (27 total). Then you had an "extra" timeline that duplicated all the animation stuff. You were creating references to those Quads by targeting them with paused tweens. Then you'd create a new array each time through, so by the end of your 500 loops, you had 1500 Quads referenced by 27,000 tweens inside 1000 timelines! No wonder memory usage shot up. And like I said, since you had paused the timelines, none of their tweens could expire and gc.

 

It makes perfect sense that clearing the timelines would release the memory (from the tweens and the Quads).

 

There was a bug introduced in version 12.0.3 that was affecting the fromTo() tweens (sorry about that). It should be resolved in the upcoming 12.0.4 release which you can preview here (attached).

 

To summarize, the memory issue is unrelated to GSAP, and the fromTo()/invalidate() thing was a bug that's resolved.

 

Does that clear things up for you?

12.0.4_AS3_preview.zip

Link to comment
Share on other sites

Yeah I cleared it up earlier with you that it was due to me not clearing the timelines as they were paused. The 500 loop is not a part of my actual code, it was just to see the memory increase even though I'm sure I was disposing of everything for gc correctly minus the solution commented in the code that you gave me earlier.

 

So the invalidate thing was a bug, well that's good to know :) Cheers for the preview. One last thing, if I have the following setup:

timeline_main(has same tweens/targets, stagger 0.3)

timeline_extra(has same tweens/targets, stagger 1)

Then timeline_main.restart(), the tweens play through the sequence, if after that I call:

timeline_main.pause();timeline_extra.pause("2")

 

I notice that for timeline_extra's timeline all it's tweens up to that label are updated to what they should look like at that point in time. The tweens that would play after that point in time though have not reset their targets alpha/scale to 0, so...before "2" all tweens are executed/paused at that point in time, but any after that which have not started are not run at all?

 

Can you explain this? If I set timeline_main.pause(0) instead, then all tweens are reset to the starting alpha/scale in the fromTo. Does the timeline_main have more influence? Or is it to do with the timing of the tweens from different stagger values. Is there a way to control the rendering of these timelines? Such as just rendering what tweens are active/placed at a specific time on the timeline, instead of going through and rendering/executing the previous tweens. Likewise can I reset the tween targets to the state they all started in where immediateRender:true set the scale and alpha values to 0, if I set the timeline_main to 0 the initial alpha/scale are set to what the from values in the tweens were, but not when I set timeline_extra to 0.

 

If that's also troubling to take in I can create another example project demonstrating the issue and current solution. I might be using timelines wrong or it may be part of the bug that was fixed in your upcoming release which I haven't tried yet.

 

Cheers for all the help, hugely appreciated.

 

EDIT: I can confirm that it's not related to the fixed bug, most likely I am doing something wrong. If I play timeline_extra from 0 it will not update the tween targets to alpha/scale 0 until it reaches that point in time unlike timeline_main(both setup the same way via buildTween() function).

Link to comment
Share on other sites

Yeah, I had a very hard time following the text description, so my recommendation would be to:

  1. Try the preview. Maybe it'll fix what you were asking about, in which case we don't need to waste any time looking into it. 
  2. If the preview doesn't fix it, then please create a very simple example that demonstrates what you're talking about so that I can publish and see it on my end. 

In case it helps, let me explain how things render inside timelines. When the playhead moves to a new position, the timeline figures out which tweens need to render and which ones don't, and it'll trigger the ones that need updates. Everything happens in order, too, so if you jump forward 10 seconds, it will render the tweens between the old time and new time in the order they occur in the timeline. If you jump backwards, it'll do the same, but in reverse order so that everything renders as it should. This should be seamless to you - it isn't something you should have to worry about at all. You should be able to skip around to any spot, backwards or forwards, and it will render things correctly. If that's not what you're seeing in the preview of 12.0.4, I'd definitely like to see an example so that we can identify any potential bugs, but I'm pretty confident things are rock-solid (famous last words, right?).

Link to comment
Share on other sites

Ha, ok well I think your explanation clears it up. Below is roughly what I was doing with my code, from what I gather about the rendering, in this case I need to reset timeline_1 with pause(0) rather than just pause().

 

var timeline_1:TimelineLite = new TimelineLite({paused:true})
var timeline_2:TimelineLite = new TimelineLite({paused:true})

buildTween(timeline_1, 0.3) //adds tweens to target objects with a stagger of 0.3
buildTween(timeline_2, 1)   //adds tweens to the same target objects with a stagger of 1

//These two tweens are added for each target object to the timelines sent to the buildTween function:
/*
var staggerValue:Number = i * _stagger
_timeline.add(String(i), staggerValue)
.fromTo(cardArray[i], 0.5, { alpha:0 }, { alpha:1, immediateRender:true, ease:Power1.easeOut }, staggerValue)
.fromTo(cardArray[i], 0.5, { scaleX:0, scaleY:0 }, { scaleX:1, scaleY:1, immediateRender:true, ease:Back.easeOut }, staggerValue)
*/

//After tweens have been built, I start the first one
timeline_1.restart()

//Time passes, say 5 seconds a button is pressed that calls the following:

timeline_1.pause()//reset the timeline with timeline.pause(0) and the problem below doesn't occur, as the playhead has reversed all the tweens setting the alpha/scale values back to 0.
timeline_2.pause(2.2) //timeline_2 has done it's rendering with the playhead from "0"(initial paused state) to "2.2", it is unaware that the targets have had their alpha and scale values altered but resets them when the fromTo tween starts on the timeline? 

 

In another case I used a tween to control a starling movieclip currentFrame property instead of controlling it with starlings juggler. I had it trace the frame number it was changing and noticed when the tween reached the end as it would go back to the first frame the traced numbers went backwards eg("frame1","frame2","frame3","frame2","frame1").

 

Now that I know how the rendering works I understand why that is happening. Would be great if I could avoid that behaviour for that case though so it was telling the movieclip class to update the frame as the playhead moved back to 0 decreasing the currentFrame property.

 

Is there some sort of book/resource out there to learn about all this? I guess that's what the forums are for :P

Link to comment
Share on other sites

It seems like there are a lot of things being mixed together here. Let me try to address a few that I was able to discern:

  1. No, you do not need to jump back to the beginning before jumping forward to another spot in a timeline. For example, if a 10-second timeline has finished playing and you want to jump to the 2-second spot, you don't need to pause(0) before you pause(2). You can simply pause(2) or seek(2). 
  2. Keep in mind that fromTo() and from() tweens are unique because immediateRender is true by default, meaning they render their beginning values immediately when the tween is created regardless of when the tween is scheduled to actually run. That's a one-time convenience (the initial set).
  3. If you jump to an earlier spot in a timeline, it won't cause the tweens to iteratively set their values multiple times backwards. It just sets the values once, right away. You said something about a MovieClip frame going backwards gradually, like frame3, frame2, frame1 - was that just when you did a seek() to a new spot? So, for example, if you have a tween that animates the MovieClip's frame from 1 to 60 over the course of 1 second and it finishes (at frame 60 of course) and then you seek(0.5), the MovieClip will instantly jump to frame 30 (not frame59, frame58, frame57...frame30).

As far as where to learn all this stuff, we really try to provide solid docs (http://api.greensock.com/as/) as well as learning resources (http://www.greensock.com/learning/) and there are quite a few tutorials on the web. There are some books that cover some basics, but nothing that goes deep (that I know of at least). If you have specific questions, these forums are tough to beat. 

 

Happy tweening!

Link to comment
Share on other sites

I think with my example I should have stayed with the names timeline_main, timeline_extra instead of 1/2. I had the tweens and the targets on two timelines, just with different staggered values. That's why I had a problem with rendering. I don't recall the fromTo causing an immediateRender:true without declaring it, it might have been part of the bug? I'll give it a go shortly.

 

 

The movieclip having its frame property tweened looks like this:
 

TweenMax.to(movieclipObj,1,{currentFrame:movieclipObj.numFrames,ease:Linear.easeNone,repeat:-1})

 

And testing it doesn't produce the error that I had mentioned, I think I was using a timeline initially like I described earlier, will try to see if I can get the old behaviour back. This one traces the currentFrame property being set with the same value about 6 times, the animation is only 8 frames, is there a way to only have the tween update the property when the currentFrame increments? I'm guessing it's sending a number to the setter which converts the value to int.

 

 

Cheers.

Link to comment
Share on other sites

In recent versions of GSAP, fromTo() has immediateRender:true - maybe you had an old version. 

 

As for the frame tween, yes, the way you wrote it would indeed cause TweenMax to set currentFrame to values that very likely had decimals, and then Starling was rounding for you internally. You could resolve that by using roundProps, like roundProps:"currentFrame" but if you want to only set the value when it's new, you'd need to create a proxy and check it each time it gets updated, like:

 

var frameProxy:Object = {frame:movieclipObj.currentFrame};
TweenMax.to(frameProxy, 1, {frame:movieclipObj.numFrames, ease:Linear.easeNone, repeat:-1, onUpdate:updateFrame});
function updateFrame():void {
    var frame:int = (frameProxy.frame + 0.5) >> 0; //much faster than Math.round()
    if (frame != movieclipObj.currentFrame) {
          movieclipObj.currentFrame = frame;
    }
}

But frankly, if it were me I'd probably just add roundProps:"currentFrame" to your original tween because it doesn't cost much to have it set the value a few extra times during the tween, and it would keep your code more concise. 

Link to comment
Share on other sites

If the starling movieclip class converts the number to int when the tween sends the value then what difference would roundProps offer?

 

The immediateRender:true was required, tried it out with the latest GSAP release I had which had the invalidate()/fromTo bug, but with the pre-release 12.04 you provided immediateRender:true is no longer needed.

 

So with the two timelines with the same tween targets being tweened, is it best to pause(0) the timeline I'm not going to actively be working with when I switch to using the other timeline? (example above in reply #13, timeline_1 & timeline_2) Or is there a better way to handle different sequences on the same targets?

Link to comment
Share on other sites

If Starling is rounding the currentFrame correctly now anyway, then there isn't any compelling reason to use roundProps. 

 

And yes, if you have 2 timelines that are controlling the same properties of the same objects, you should typically pause() one before you play/resume the other because otherwise you may run into an overwrite scenario that kills one of the tweens (you don't want tweens fighting each other for control of the same properties of the same object). 

Link to comment
Share on other sites

I do pause() the timeline, I was asking if there was a better option than pause(0). If I just pause() and then manipulate the 2nd timeline like in the example in reply #13, then the tween targets don't reset to initial values that I set in my fromTo tweens.

 

Is there a way to reset the tween targets to what they should be on the timeline I'm manipulating? Or is pause(0) on the previous timeline the best way to go about it like mentioned in the example in reply #13?

Link to comment
Share on other sites

You're asking how to revert things to an earlier state, right? If so, yes, seek(0) or pause(0) or time(0) or totalTime(0) would all make the values go back to what they were at that point in the timeline (the start). If you just pause(), that doesn't change the values - it just stops them where they currently are (actually, it just stops updating them - it doesn't actually lock them down somehow and prevent you from changing them any other way).

 

Does that answer your question?

Link to comment
Share on other sites

Err not exactly. I get that. I keep trying to point out with the last few posts that I'm dealing with two seperate timelines, I'm going to paste the code again from above.

 

var timeline_1:TimelineLite = new TimelineLite({paused:true})
var timeline_2:TimelineLite = new TimelineLite({paused:true})

buildTween(timeline_1, 0.3) //adds tweens to target objects with a stagger of 0.3
buildTween(timeline_2, 1)   //adds tweens to the same target objects with a stagger of 1

//These two tweens are added for each target object to both timeline_1 and timeline_2 inside the buildTween() function:
/*
var staggerValue:Number = i * _stagger
_timeline.add(String(i), staggerValue)
.fromTo(cardArray[i], 0.5, { alpha:0 }, { alpha:1, ease:Power1.easeOut }, staggerValue)
.fromTo(cardArray[i], 0.5, { scaleX:0, scaleY:0 }, { scaleX:1, scaleY:1, ease:Back.easeOut }, staggerValue)
*/

//After tweens have been built, I start the first one
timeline_1.restart()

//Time passes, say 5 seconds a button is pressed that calls the following:

timeline_1.pause()//reset the timeline with timeline.pause(0) and the problem below doesn't occur, as the playhead has reversed all the tweens setting the alpha/scale values back to 0.
timeline_2.pause(2.2) //timeline_2 has done it's rendering with the playhead from "0"(initial paused state) to "2.2", it is unaware that the targets have had their alpha and scale values altered but resets them when the fromTo tween starts on the timeline?

 

 

So before I manipulate either of the paused timelines, no tween targets are visible, all have scale and alpha set to 0 from the fromTo tweens. When I play timeline_1, if I then pause() it without returning the playhead to 0 reverting to the original state, when I then manipulate timeline_2 such as timeline_2.pause(2.2), then the tween targets that had their alpha/scale values set to 1 from timeline_1 will not reset to their property values to 0. Only the tweens that occur from timeline_2's starting time of 0 when it was paused on creation to the newly paused time of 2.2 will be affected.

 

So I have the present solution of "timeline_1.pause(0)" , then timeline_2 will be accurate visually with it's tween targets.

 

Perhaps I should make an example project?(Pretty much the same as the code sample above but you'd visually see what I'm trying to describe)

Link to comment
Share on other sites

Yep, I see exactly what you're saying (I think). It sounds like I must not be explaining myself very well if you're still unsure. Let me try again a different way...

 

A tween records its starting values when the tween actually begins (essentially when its parent timeline's playhead touches it). Otherwise, it would be virtually impossible to accommodate sequences properly. Anyway, let's visualize the following simple sequence:

 

var t1:TimelineLite = new TimelineLite({paused:true});
var t2:TimelineLite = new TimelineLite({paused:true});

buildTweens(t1);
buildTweens(t2);

function buildTweens(tl):void {
    tl.fromTo(mc, 1, {x:0}, {x:400});
    tl.fromTo(mc, 1, {y:0}, {y:400});
}

t1.play();

//after 3 seconds, we'll pause the first timeline and play the 2nd. 
TweenLite.delayedCall(3, function():void {
    t1.pause();
    t2.play(0);
});

We're just tweening mc.x from 0 to 400, and then doing the same thing to mc.y. So when the first timeline finishes, mc.x and mc.y will be 400. Then we unpause the 2nd timeline and its playhead starts advancing. It runs the x tween fine, but remember, mc.y is still 400 because that's where the first timeline left it. There's a 1 second delay before the y tween starts rendering, so what we'll see is mc.y staying at 400 during the x tween (we're talking about the 2nd timeline of course) and then as soon as mc.x finishes tweening, mc.y will jump up to 0 and tween back down to 400 (because we're doing a fromTo() tween). This is all expected behavior. The y tween shouldn't run when you didn't ask it to - it should wait until its scheduled time (except for the immediateRender which occurs when you create the tween). 

 

So if you want to revert the positions/values that were altered by the first timeline, you should indeed pause(0) before you begin the 2nd timeline. 

 

Does that clarify things?

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