Flash - Play movie clip in reverse? - actionscript-3

I'm trying to get a movie clip to play in reverse when I mouse_out from it (it plays on mouse_over).
My actionscript is as follows:
mc.stop();
mc.addEventListener(MouseEvent.MOUSE_OVER,mover);
mc.addEventListener(MouseEvent.MOUSE_OUT,mout);
function mover(e:MouseEvent):void
{
mc.play();
}
function mout(e:MouseEvent):void
{
//Play in reverse
}
How would I achieve this?
Thanks

The best way would be to use an ENTER_FRAME event listener. Basically this is what you want to do
function mover(e:MouseEvent):void {
stopPlayReverse();
mc.play();
}
function mout(e:MouseEvent):void {
this.addEventListener(Event.ENTER_FRAME, playReverse, false, 0, true);
}
function playReverse(e:Event):void {
if (mc.currentFrame == 1) {
stopPlayReverse();
} else {
mc.prevFrame();
}
}
function stopPlayReverse():void {
if (this.hasEventListener(Event.ENTER_FRAME)) {
this.removeEventListener(Event.ENTER_FRAME, playReverse);
}
}
This would play your MovieClip in reverse until it hits frame 1, then it will stop.

If the motion allows, you can use a Tween (for example if you want to change the alpha, location or scale). On the MouseOut you can call .yoyo() for the Tween, which will play it in reverse.
Something like this:
var tween:Tween;
mc.addEventListener(MouseEvent.MOUSE_OVER,mover);
mc.addEventListener(MouseEvent.MOUSE_OUT,mout);
function mover(e:MouseEvent):void
{
tween = new Tween(obj, "alpha", None.easeNone, 1, 0, 1, true);
}
function mout(e:MouseEvent):void
{
tween.yoyo();
}

TweenLite.to(mc, 2, {frame:1});

If your tween is not all that serious you can literally make a whole new set of frames in reverse and just play it from that keyframe.
That's the poor man's reverse tween.

By using a boolean which works as a trigger and Event.ENTER_FRAME, you can do the following to reverse frames:
//Boolean and Event.ENTER_FRAME
var reversing:Boolean = false;
AddEventListener(Event.ENTER_FRAME, reverse);
function reverse(e:Event){
if(reversing)
{
//mc is displaying previous frame every frame
mc.prevFrame();
//until the currentFrame is 1
if(mc.currentFrame == 1)
reversing = false;
}
}
Your //Play in reverse would set reversing = true;

You can do it passing the movie clip object to find the correct object to reverse. This manner helps you to use with the child you want. You can get it with:
fMoveBack(this.getChildByName("my_clip"));
function fMoveBack(my_clip:MovieClip):void {
this.addEventListener(Event.ENTER_FRAME, playReverse(my_clip));
}
function playReverse(mc:MovieClip):Function {
return function playReverse(e:Event):void {
if (mc.currentFrame == 1) {
stopPlayReverse(mc);
} else {
mc.prevFrame();
}
};
}
function stopPlayReverse(mc:MovieClip):void {
if (this.hasEventListener(Event.ENTER_FRAME)) {
this.removeEventListener(Event.ENTER_FRAME, playReverse);
}
}

Related

AS3 - How to get function to run after currentFrame updates?

I have 2 copies of a MovieClip (mcA) on my main timeline. Within mcA, I have 5 more MovieClips (mcB) and this code:
addEventListener(MouseEvent.CLICK, clickedPoint);
function clickedPoint(e:MouseEvent) {
e.target.play();
setStat(e.target.parent);
}
So I toggle the frame of the mcB that was clicked, and I run a function that references the corresponding mcA on the main timeline.
In setStat, I call another function that checks the currentFrame of all the mcBs in the mcA.
getPoints(stat) {
var points = 0;
for(var i = 1; i <= 5; i++)
{
if(stat["pnt"+i].currentFrame == 2) points++;
}
trace(points);
return points;
}
My problem is that the setStat function seems to run before the currentFrame of the mcB that has been clicked on updates.
How should I change my code so that the mcB that is clicked on registers as having changed its currentFrame when I call setStat?
You could call setStat() after the next frame update. A simple way to do this is to add an ENTER_FRAME event handler which removes itself when first invoked:
function clickedPoint(e:MouseEvent) {
e.target.play();
e.target.addEventListener(Event.ENTER_FRAME, function(e:Event):void {
e.target.removeEventListener(Event.ENTER_FRAME, arguments.callee);
setStat(e.target.parent);
});
}
You can encapsulate this behavior in a function that behaves like setTimeout:
function callNextFrame(target:DisplayObject, callback:Function, ...params:Array):void {
target.addEventListener(Event.ENTER_FRAME, function(e:Event):void {
target.removeEventListener(Event.ENTER_FRAME, arguments.callee);
callback.apply(null, params);
});
}
// Usage:
callNextFrame(e.target as DisplayObject, setStat, e.target);

Flash Game ArgumentError: Error #2025 removeChild

I'm trying to get the bat character to remove the jack/2/3 child(s) in my game here, but I keep getting the ArgumentError: Error #2025. I understand that I may be removing a child twice, perhaps? I'm looking around and I'm not really experienced in this stuff so I'm having a hard time understanding what needs to be done to fix this issue. Can someone tell me what needs to be done with my code specifically, please?
var jack:pumpkin = new pumpkin();
var jack2:pumpkin = new pumpkin();
var jack3:pumpkin = new pumpkin();
var score:Number = 0;
scoreBox.text = String(score);
addChild(jack);
jack.x = 125;
jack.y = 285;
addChild(jack2);
jack2.x = 270;
jack2.y = 310;
addChild(jack3);
jack3.x = 445;
jack3.y = 285;
stage.addEventListener(KeyboardEvent.KEY_DOWN, moveLeft);
stage.addEventListener(KeyboardEvent.KEY_DOWN, moveRight);
stage.addEventListener(KeyboardEvent.KEY_DOWN, moveDown);
stage.addEventListener(KeyboardEvent.KEY_DOWN, moveUp);
stage.addEventListener(KeyboardEvent.KEY_UP, bump);
function moveLeft(e:KeyboardEvent):void {
if (e.keyCode == 37) {
bat.x -= 5;
}
}
function moveRight(e:KeyboardEvent):void {
if (e.keyCode == 39) {
bat.x += 5;
}
}
function moveDown(e:KeyboardEvent):void {
if (e.keyCode == 40) {
bat.y += 5;
}
}
function moveUp(e:KeyboardEvent):void {
if (e.keyCode == 38) {
bat.y -= 5;
}
}
function bump(e:KeyboardEvent):void {
stage.addEventListener(Event.ENTER_FRAME, bumpIt);
function bumpIt(e:Event):void {
if (bat.hitTestObject(jack)) {
stage.removeEventListener(Event.ENTER_FRAME, bumpIt);
removeChild(jack);
score++;
scoreBox.text = String(score);
}
if (bat.hitTestObject(jack2)) {
stage.removeEventListener(Event.ENTER_FRAME, bumpIt);
removeChild(jack2);
score++;
scoreBox.text = String(score);
}
if (bat.hitTestObject(jack3)) {
stage.removeEventListener(Event.ENTER_FRAME, bumpIt);
removeChild(jack3);
score++;
scoreBox.text = String(score);
}
}
}
Due to the nested bumpit() event handler, on every key up you're adding another enter frame event if your hit-test has no collision.
On KeyboardEvent.KEY_UP, event handler calls bump() which adds an Event.ENTER_FRAME listener that will call bumpIt().
If bat.hitTestObject() is true, you remove Event.ENTER_FRAME.
If not, you still have the Event.ENTER_FRAME listener firing bumpIt() every frame.
So, every key up you're potentially adding another frame handler.
If ten key up events occurred and none of them hit test your objects, you are now calling bumpIt ten times a frame.
If you need to hit test on key up, just put the logic there:
stage.addEventListener(KeyboardEvent.KEY_UP, bump);
function bump(e:KeyboardEvent):void {
if (bat.hitTestObject(jack)) { /* ... */ }
}
Or, if you're tracking an animation sequence after key up, maybe add some state variable, such as:
var isFlying:Boolean = false;
stage.addEventListener(KeyboardEvent.KEY_UP, bump);
function bump(e:KeyboardEvent):void {
// If bat is already flying, don't add another frame handler
if (isFlying)
return;
// Otherwise, indicate bat is now flying and add frame handler
isFlying = true;
stage.addEventListener(Event.ENTER_FRAME, bumpIt);
}
Then, if your hit-test works and you remove your frame handler, reset the state variable:
stage.removeEventListener(Event.ENTER_FRAME, bumpIt);
isFlying = false;
Another solution is to remove the nested handlers. Because you have nested bumpIt() inside bump(), you are seeing cumulative firing of callbacks due to scope:
function bump():void {
function bumpIt():void { /* ... */ }
}
Simply promote bumpIt():
function bump():void { /* ... */ }
function bumpIt():void { /* ... */ }

ActionScript 3.0 - 2 gotoAndPlay() commands in one function

I have the following Adobe Flash (ActionScript 3.0) movie:
When a button is pressed I want to play frame 17 to 24, and after this, I want to go back and play frame 10 to 16 in the same animation. I've tried something like this but unfortunately doesn't works:
button.addEventListener(MouseEvent.CLICK, buttonClick);
function buttonClick(event:MouseEvent):void{
gotoAndPlay(17);
gotoAndPlay(10);
}
In other short words: after gotoAndPlay(17); I want to gotoAndPlay(10);
Thanks for your attention!
Try this:
stop();
// Properties.
var queue:Array = [];
var currentBlock:Point;
// Queue a section of timeline to play.
function queueBlock(start:int, end:int):void
{
queue.push(new Point(start, end));
}
addEventListener(Event.ENTER_FRAME, enterFrame);
function enterFrame(e:Event):void
{
if(!currentBlock)
{
if(queue.length > 0)
{
// Select and remove first block to play.
currentBlock = queue[0];
queue.splice(0, 1);
gotoAndPlay(currentBlock.x);
}
}
else
{
play();
if(currentBlock.y == currentFrame)
{
// Got to the end of the block, end it.
currentBlock = null;
stop();
}
}
}
Which will let you do this:
// Demo:
queueBlock(17, 24);
queueBlock(10, 16);

Flash AS3 Press and Hold Button

I'm no expert in Flash but I found a way in AS2 to make a "press and hold" button. Now I'm working with AS3 and I'd like this code to be converted to AS3. Can someone help ?
stop();
function startTimer(mc, conversionTime) {
mc.onEnterFrame = function() {
if ((getTimer() / 1000) - conversionTime > 1) {
delete this.onEnterFrame;
gotoAndStop(3);
}
};
}
button1.onPress = function() {
var conversionTime:Number = getTimer() / 1000;
startTimer(this, conversionTime);
this.onRelease = function() {
if (this.onEnterFrame != null) {
gotoAndStop(2);
}
delete this.onEnterFrame;
};
};
Thanks !
In AS3 it would look like this:
mc.addEventListener(MouseEvent.MOUSE_DOWN, _mouseDown);
var myTimer:Timer = new Timer(5000,1);
myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, _buttonPressedEnoughLong);
private function _mouseDown(e:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, _mouseUp);
myTimer.start();
}
private function _mouseUp(e:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, _mouseUp);
myTimer.reset();
}
private function _buttonPressedEnoughLong(e:TimerEvent) : void {
e.currentTarget.reset();
// Do stuff
}
You need to hold button 5 seconds, before event will fire.
Change mc.onEnterFrame = function() ... to:
mc.addEventListener(Event.ENTER_FRAME, onEvent);
function onEvent(e:Event)
{
if ((getTimer() / 1000) - conversionTime > 1)
{
this.removeEventListener(Event.ENTER_FRAME, onEvent);
gotoAndStop(3);
}
}
Change button1.onPress = function() ... to:
button1.addEventListener(MouseEvent.MOUSE_DOWN, onBtnDown);
function onBtnDown(e:MouseEvent)
{
var conversionTime:Number = getTimer() / 1000;
startTimer(this, conversionTime);
function onBtnUp(e:MouseEvent)
{
if (this.hasEventListener(Event.ENTER_FRAME))
{
gotoAndStop(2);
this.removeEventListener(Event.ENTER_FRAME, onEvent);
}
}
}

Actionscript 3 mouse_over play movie, mouse_out reverse movie

I'm trying to make some flash buttons with a mouse_over animation that plays in reverse on mouse_out. Now I have it working for one of my three movie clip instances.
I am using e.currentTarget.play() instead of having a function for each movie clip, but how do I do the same for my playReverse function? I tried putting e.currentTarget.prevFrame() instead of mc1.prevFrame() but it did not work. My code is as follows:
mc1.addEventListener(MouseEvent.MOUSE_OVER,mover);
mc2.addEventListener(MouseEvent.MOUSE_OVER,mover);
mc3.addEventListener(MouseEvent.MOUSE_OVER,mover);
mc1.addEventListener(MouseEvent.MOUSE_OUT,mout);
mc2.addEventListener(MouseEvent.MOUSE_OUT,mout);
mc3.addEventListener(MouseEvent.MOUSE_OUT,mout);
function mover(e:MouseEvent):void {
stopPlayReverse();
e.currentTarget.play();
}
function mout(e:MouseEvent):void {
this.addEventListener(Event.ENTER_FRAME, playReverse, false, 0, true);
}
function playReverse(e:Event):void {
if (mc1.currentFrame == 1) {
stopPlayReverse();
} else {
mc1.prevFrame();
}
}
function stopPlayReverse():void {
if (this.hasEventListener(Event.ENTER_FRAME)) {
this.removeEventListener(Event.ENTER_FRAME, playReverse);
}
}
Any idea how I can fix this?
Your function playReverse only use mc1 how can it work with the others movie clip.
If you choose to do it that way you can keep a track of the current MovieClip playing in reverse.
You will have to add more logic if you want that the play in reverse always finish when passing over one clip to another.
var currentMovieClip:MovieClip=null;
function mout(e:MouseEvent):void {
var mc:MovieClip = e.currentTarget as MovieClip;
if (mc !== null) {
currentMovieClip = mc;
this.addEventListener(Event.ENTER_FRAME, playReverse, false, 0, true);
}
}
function playReverse(e:Event):void {
if (currentMovieClip==null) {
return;
}
if (currentMovieClip.currentFrame == 1) {
stopPlayReverse();
} else {
currentMovieClip.prevFrame();
}
}
Another way that implies that you can have each clip to finish their play in reverse
function mover(e:MouseEvent):void {
stopPlayReverse(e.currentTarget as MovieClip);
e.currentTarget.play();
}
function mout(e:MouseEvent):void {
var mc:MovieClip = e.currentTarget as MovieClip;
if (mc !== null) {
mc.addEventListener(Event.ENTER_FRAME, playReverse, false, 0, true);
}
}
function playReverse(e:Event):void {
var mc:MovieClip = e.currentTarget as MovieClip;
if (mc.currentFrame == 1) {
stopPlayReverse(mc);
} else {
mc.prevFrame();
}
}
function stopPlayReverse(mc:MovieClip):void {
if ((mc!==null) && mc.hasEventListener(Event.ENTER_FRAME)) {
mc.removeEventListener(Event.ENTER_FRAME, playReverse);
}
}