Actionscript 3.0 Movieclip modification on EXIT_FRAME - actionscript-3

I have this baffling problem with Flash AS3 that I have been attempting to solve for a long time. I have a notion that perhaps this is a bug with the flash player, but perhaps you can shed some insight.
I have a MovieClip in Flash that is a star for 10 frames, a circle for another 10, and then a square for another 10, after which it will gotoAndPlay(1), replaying the animation. This MovieClip extends an AS3 class I have called FlipClip.
FlipClip has a function in it called reverseClip. This function's purpose is to flip certain graphic children around an axis every time Flash launches the EXIT_FRAME event.
public function FlipClip()
{
//as soon as this is instantiated, add the eventListener
addEventListener(Event.EXIT_FRAME,flipTheClip);
}
public function flipTheClip(e:Event)
{
trace("currentFrame = " + currentFrame);
//for sake of simplicity, we will flip every child
for (var i=0; i<numChildren; i++)
{
var targetClip = getChildAt(i);
var axis = 10;
//if the target child has not already been flipped...
if (Math.abs(targetClip.scaleX) / targetClip.scaleX != -1)
{
//reverse the child's direction with scaleX and move based on the axis
targetClip.scaleX *= -1;
var dist:Number = targetClip.x - axis;
targetClip.x = axis - dist;
}
}
}
The obvious outcome is that every time we exit a frame, all of the graphic elements are flipped horizontally around x=10, and every ten frames the shape of the MovieClip changes from a star, to a circle, to a square. Right?
Nope.
The MovieClip does successfully flip around that axis, but then a strange problem occurs. The animation stops. The MovieClip is stuck as an eternal star. And Flash doesn't even recognize that the animation has stopped, as we get this output over and over;
currentFrame = 1
currentFrame = 2
currentFrame = 3
currentFrame = 4
...
currentFrame = 30
currentFrame = 1
All the way up to 30, at which point it goes back to one. The clip is still playing, but somehow the graphic elements are not updating!
Is this a problem with the flash player? Is this a problem with the code? Any help is appreciated!
I've uploaded the files for the .fla and .as on dropbox. I'm still figuring out how to embed something like that, but for now I'm gonna hope this link works for you.
https://www.dropbox.com/sh/hcljutesblichpp/AABKQ4Kn8OTwfTaeh0I3nnOZa?dl=0
UPDATE:
If I convert every individual shape into a MovieClip within the parent MovieClip, it plays correctly. However, this is not very memory efficient or feasible with complex animations. Hopefully this bit of information can help you solve the problem.

There are couple of thing which you need to take care.
You don't need to flip element based on the numChildren as it always
return 1 as on each frame you will get single children.
you also don't need to do the check another condition
Math.abs(targetClip.scaleX) / targetClip.scaleX != -1 to set the
flip.
And also you need to use ENTER_FRAME instead of EXIT_FRAME.
ENTER_FRAME works for the current frame whereas EXIT_FRAME works for
previous frame.
Use the below code.
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.utils.setTimeout;
public class FlipClip extends MovieClip
{
var mInstance
var prevX;
public function FlipClip()
{
//as soon as this is instantiated, add the eventListener
addEventListener(Event.ENTER_FRAME,flipTheClip);
mInstance = this;
//mInstance.visible = false;
}
public function flipTheClip(e)
{
this.scaleX *= -1;
prevX = this.x;
if(this.scaleX < 0)
this.x = prevX + this.width
else
this.x = prevX - this.width
}
}
}
Paste above code in FlipClip.as file and change the frame rate to 1.
You need to update the moviClip placement based on your requirement.
Hope above answer solve your problem.

You need to remove listener for EXIT_FRAME before playing animation. Also you are Flipping your movieClip here but not adding any code for playing it.
Paste below code in your FlipClip.as file.
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.utils.setTimeout;
public class FlipClip extends MovieClip
{
var mInstance
public function FlipClip()
{
//as soon as this is instantiated, add the eventListener
addEventListener(Event.EXIT_FRAME,flipTheClip);
mInstance = this;
mInstance.visible = false;
}
private function playallAnimation()
{
this.gotoAndPlay(1);
}
public function flipTheClip(e)
{
removeEventListener(Event.EXIT_FRAME,flipTheClip);
//for sake of simplicity, we will flip every child
for (var i=0; i<numChildren; i++)
{
var targetClip = getChildAt(i);
var axis = 10;
//if the target child has not already been flipped...
if (Math.abs(targetClip.scaleX) / targetClip.scaleX != -1)
{
//reverse the child's direction with scaleX and move based on the axis
targetClip.scaleX *= -1;
var dist:Number = targetClip.x - axis;
targetClip.x = axis - dist;
}
}
setTimeout(function()
{
mInstance.visible = true;
playallAnimation();
},200);
}
}
}
Hope this will work for you.

Related

TouchEvent.TOUCH_BEGIN, onTouchBegin Freezes after several Reloads

I am building an Adobe Air AS3 IOS and Android App, in which i have a movie clip in the center of the stage. When you start touching this movie clip, you can move it all around the stage.
This is how i'm doing so :
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
MC_M1.alpha = 1;
MC_M1.addEventListener(Event.ENTER_FRAME, ifHitAct);
MC_M1.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
MC_M1.x = 0.516 * gameIntro.stageWidthToUse;
MC_M1.y = 0.75 * gameIntro.stageHeightToUse;
MC_M1.height = 0.2 * gameIntro.stageHeightToUse;
MC_M1.width = MC_M1.height / 1.4;
gameIntro.STAGE.stage.addChildAt(MC_M1,1);
function onTouchBegin(event:TouchEvent)
{
trace("TouchBegin");
if (touchMoveID != 0)
{
trace("It Did Not");
return;
}
touchMoveID = event.touchPointID;
gameIntro.STAGE.stage.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
gameIntro.STAGE.stage.addEventListener(TouchEvent.TOUCH_END, onTouchEnd);
}
function onTouchMove(event:TouchEvent)
{
if (event.touchPointID != touchMoveID)
{
return;
}
//trace("Moving")
MC_M1.x = event.stageX;
MC_M1.y = event.stageY;
}
function onTouchEnd(event:TouchEvent)
{
if (event.touchPointID != touchMoveID)
{
return;
}
//trace("Ending");
touchMoveID = 0;
gameIntro.STAGE.stage.removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
gameIntro.STAGE.stage.removeEventListener(TouchEvent.TOUCH_END, onTouchEnd);
}
When the player actually looses the game, what i am actually doing is the following :
MC_M1.removeEventListener(Event.ENTER_FRAME , ifHitAct);
MC_M1.removeEventListener(TouchEvent.TOUCH_BEGIN , onTouchBegin);
gameIntro.STAGE.stage.removeChild(MC_M1);
MC_M1.alpha = 0;
isDead = 1;
replayButToUse.x = 0.127 * gameIntro.stageWidthToUse;
replayButToUse.y = 0.91 * gameIntro.stageHeightToUse;
replayButToUse.addEventListener(MouseEvent.CLICK, gotoIntro);
This is all happening in a class called : introClassToUse.
So when the users looses, he will get a replay button, and when he clicks it, he will go back to the same class and reload everything, using the following code :
function gotoIntro(event:MouseEvent):void
{
replayButToUse.removeEventListener(MouseEvent.CLICK, gotoIntro);
replayButToUse.alpha = 0;
replayButToUse.removeEventListener(MouseEvent.CLICK, gotoIntro);
stop();
var reload:introClassToUse = new introClassToUse();
}
And so everything loads back up and the game restarts. My problem is, i'm facing a very weird behavior when i tend to replay the game more than 2-3 times. The MC_M1 just stops listening to any touch event, but keeps on listening to ENTER_FRAME events, in which i keep touching the MC_M1 but it seems to not respond to it. I even debugged it remotely from my iPhone, for the first couple of replays, i can see the trace("TouchBegin"); with it's outcome, it was showing me TouchBegin, but after a few replays, the touch events just froze. What am i missing?
Any help is really appreciated, i'm new in AS3, i need to learn so i could manage more
Edit 1 :
I have no code on any frame, i just have lots of AS Classes.
The fla file is linked to an AS Class called gameIntro. In this class, i have linked the following :
- STAGE is an object of type Stage.
- gameIntro.STAGE = stage
Later on, when the user clicks a play button, i call the class introClassToUse. This class has all the game functionalities. All the code present above is in introClassToUse. When the user looses and clicks the replay button, he will go to "goToIntro" function, im which i recall the introClassToUse.
It's all working fine, with several other timers implemented and all, the only problem is that after several replays, the MC_M1 just freezes over
I am removing the MC_M1 each time the user looses and re-add them when i call back the introClassToUse, because i tried to use the .visible property, it didn't work at all ( this is why i am using the gameIntro.STAGE.stage.removeChild(MC_M1)
I know the question is old but maybe someone is still wondering what is going on here (like me).
There are lot of problems in you code but I thing the root of your problem starts here:
function gotoIntro(event:MouseEvent):void{
//...
var reload:introClassToUse = new introClassToUse();
}
It is usually unwanted behavior if simply creating an instance does more than nothing to your program and you don't even need to assign it to variable in this case.
You mentioned this code is located in your introClassToUse class. This basically means that you are creating new instance of your game inside old one and this seem to be completely awry.
You should consider using only instance properties in your class definition and create new introClassToUse() in external classes;
You didn't include many important details about your code like
How the whole class structures look like - for example you can't place line like MC_M1.addEventListener(Event.ENTER_FRAME, ifHitAct);in the scope of your class so obviously you have this in some function and we don't know when and from where it is called.
Where and how your variables are declared, and assigned. It's hard to tell if your MC_M1 is property of an instance or a class, is it internal/public/private/...
Do you link library symbols to your classes or acquire it from stage.
There could be many things that could give you such result. Based on what you wrote I've reproduced behavior similar to what you've describe but using mouse event and a dummy loose condition. This ends the game each time you drop the mc partially outside right edge of the sage, show restart button and starts again if you click it (basically it's mostly your code). It works fine for about 10s and than suddely you can't move the mc anymore. The frame event is still tracing out but touch/mouse is not.
How can it be? I suspect that you could remove only listeners somewhere and have invisible mc stuck on the new one. And this could be easy overlooked, especially if you using static properties. Again we don't even know where is your movie clip coming from so we can only guess what is happening whit your code but I've tried to take the example simple this is how I did it. The problem may lay in some completely different place but you can guess for all scenarios.
Document class of the project - GameIntro.as
package
{
import flash.display.Sprite;
public class GameIntro extends Sprite
{
//Document class. this need to be compiled with strict mode off.
public function GameIntro() {
GameIntro.STAGE = stage;
GameIntro.stageWidthToUse = stage.stageWidth;
GameIntro.stageHeightToUse = stage.stageHeight;
var intro:IntroClassToUse = new IntroClassToUse();
stage.addChild(intro);
}
}
}
IntroClassToUse.as
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.utils.Timer;
/**
* You need to have library symbol linked to this class in .fla with two mcs -
* mcFromLibrarySymbol (dragable) and repButton (reapatButton)
*/
public class IntroClassToUse extends MovieClip
{
var t = 0; //timer ticks
var fc:uint = 0; //frames counter
var isDead = 0;
var mc;
static var repButton;
var logicContex:Timer = new Timer(30);
public function IntroClassToUse() {
trace("toUse", GameIntro.stageWidthToUse);
mc = mcFromLibrarySymbol;
if(!repButton) repButton = repButtonX;
logicContex.addEventListener(TimerEvent.TIMER, logicInterval);
logicContex.start();
init();
}
internal function init() {
trace("init");
mc.alpha = 1;
mc.addEventListener(Event.ENTER_FRAME, onFrame);
mc.addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
mc.x = 0.516 * GameIntro.stageWidthToUse;
mc.y = 0.75 * GameIntro.stageHeightToUse;
mc.height = 0.2 * GameIntro.stageHeightToUse;
mc.width = mc.height / 1.4;
GameIntro.STAGE.stage.addChildAt(mc, 1);
}
internal function onLoose() {
trace("onLoose");
mc.removeEventListener(Event.ENTER_FRAME , onFrame);
mc.removeEventListener(MouseEvent.MOUSE_DOWN, onMDown);
GameIntro.STAGE.stage.removeChild(mc);
mc.alpha = 0;
isDead = 1;
repButton.x = 0.127 * GameIntro.stageWidthToUse;
repButton.y = 0.91 * GameIntro.stageHeightToUse;
repButton.addEventListener(MouseEvent.CLICK, onReplay);
repButton.alpha = 1;
}
internal function onReplay(e:MouseEvent):void {
trace("onReplay");
repButton.removeEventListener(MouseEvent.CLICK, onReplay);
repButton.alpha = 0;
stop();
new IntroClassToUse();
}
internal function onMDown(e:MouseEvent):void {
trace("mouseDow");
GameIntro.STAGE.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMMove);
GameIntro.STAGE.stage.addEventListener(MouseEvent.MOUSE_UP, onMUp);
}
internal function onMMove(e:MouseEvent):void {
mc.x = e.stageX;
mc.y = e.stageY;
}
//you loose the game if you release you mc with part of it over rigth stage edge.
internal function onMUp(e:MouseEvent):void {
trace("mouseUp");
GameIntro.STAGE.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMMove);
GameIntro.STAGE.stage.removeEventListener(MouseEvent.MOUSE_UP, onMUp);
trace("Stage:", GameIntro.STAGE.numChildren);
if (mc.x + mc.width > GameIntro.STAGE.stageWidth) onLoose();
}
internal function onFrame(e:Event):void {
trace("frames", fc++);
}
internal function logicInterval(e:TimerEvent):void {
if (t++ < 300 || !isDead) return;
init();
mc.alpha = 0;
mc.removeEventListener(MouseEvent.MOUSE_DOWN, onMDown);
isDead = 0;
}
}
}

Keeping Object in Stage-Flash

I am making a game for my class which is similar to Space Invaders/Galaga. I'm new to ActionScript and coding really, I have created an enemy class for which I have it spawn and then move in the x direction. I'm just wondering how I would go about having my enemy move down after it has reached the end of my stage which is 700x500 and then proceed to go to other side, I'm assuming planting an if statement in my enemy class, just unsure on how to go about it, any help will do, much appreciated guys.
Enemy Class
package
{
import flash.display.MovieClip;
public class Enemy extends MovieClip
{
public function Enemy()
{
x = 60;
y = 30;
}
public function moveDownABit():void
{
}
public function moveRight():void
{
x = x + 2;
}
public function moveDown():void
{
}
public function moveLeft():void
{
}
public function moveUp():void
{
}
}
}
Game
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
public class SpaceVigilanteGame extends MovieClip
{
public var enemy:Enemy;
public var avatar:Avatar;
public var gameTimer:Timer;
var gameWidth:int = 0;
var gameHeight:int = 0;
public function SpaceVigilanteGame()
{
enemy = new Enemy();
addChild( enemy );
avatar = new Avatar();
addChild( avatar );
gameWidth = stage.stageWidth;
gameHeight = stage.stageHeight;
gameTimer = new Timer( 25 );
gameTimer.addEventListener( TimerEvent.TIMER, moveEnemy );
gameTimer.start();
}
public function moveEnemy( timerEvent:TimerEvent ):void
{
//enemy.moveDownABit();
if(enemy.x+enemy.width+2<=gameWidth)
{
enemy.moveRight();
}
else if(enemy.y+enemy.height+2<=gameHeight)
{
enemy.moveDown();
}
else if(enemy.x-2>=0)
{
enemy.moveLeft();
}
else if(enemy.y-2>=0)
{
enemy.moveUp();
}
}
}
}
This is pretty basic stuff.
Lets assume you have 4 functions in your Enemy class, moveDown, moveUp, moveRight and moveLeft.
We need to know the width and height of the area the Enemy will move around in, either by hardcoding (will bite you in the butt later on, possibly) or by doing it more dynamic like this:
var gameWidth:int = stage.stageWidth;
var gameHeight:int = stage.stageHeight;
stage.stageWidth or its Height counterpart will give you the size of your SWF movie in pixels, with scaling and so on.
You already have a Timer set up in your Document Class, every 80ms the function moveEnemy will get executed. An alternative approach is to use Event.ENTER_FRAME and execute a function every frame.
Now think about it, every time your function gets called, the enemy will move down a bit. As you said, there should be some kind of...checking mechanism. But we shouldn't put it in the Enemy class, the Enemy doesn't need to know when to stop, that's the problem of the Document class. Ideally, you should be able to use that Enemy in every sort of Class, right? So giving the Enemy boundaries will just be a lot of work when the Document Class could do it instead.
The solution is very easy, you need to check the position of your enemy against the dimensions of your stage every time you want to move your Enemy.
Essentially:
private var gameWidth:int = 0;
private var gameHeight:int = 0;
public function SpaceVigilanteGame(){
//...your init code for enemy
gameWidth = stage.stageWidth;
gameHeight = stage.stageHeight;
//...your timer code
}
public function moveEnemy(timerEvent:TimerEvent):void{
//lets first check if we can go to the right
if(enemy.x+enemy.width+2<=gameWidth){
//so, we take the right outermost border of your enemy by taking its x-position and adding its width. To check if a step right would be out of bounds, we add the amount it WOULD move
//as an example, your enemy has the x-position 100, and is 200 pixel wide, is 100+200+2 smaller or equal to 700 (your stage width)? Yes it is, thus you can move it
enemy.moveRight();
}
else if(enemy.y+enemy.height+2<=gameHeight){
//but what happens if we can't go right? we jump to this additional if condition that will check if the enemy can move down
//same thing as above, but instead we use y-position and the heights
enemy.moveDown();
}
else if(enemy.x-2>=0){
//if we can't move right or down, try left instead
//this time we only need the x-position of the enemy, because we need to look at the leftmost border
enemy.moveLeft();
}
else if(enemy.y-2>=0){
//same deal with going up
enemy.moveUp();
}
}
This is untested code, but I hope you're getting the general gist of this example. The problem here is though that the Enemy will always attempt to move right first. When you start at x:0,y:0 he will move right until he hits the end, then move down until he hits an end, then move left and right alternatively forever.
Movement 101:
If you want to move to the right x = x + 1
If you want to move to the left x = x - 1
If you want to move up y = y - 1
If you want to move down y = y + 1

How to stop a movieClip from playing in Flash CS6 AS3 (with Box2D)

I've spent 14 hours on this problem. This is a basic collision checker that sets a MovieClip animation to play when a collision occurs. The clip is
currentBallObject.clip.
It works. The clips plays. But it repeats over and over.
private function checkCollisions():void
{
var i = balls.length;
while (i--)
{
var currentBallObject = balls[i];
if (currentBallObject.contact)
{
//condition hits ground
if (currentBallObject.ground)
{
currentBallObject.body.SetPosition(new b2Vec2(currentBallObject.startX / PIXELS_TO_METRE, currentBallObject.startY / PIXELS_TO_METRE));
currentBallObject.body.SetLinearVelocity(new b2Vec2(0, 0));
currentBallObject.body.SetAngularVelocity(0);
//currentBallObject.texture.pop();
}
else // it hit player
{
// assign clip texture to current position
currentBallObject.clip.x = currentBallObject.body.GetPosition().x * PIXELS_TO_METRE;
currentBallObject.clip.y = currentBallObject.body.GetPosition().y * PIXELS_TO_METRE;
// whisk old object away
currentBallObject.body.SetPosition(new b2Vec2(currentBallObject.startX / PIXELS_TO_METRE, currentBallObject.startY / PIXELS_TO_METRE));
currentBallObject.body.SetLinearVelocity(new b2Vec2(0, 0));
currentBallObject.body.SetAngularVelocity(0);
currentBallObject.contact = false;
}
}
}
}
I added this code to delete the MovieClip or somehow get rid of it after it has played through once. (42 frames). I also tried to add a frameListener and at least a dozen other suggestions. When I add
stop()
The animation doesn't play. It just loads the last frame. The code I have now is:
private function updateClips():void
{
var i = balls.length;
while (i--)
{
var currentBallObject = balls[i];
if(currentBallObject.clip)
{
var frame:int = currentBallObject.clip.currentFrame;
//trace(currentBallObject.clip.currentFrame);
if(frame == 42)
{
currentBallObject.clip._visible = false;
currentBallObject.clip.removeMovieClip();
currentBallObject.clip.enabled = -1;
}
}
}
}
I've tried counting the frames, putting it a run-once function, a frame exit listener, I am out of ideas. I just want to make a MovieClip run one time through. I also tried putting stop() in the timeline and then the animation didn't play. It just loaded the last frame.
Right now the collisions work but the animations stay on the screen forever, looping forever.
Edit: I got the code by Patrick to run without errors.
I added the event listener with the others like this:
_input = new Input(stage);
...
addEventListener(Event.ENTER_FRAME, oEF);
addEventListener(Event.ENTER_FRAME, update);
time_count.addEventListener(TimerEvent.TIMER, on_time);
time_count.start();
}
And then created a function:
private function oEF(e:Event):void{
var i = balls.length;
while (i--)
{
var currentBallObject = balls[i];
if (currentBallObject.clip.currentFrame >= currentBallObject.clip.totalFrames)
{
currentBallObject.clip.stop();
currentBallObject.clip.removeEventListener(Event.ENTER_FRAME, oEF);
if (currentBallObject.clip.parent) currentBallObject.clip.parent.removeChild(currentBallObject.clip);
}
}
}
But I still get the same problem as any other result. The MovieClip disappears on contact without the animation happening.
Through debugging I've learned more. The value of currentFrame starts off going 1-40 then stays at 40 for the rest of the execution.
So the MovieClip is always on the last frame for every object.
if clip is a MovieClip then you can use clip.totalFrames in an enterframe listener.
function oEF(e:Event):void{
if (this.currentFrame >= this.totalFrames){
this.stop();
this.removeEventListener(Event.ENTER_FRAME, oEF);
if (this.parent) this.parent.removeChild(this);
}
}
this.addEventListener(Event.ENTER_FRAME, oEF);
I figured it out.
if (currentBallObject.clip.currentFrame == currentBallObject.clip.totalFrames)
{
trace("Frame before kill: ", currentBallObject.clip.currentFrame);
currentBallObject.clip.x = 0;
currentBallObject.clip.y = 0;
}
The above block goes right after
var currentBallObject = balls[i];
It checks if the movieClip is on the last frame and then gets rid of the clip by setting clip.x & clip.y to 0. I could find no other way to stop the movie in this particular case.

AS3 gotoAndStop causes object to remove itself

I have a student who is working on a Tower Defense game in AS3 and has an issue that has stumped me. He is using hitTestObject to change the direction that a movieClip is moving. The movieClip has its own timeline with frames for the different directions that the object is facing and a linked .as file with the code for the behavior of the object.
When he calls gotoAndStop to change the internal frame of the movieClip, the removed event is triggered, but the object stays on the screen and no longer moves.
All of my searches find answers about removing objects, but I have not seen anything about preventing an object from removing itself.
The following code is a loop triggered by an ENTER_FRAME event in the .as class file for the movieClip object:
private function eFrame(event:Event):void
{
if (_root.isPaused == false)
{
//MOVING THE ENEMY
this.x += speed * xDir;
this.y -= speed * yDir;
if (health <= 0)
{
_root.currency += 4;
this.parent.removeChild(this);
}
if (this.x > 770)
{
this.parent.removeChild(this);
_root.health -= 10;
_root.gotHit = true;
}
//checking if touching any invisible markers
for (var i:int=0; i<_root.upHolder.numChildren; i++)
{
//the process is very similar to the main guy's testing with other elements
var upMarker:DisplayObject = _root.upHolder.getChildAt(i);
if (hitTestObject(upMarker))
{
yDir = 1;
xDir = 0;
this.gotoAndStop(3);
}
}
for (i=0; i<_root.downHolder.numChildren; i++)
{
//the process is very similar to the main guy's testing with other elements
var downMarker:DisplayObject = _root.downHolder.getChildAt(i);
if (hitTestObject(downMarker))
{
yDir = -1;
xDir = 0;
this.gotoAndStop(7);
}
}
for (i=0; i<_root.rightHolder.numChildren; i++)
{
//the process is very similar to the main guy's testing with other elements
var rightMarker:DisplayObject = _root.rightHolder.getChildAt(i);
if (hitTestObject(rightMarker))
{
yDir = 0;
xDir = 1;
this.gotoAndStop(6);
}
}
for (i=0; i<_root.leftHolder.numChildren; i++)
{
//the process is very similar to the main guy's testing with other elements
var leftMarker:DisplayObject = _root.leftHolder.getChildAt(i);
if (hitTestObject(leftMarker))
{
yDir = 0;
xDir = -1;
this.gotoAndStop(2);
}
}
}
}
private function remove(event:Event):void
{
trace("remove");
removeEventListener(Event.ENTER_FRAME, eFrame);
_root.enemiesLeft -= 1;
}
}
When the gotoAndStop line executes, the frame of the movieClip changes and then the code jumps directly to a function that is triggered by the REMOVED event.
Does anyone have an idea why the REMOVED event might be triggered by this code?
Thank you for your help.
The REMOVED Event is triggered by anything that is removed from the stage inside the MovieClip or Sprite that is containing it, if I'm not mistaken. And especially with MovieClips that have animation, things get removed and added everytime, for instance if some part of the animation ends on the timeline, or at keyframes.
Event.REMOVED_FROM_STAGE is dispatched only when the container itself is removed from stage. Maybe that's causing your confusion? I can't see from your code example exactly what event type you're listening for.
Where are you adding the remove-listener?
Without more information, I would guess that you are listening to a clip inside an animation, and that it's not there on all frames (or, maybe even more likely - that the instance is being swapped out for another, identical one, by flash pro. This can happen depending on in what order you added keyframes, the alignment of the moon and fluctuations in the ionosphere. It's easiest fixed by simply removing all key-frames and then re-creating them. And then never using flash pro for anything ever again.)

How can I use Action Script 3.0 to make random placed Symbols fly by?

I'm trying to make a simple animation with Flash CS4 and Action Script 3.0 to make a number of Symbols fly by from right to left constantly. What I want is that once a symbol has reached the end of the screen it is destroyed and another one is placed at the start position.
I intend to give each symbol a random speed and create a random symbol each time one is 'destroyed'. Any clues where I can start?
As you seem new to flash as a platform I would think writing classes shouldn't be your first port of call when learning ActionScript. Definitely just play about on the timeline for now and learn the basics. As very simple solution to this, I would suggest creating a MovieClip in the library with a class name like 'MyBall'... then paste this onto the first frame of the main timeline et voila.
// Create some variables to store data
var numberOfBalls : int = 20;
var myBalls : Array = [];
var xVelocities : Array = [];
var maxXVelocitySpeed : Number = 5;
var minXVelocitySpeed : Number = 2;
// Add your orginal balls to the stage
for (var i : int = 0; i < numberOfBalls; i++)
{
var myBall : MyBall = new MyBall();
myBall.x = -(Math.random() * stage.stageWidth);
myBall.y = Math.random() * stage.stageHeight;
var xVelocity : Number = minXVelocitySpeed + (Math.random() * (maxXVelocitySpeed - minXVelocitySpeed));
myBalls.push(myBall);
xVelocities.push(xVelocity);
addChild(myBall);
}
// Add a listener for enter frame events
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
//Run this code on every frame to move the balls and reposition them if they are off the stage
function enterFrameHandler(event : Event) : void
{
for each( var myBall : MyBall in myBalls)
{
var ballIndex : int = myBalls.indexOf(myBall);
myBall.x += xVelocity[ballIndex];
if (myBall.x > stage.stageWidth)
{
myBall.x = -(Math.random() * stage.stageWidth);
myBall.y = Math.random() * stage.stageHeight;
}
}
}
First, turn your symbols into MovieClips. Then create a base class MySymbol.as for your symbols, something like:
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.geom.Point;
public class MySymbol extends MovieClip
{
public var speed:Number; // Pixels moved per frame
public function MySymbol(speed:Number, startPosition:Point)
{
this.speed = speed;
this.addEventListener(Event.ENTER_FRAME, update);
this.x = startPosition.x;
this.y = startPosition.y;
}
private function update():void
{
this.x -= this.speed;
if (this.x < 0 - this.width) { // We're at the left edge
this.removeEventListener(Event.ENTER_FRAME, update);
this.dispatchEvent(new Event(Event.COMPLETE));
}
}
}
}
Then make sure your movie clips are exported for AS3 (the "linkage" option on the item in the library). Make the class name for each item unique (e.g. MySymbol1, MySymbol2), and set the base class to MySymbol.
Your document class might look something like this:
package {
import flash.display.MovieClip;
import flash.events.Event;
import MySymbol; // Not strictly needed
public class DocumentClass extends flash.display.MovieClip
{
private static var SYMBOLS:Array = new Array(MySymbol1, MySymbol2);
public function DocumentClass()
{
// Create five symbols:
for (var i:int = 0; i < 5; i++) {
makeSymbol();
}
}
private function makeSymbol():void
{
// Pick a random symbol from the array:
var symType:Class = SYMBOLS[Math.random() * SYMBOLS.length];
// Construct the new symbol:
var loc:Point = new Point(stage.stageWidth, Math.random() * stage.stageHeight);
var sym:MySymbol = new symType(1 + Math.random() * 30, loc);
// Listen for the object hitting the left edge:
sym.addEventListener(Event.COMPLETE, remakeObject);
this.addChild(sym);
}
private function remakeObject(e:Event):void
{
e.target.removeEventListener(Event.COMPLETE, remakeObject);
this.removeChild(e.target);
// Replace the dead symbol:
makeSymbol();
}
}
}
It is a lot more efficient if instead of destroying and re-creating an object that flies off-stage you re-use the existing one and move it back to the right. But this is an optimization you can implement later, if things become slow.
Note that all the code above is UNTESTED and I have not coded AS3 in a while, so there's likely at least a few bugs in it. Hopefully it will serve as a good enough starting point.
Define a Circle (symbol) class that extends Sprite/Shape and has a velocity variable
Draw a circle (or whatever) with a random color
Math.floor(Math.random() * 0xffffff)
Assign a random value to velocity
minVelocity + Math.floor(Math.random() * velocityRange)
Create a start() method inside the Circle class that registers an enter frame handler
Increment this.y inside the enter frame handler, and dispatch a 'recycleMe' event if y is more than the max value.
Create N instances of Circle, addChild them, and call their start() methods.
listen to 'recycleMe' events on each of them, and reset the value of y from the handler.
Here's a few prompts to get you started.
MovieClips have an x and y property. If you were to add to these numbers over time you would see the MovieClip move along the x and/or y axis of the stage. Look into doing this using the Event.ENTER_FRAME which will allow you to change the values every time the screen is going to update.
Your stage will have a given width (a stageWidth property). You probably want to monitor when your MovieClip's x property is greater than the width of your stage. If it is remove (removeChild) it and add a new one (addChild) and place it back at the start x/y position.