EventListener AS3 problems reset problems - actionscript-3

Hey guys I am having a problem with Event Listeners in my AS3 file. I am trying to make this object that lasts for 83 frames to appear in a different location every time the parent (83 frame) movie clip resets. The problem is I have a function that places the object at a random y value which works great once. When it resets the ojbect appears on the same Y point. This is because I removeEventListener the function otherwise the object goes shooting off the screen when it loads. How do I call that event listener again without causing a loop that will shoot the object off screen?
Here is my code:
import flash.events.Event;
stop();
addEventListener(Event.ENTER_FRAME, SeaWeedPostion);
//stage.addEventListener(Event.ADDED_TO_STAGE, SeaWeedPostion);
function SeaWeedPostion(e:Event):void{
// if(newSeaWeed == 1) {
var randUint:uint = uint(Math.random() *500 + 50);
this.seaweedSet.y += randUint;
trace(randUint);
stopPos();
//}else{
//nothing
// }
}
function stopPos():void{
removeEventListener(Event.ENTER_FRAME, SeaWeedPostion);
//var newSeaWeed = 0;
}
function resetSeaWeed():void{
addEventListener(Event.ENTER_FRAME, SeaWeedPostion);
}
I have some // code in there from trying different things.
Anyone have any suggestions?
Thanks!

ENTER_FRAME event is triggered every frame, so rather than changing position on each frame maybe it's better to create a counter, count frames and if it reaches 82 change position of SeaWeed.
var counter:uint = 0;
Now add ENTER_FRAME listener
addEventListener(Event.ENTER_FRAME, onEnterFrame);
function SeaWeedPostion(e:Event):void {
counter++;
//Are we there yet?
if(counter < 83) {
//Nope, carry on
}
else {
//Yey!
changePosition();
counter = 0;
}
}
//Reset SeaWeed position when called
function changePosition() {
var randUint:uint = uint(Math.random() *500 + 50);
this.seaweedSet.y += randUint;
trace(randUint);
}

Related

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.

Repeat a Function when it meets the condition

I have a question about action script 3.
I am making a game, the basic rule of the game is:
an object falls from the top
the hero(user) has to avoid the object
if the object hits the ground or the hero: the hero dies or the object falls again from the top.
I am using the add child method for the object, and timer function for the fall.
the problem is:
when the object hits the ground, the function does not loop. it ends just like that. so there wont be any falling objects anymore.
please help me. thanks :)
stage.addEventListener(Event.ENTER_FRAME, addfire1);
function addfire1(e:Event):void
{
if (api1==false)//if object is not on the stage
{
randomx = randomRange();//generate random X
addChild(api);
api.x = randomx;//set x
api1 = true;//object is now on stage
}
if (api.hitTestObject(hero) || api.hitTestObject(ground))
{
falltimer.stop();
//stop timer;
falltimer.reset();
//reset fall Count to zero ;
removeChild(api);//object removed
api1=false;
}
}
function firefall(Event:TimerEvent):void
{
if (api1)
{
api.y += 20;//set speed y
}
}
Just separate the two cases: hero and floor.
if (api.hitTestObject(hero))
{
falltimer.stop();
//stop timer;
falltimer.reset();
//reset fall Count to zero ;
removeChild(api);//object removed
api1=false;
}
else if (api.hitTestObject(ground))
{
//reset object's position
api.y = -20;
}
Assuming there is only one object falling at the time I'd not remove the object but instead just move it to the original y position and a new x position. And instead of having the timer i'd create an update-function that runs every time you enter a frame.
stage.addEventListener(Event.ENTER_FRAME, update);
private function update(e:Event):void
{
if(!api1) //if object is not on the stage (same as api1==false)
{
addfire1();
}
if(api1) //if object if on stage (same as api1==true)
{
firefall();
}
}
private function addfire1(e:Event):void
{
randomx = randomRange();//generate random X
addChild(api);
api.x = randomx;//set x
api1 = true;//object is now on stage
if (api.hitTestObject(hero))
{
hitHero(); //execute what should happen to the hero when the he is hit
resetFire();
}
else if(api.hitTestObject(ground))
{
resetFire();
}
}
private function firefall(Event:TimerEvent):void
{
api.y += 20;//set speed y
}
private function resetFire():void
{
api.x = randomRange();
api.y = 0;
}
If you write it like this you don't have to mix stuff up. Try to keep everything seperated, one function does one thing. If you are making a big game try to seperate everything in classes.
Hopefully this fixes the problem and makes it easier for you to finish the game :)

How to get this code to show movieclip correctly?

I have the following code and it works fine, except I want it to play the Explosion movieclip in the library when an EnemyShip disappears but I only want it to play once and then disappear but not quite sure how to do it (I've tried a few things and it either makes the explosion animation loop and the ships don't disappear, which I believe is as a result of putting it inside the kill function, or I get other ArgumentErrors).
var speed:Number;
var shot = new ShotSound();
var explosion = new Explosion();
this.x = 800;
this.y = Math.random() * 275 + 75;
speed = Math.random()*5 + 9;
addEventListener("enterFrame", enterFrame);
addEventListener(MouseEvent.MOUSE_DOWN, mouseShoot);
function enterFrame(e:Event)
{
this.x -= speed;
if(this.x < -100)
{
removeEventListener("enterFrame", enterFrame);
stage.removeChild(this);
}
}
function kill()
{
stage.addChild(this);
explosion.x = this.x;
explosion.y = this.y;
removeEventListener("enterFrame", enterFrame);
stage.removeChild(this);
shot.play();
}
function mouseShoot(event:MouseEvent)
{
kill();
}
Thank for for any help I may receive.
You need some script to fire when the Explosion reaches it's final frame. A few ways you can do this:
1.
Dispatch an event on the last frame of your explosion animation. eg. this.dispatchEvent(new Event(Event.COMPLETE)); then listen for that event:
var explosion = new Explosion();
addChild(explosion);
explosion.addEventListener(Event.COMPLETE, removeExplosion);
function removeExplosion(e:Event):void {
MovieClip(e.currentTarget).stop();
MovieClip(e.currentTarget).removeEventListener(Event.COMPLETE, removeExplosion);
removeChild(MovieClip(e.currentTarget));
}
2.
Have the explosion remove itself on the last frame of the animation. eg. if(this.parent) parent.removeChild(this);
3.
If you can't or don't want to modify the explosion timeline, use the undocumented AddFrameScript command:
var explosion = new Explosion();
addChild(explosion);
explosion.addFrameScript(explosion.totalFrames-1, function():void {
explosion.stop();
if(explosion.parent){
explosion.parent.removeChild(explosion);
}
});
Here is a tip with your setup:
add a function called removeMe (or similiar) to avoid redundant code (so you call this function on kill or when the ship goes out of bounds
function removeMe(e:Event = null):void {
this.removeEventLIstener(Event.ENTER_FRAME,enterFrame);
if(this.parent){
this.parent.removeChild(this);
}
//any other cleanup that's required
}
Next, an updated kill function:
function kill(){
var explosion = new Explosion();
explosion.addEventListener(Event.COMPLETE, removeMe); //you need to dispatch this event on the last frame of the explosion timeline as shown below
addChild(explosion); //add it to the ship so it stays with it as the ship moves
//not sure what shot.play() does and if that belongs here.
}
//on the last frame of your explosion timeline:
stop();
dispatchEvent(new Event(Event.COMPLETE));
For starters, you're never adding explosion to the display list.
Change
var explosion = new Explosion();
stage.addChild(this);
to
var explosion = new Explosion();
stage.addChild(explosion);
Once you've done that, you'll want to add a listener to explosion to find out when it has finished playing:
explosion.addEventListener(Event.ENTER_FRAME, onExplosionProgress);
function onExplosionProgress(e:Event):void
{
if(explosion.currentFrame == explosion.totalFrames)
{
// explosion has reached end of its timeline
explosion.removeEventListener(Event.ENTER_FRAME, onExplosionProgress);
explosion.stop();
stage.removeChild(explosion);
}
}

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

While loop not working in ActionScript 3.0

I'm trying to create a function (called by a mouseover event) which will play the movie backwards while the mouse is over the instance, and stop while it's not.
This is what I have so far:
var b2:rightButton = new rightButton(); //new instance
b2.X = 550; //instances position
addChild(b2); //add instance to stage
b2.alpha = .4; // set instances alpha
var num = 0; // new variable called 'num'
b2.addEventListener(MouseEvent.ROLL_OVER, rightScroll); //mouse event for roll over
function rightScroll(event:MouseEvent) { //the function
num = 1; //set num to 1
b2.alpha = .8; //set alpha to 80%
}
b2.addEventListener(MouseEvent.ROLL_OUT, no_rightScroll); //event for roll out
function no_rightScroll(event:MouseEvent){ //roll- out function
num = 0; //set num back to 0
b2.alpha = .4; //set alpha back to 40%
}
while (num == 1){ // while num =1 (while mouse is over)
prevFrame(); //goto previous frame
}
Does anyone knows how to fix that, or a better way to do this?
The problem with your code at the moment is that loops do not execute in line with the framerate of your movie, so your code will call prevFrame() many, many times in a single frame. This can result in endless loops, which will cause your program to crash, and is completely useless in terms of animation.
The best approach is to listen to the ENTER_FRAME event of your movie, and move the playhead back one frame each time the event is dispatched. By adding and removing the listener in your button actions, you will get the effect you're looking for:
var b2:rightButton = new rightButton(); //new instance
b2.X = 550; //instances position
addChild(b2); //add instance to stage
b2.alpha = .4; // set instances alpha
b2.addEventListener(MouseEvent.ROLL_OVER, rightScroll); //mouse event for roll over
function rightScroll(event:MouseEvent):void { //the function
stage.addEventListener(Event.ENTER_FRAME,moveBackwards); //add stage listener
b2.alpha = .8; //set alpha to 80%
}
b2.addEventListener(MouseEvent.ROLL_OUT, no_rightScroll); //event for roll out
function no_rightScroll(event:MouseEvent):void { //roll- out function
stage.removeEventListener(Event.ENTER_FRAME,moveBackwards); //remove stage listener
b2.alpha = .4; //set alpha back to 40%
}
function moveBackwards(evt:Event):void {
prevFrame();
}
You'd probably find it much easier to write and read if you use the Greensock TweenLite library. Tweenlite can tween frames just as easily as other numeric values.
Inside your event listener, try adding this:
TweenLite.to( targetMC, 1, { frame:1, ease:fl.transitions.easing.None.easeNone } );
It will tween your movieclip (targetMC in this example) to frame 1 linearly with a duration of 1 second. You can play around with it using any of the other Tweenlite parameters as well.