Slow Down Playback of a MovieClip - actionscript-3

I am trying to gradually slow down a movie clip using Actionscript 3. My current code plays the movie clip and then abruptly stops and ticks ahead a few frames. A much rougher look than I want.
var t:Timer=new Timer(2000,1);
t.addEventListener(TimerEvent.TIMER,slowDown);
t.start();
function slowDown(e:TimerEvent):void {
if (currentFrame==totalFrames) {
gotoAndStop(1);
} else {
gotoAndStop(currentFrame+1);
}
}
Is the Timer class at least the right direction? Thanks.

Sounds to me like you want to employ the power of a Tweening Engine - there are quite a few of them out there, but my favourite is Greensock TweenMax.
The following code will tween the playhead of a MovieClip gradually slowing down (easing) as it nears the end of playback:
import com.greensock.*;
import com.greensock.easing.*;
TweenMax.to(myMovieClip, 2, { frame: myMovieClip.totalFrames, ease: Expo.easeOut });

If you just want a simple ease to a known location you can use this on enterframe:
speed = 0.2; // Somewhere between 0 and 1
x = (targetX - x) * speed;
You can change targetX when ever you like, and it will just ease to the value. You can do this for any property.

Related

"Smooth and Regular" scroll in flash

I am working on a news ticker in Flash AS3. The code is reading some RSS from CNN and generates a MovieClip with headline text one after another. Now this movieclip starts scrolling from right to left. For scrolling I am using TweenLite. I don't want any easing, just want a regular and smooth scrolling.
I have used both options:
TweenLite.to(news_mc, 60, {x:minX} );
and
TweenLite.to(news_mc, 60, {x:minX, ease:Linear.easeNone} );
But, in both case, the animation is not smooth. It starts scrolling speedily and at last it becomes very slow.
I've seen something similar to this. Are you implementing your TweenLite call in a loop? You should only be calling for a tween on the target object once. Only once that tween is finished or you want a brand new tween on that object should you call TweenLite.to with that target object again.
Seeing as how you're only after a linear tween, would it not be simpler to simply increment/decrement the target's X every frame? Something like this:
this.addEventListener(Event.ENTER_FRAME, onEnterFrame)
private function onEnterFrame(e:Event):void
{
if(news_mc.x > minX)
{
news_mc.x -= 3 //This is a shot in the dark, tweak this for your values
}
else
{
news_mc.x = maxX
}
}

Ways to animate bezier curves with AS3?

I've been trying to find the best way to animate bezier curves with AS3. By this far following has been the best solution:
import flash.display.*;
import flash.display.Sprite;
import flash.geom.*;
import com.greensock.TweenMax;
import com.greensock.easing.*;
public class Waves extends MovieClip
{
public var piste:Number = stage.stageHeight;
public var piste2:Number = 0;
var a:Sprite = new Sprite();
var coord:Vector.<Number> = new Vector.<Number>();
var com:Vector.<int> = new Vector.<int>();
public function Waves()
{
addChild(a);
coord.push(0, 30);
com.push(1);
coord.push(260, piste, stage.stageWidth, 30);
com.push(3);
tweenNumbers();
}
public function tweenNumbers():void {
TweenMax.to(this, 0.45, {piste:piste2, repeat:-1, yoyo:true, immediateRender:true, ease:Expo.easeOut, onUpdate:draw});
}
public function draw():void {
coord[3] = piste;
a.graphics.clear();
a.graphics.lineStyle(1,0x990000,1);
a.graphics.drawPath(com, coord);
}
}
Do I really have to use graphics.clear to animate curves? Is there more efficient way? If I tween faster than 1 second, rendering lags and you can see the previous line, is there way to get rid of it?
Hmm. Perhaps you should post your used version of TweenMax to properly debug the issue. There seem to be several of them, some use asynchronusly dispatched "update" events, some employ an enterframe listener, thus making sure each update routine is called each frame. So, graphics jittering can occur in an asynchronus scenario.
On the other questions:
Yes, you have to redraw the graphics object in question, this involves calling graphics.clear(). See, the Graphics object is a blackbox entity, you can't directly reach a control point of a curve to tween it somehow. So, in order to change a point on a curve, you have to redraw it.
A more efficient way would be emulating a tween on your Sprite directly, via an enterframe listener and a function similar to Strong.easeOut used in tweening to interpolate coordinates. You will then get rid of the all extra framework included in TweenMax library and will get full control of the event and code flow. This, however, is some work to both emulate yoyo behavior, time setting behavior, framerate behavior (you can switch to "time=frame" approach, eliminating one of the issues) and easing behavior. The tweenNumbers will look like this:
var isYoyo:Boolean=false;
var currentFrame:int;
var maxFrame:int;
function easingFunction(frame:int,maxframe:int,a:Number,b:Number):Number {
var x:Number=Number(frame)/maxframe;
return a+(b-a)*(x*x*(3-2*x)); // 3x^2-2x^3, a double-easing Perlin function
// recreate your needed function here!
}
var piste1:Number=0; // storing start coordinate
private function tweenNumbers():void {
maxFrame=Math.round(0.45*stage.frameRate); // from seconds to frames
currentFrame=0;
isYoyo=false;
a.addEventListener(Event.ENTER_FRAME,onUpdate);
}
private function onUpdate(e:Event):void {
if (!isYoyo) {
currentFrame++;
if (currentFrame==maxFrame) isYoyo=true;
} else {
currentFrame--;
if (currentFrame==0) isYoyo=false;
} // advance time
coords[3]=easingFunction(currentFrame,maxFrame,piste1,piste2);
// tween the coords[3] manually
a.graphics.clear();
a.graphics.lineStyle(1,0x990000,1);
a.graphics.drawPath(com, coord);
// draw updated path
}
No guarantee of desynching, though, but will normally work. Also a desynch (seeing previous line) can possibly happen if you have set stage framerate too high, so the video subsystem of a target device can't draw as many frames at once.

Changing individual movieclip's frame rate with TweenMax

My aim is to change the frame rates of my individual (looping) movie clips through clickable controls (slow/med/fast). I've heard it isnt possible to achieve this through as3/flash alone, so I've tried greensock's TweenMax... However I can't seem to figure out how to do this. Is there anyone that could help?
box1.addEventListener(MouseEvent.MOUSE_DOWN, box1down);
function box1down(event:MouseEvent):void {
//FRAMERATE CODE HERE
}
Many thanks!
Here is the API doc for TweenMax: http://www.greensock.com/as/docs/tween/com/greensock/TweenMax.html
If you have multiple movieclips that you are trying to control, you can just create an abstract class with the functionality you want and extend that class. So something like:
public class ControlledMovieClip extends MovieClip {
public function ControlledMovieClip() {
stop();
}
public function animate(frameRateInSeconds:Number):void {
TweenMax.to(this, frameRateInSeconds, { frame: this.totalFrames - 1, repeat: -1, ease: Linear.easeNone });
}
}
Have all your movieclips that are looping extend that class, and then you could call the animate function on the objects in your box1down event handler.
I haven't tested that code so you might need a gotoAndStop(1) at the end of each iteration.
It's possible through Actionscript alone it just requires you to handle the frame progression yourself (instead of using mc.play() you stop the movieclip and call nextFrame() yourself).
Lets say a Movieclip (myMC) has 20 frames of animation. To manually run the animation at normal speed you simply call myMC.nextFrame(); on every frame of your project (using an ENTER_FRAME listener for example).
To have the animation run at half speed you can use a frame count and a frame trigger:
var frameTick = 0;
var frameAnimTrigger = 2;
function Update(e:Event):void
{
frameTick++;
if(frameTick == frameAnimTrigger)
{
myMC.nextFrame();
frameTick = 0;
}
}
Because nextFrame is only called every other frame the animation appears to run at half speed.

Action Script 2 Suggestion

I am doing a project which is about interacting, mouse on screen, Hence, I want to do it by using Adobe Flash Pro and Action Script2.
here is the Task:
- a simple animations (for example: that full of spiders walking/jumping from up to down on the screen)
- once the mouse moves, the animation will Reverse (all spiders animation will reverse back and hide back to the top of screen from the place that the came).
- if the mouse doesn't move after 60 Seconds the animation will happen again till the mouse move again on the screen (Those spiders animation will happen again).
i have created a Animation Spider "Movie clip" (spider animation going down)
1- what script i should write to make animation reverse?
2- how can i tell Adobe my mouse is moved or it's not moving, so the spiders animation will happen or reverse?
by the way, I am a very beginner in action script 2.0
i appreciate any suggestion and help *is fine for me to do it in action script 3 too
Thanks.
Oh my. AS2 :)
OK first off I think it would be easier if you would create 2 different animations. One for the Spider to walk down. The other one to walk up. It is possible to reverse a MovieClip but I think if you`re a beginner, stick with the basics.
You need 3 thinks here.
1) Spider Clips. Going down and up.
2) An interval (timer in AS3)
var interval:Number = setInterval(spidersComeOut, 60 * 1000);
3) Mouse move listener
root.onMouseMove = function()
{
//swap your spider clips
//move the spider up again
//reset the interval with clearInterval(interval) and restart it again.
}
This is a very basic handler for mouse move.
Hope this will help you a little bit. This is not a complete solution. It will not work out of the box.
One thing at the end. If you are new to AS2 I would recomend to give as3 a shot. It is more difficult to start with, but there are more people out there willing to help with an AS3 problem then with as2.
Since you said you were ready to use AS3 here is solution.
I assume you have a separate movie clip containing your spiders animation which you place on the main timeline/stage.
1.place your MovieClip on the stage and give it the instance name of 'spiders'.
2.inside this MovieClip, on the first frame put this code (it will handle revesing the animation)
import flash.events.Event;
stop();
var _dir:int = 1;
addEventListener(Event.ENTER_FRAME, onEF);
function onEF(e:Event):void
{
getNextAnimationFrame();
}
function getNextAnimationFrame():void
{
var frameNum:int = currentFrame + _dir;
if (frameNum < 1 || frameNum > totalFrames)
{
removeEventListener(Event.ENTER_FRAME, onEF);
}
frameNum = Math.max(1, Math.min(totalFrames,frameNum));
gotoAndStop(frameNum);
}
function changeDirection($dir:int):void
{
_dir = $dir;
removeEventListener(Event.ENTER_FRAME, onEF);
addEventListener(Event.ENTER_FRAME, onEF);
}
3.on the main timeline (in the first frame) put this code:
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.MouseEvent;
var timer:Timer = new Timer(60 * 1000, 1);
timer.start();
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onTime);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
function onTime(e:TimerEvent):void
{
trace("it's time");
spiders.changeDirection(1);
}
function onMove(e:MouseEvent):void
{
timer.reset();
timer.start();
spiders.changeDirection(-1);
}
It would be possible to handle mouse, timer and animation in one piece of code, however the way it's build now is kind of OOP, if at some point you decided to build it properly it would be extremely easy to 'rewrite' this code as separate classes.

AS3 - Using Tween on integer?

Not been using the Tween functions before, so I'd like a little help.
I want to tween between two integers.
Example:
I buffer 360 frames (images).
I want to skip to frame 100 (from frame 1), but I want to use ease to make it look better.
All I need is to tween an integer that I will use for the current image displayed.
So far so good, but I'm not getting how to update my image in the tween:
public function timerEvent(event:TimerEvent):void{
TweenLite.to(this, 2, {_currentFrame: 50, ease:Strong.easeOut});
if (_currentFrame>=358) _currentFrame -= 359;
if (_currentFrame<0) _currentFrame += 359;
var myBitmap:Bitmap = new Bitmap(buffer[_currentFrame+1]);
myBitmap.smoothing = true;
imageBuffer.data = myBitmap;
}
I would seriously recommend using Greensock's TweenLite and TweenMax libraries over the built in Tweening functions.
http://www.greensock.com/tweenmax/
The beauty of these is that you can tween any numeric property of an object, and apply easing, and you can even tween frames of a MovieClip directly by using the Frames plug that is built into TweenMax:
import com.greensock.TweenMax;
import com.greensock.easing.Strong;
TweenMax.to(this,2,{frame:100,ease:Strong.easeOut});
To Tween a counter value is just as easy, and because it doesn't require the Frames plugin you can use the lighter TweenLite:
import com.greensock.TweenLite;
import com.greensock.easing.Strong;
var counter:int = 0;
TweenLite.to(this,2,{counter:100,ease:Strong.easeOut});
Edit to include new code
As the tween runs you can capture an update event which lets you perform actions on the current values of your parameters. You could then do something like this:
TweenLite.to(this, 2, {_currentFrame: 50, ease:Strong.easeOut, onUpdate:updateCallback});
function updateCallback():void
{
var myBitmap:Bitmap = new Bitmap(buffer[_currentFrame+1]);
myBitmap.smoothing = true;
imageBuffer.data = myBitmap;
}