AS3 removeChild and collisions : issue - actionscript-3

I'm working in a little shooting game with Flash and AS3. I'm still beginning for using Class documents, but I managed to understand thanks to tutorials.
So here's how it works :
I used the HitTestObject when the Enemy MovieClip hits a bullet, shot by the user :
//checking if it is touching any bullets
//we will have to run a for loop because there will be multiple bullets
for(var i:int = 0;i<_root.bulletContainer.numChildren;i++){
//numChildren is just the amount of movieclips within
//the bulletContainer.
//we define a variable that will be the bullet that we are currently
//hit testing.
var bulletTarget:MovieClip = _root.bulletContainer.getChildAt(i);
//now we hit test
if(hitTestObject(bulletTarget)){
hit++;
if(hit==4)
{
gotoAndPlay(4); //the Enemy MC is removed after 4 hits(parent.removeChild(this))
removeEventListener(Event.ENTER_FRAME, eFrame);
//the Bullet MC is removed with its Listeners
_root.bulletContainer.removeChild(bulletTarget);
bulletTarget.removeListeners();
}
if(hit<4)
{
gotoAndPlay(2);
_root.bulletContainer.removeChild(bulletTarget);
bulletTarget.removeListeners();
}
if(hit > 4)
{
_root.bulletContainer.removeChild(bulletTarget);
bulletTarget.removeListeners();
hit = 0;
}
}
}
So after 4 hits, it is completely removed from the screen.
The eFrame function remove the Enemy MC if it goes off the stage :
private function eFrame (event:Event):void{
x+=speed;
if(this.x > stage.stageWidth + 50){
removeEventListener(Event.ENTER_FRAME, eFrame);
_root.removeChild(this);
}
}
I also put a command that detects collisions between the Enemy MC and the Player (that I gave the "craft" instance name) :
if(hitTestPoint(_root.craft.x -203.25, _root.craft.y - 44.9, collide))
{
_root.dmg.width+=8;//reduce the life bar
removeEventListener(Event.ENTER_FRAME, eFrame);
gotoAndPlay(4);
}
if(hitTestPoint(_root.craft.x -210.6, _root.craft.y - 32.9, collide))
{
_root.dmg.width+=8;
removeEventListener(Event.ENTER_FRAME, eFrame);
gotoAndPlay(4);
}
if(hitTestPoint(_root.craft.x -210.6, _root.craft.y - 6, collide))
{
_root.dmg.width+=8;
removeEventListener(Event.ENTER_FRAME, eFrame);
gotoAndPlay(4);
}
if(hitTestPoint(_root.craft.x -211.4, _root.craft.y + 20, collide))
{
_root.dmg.width+=8;
removeEventListener(Event.ENTER_FRAME, eFrame);
gotoAndPlay(4);
}
...//There is a lot of other points with the same results...
So the Enemy MC is also removed if it hits the craft MC (Player). But I encountered an issue : when the Enemy MC is hit (4 times by the Bullet movieclips "shot" by the user which removes it) but also collided by the player, it is not removed as it ought to be...
It is instead still displayed on the screen, and is static : it can't be hit neither by a bullet MC, neither by the player MC...
I think this is because of the parent.removeChild(this) executed from gotoAndPlay(4) of the Enemy MC, which causes that issue : it is executed a twice (because the Enemy MC is destroyed by the Bullet MC AND by the Player)...
Anyone has an idea to solve that double execution of removeChild ?
If you want to have more info, you can download the source :
https://www.dropbox.com/s/wvl116wjqpu69d0/shoot_aircraft%20game.zip?dl=0
Thank you for your help.

Put your enemy inside of a container (could be just a Sprite object) and on the 4th frame of the animation call
parent.parent.removeChild(this.parent);
You'll have to change a few of your enemy movement lines of code maybe but you can figure that out.
Basically the idea is to hide the animation inside of a non animating Sprite. Changing frames mid code screws things up, unless it's nested deeper than the object that is being called on. I hope that makes sense.

Related

How to play animation and then play reverse on hover, start playing again until end on hover out using in Adobe Animate (Flash)?

Sorry this is so specific but I have combed through so many pages and videos and tutorials and can't figure this out.
I have all of my animations within a MovieClip. In the movie clip is also a stage sized white square button with the instance name "btn". Back on the main stage I have a second layer called "actions" with the following code applied to the first (and only) frame. It's not working. At all. (HUGE) tia
stop(); // this will stop the movie from playing at the start
btn.addEventListener((MouseEvent.ROLL_OVER, playMovie);
btn.addEventListener((MouseEvent.ROLL_OUT, stopMovie);
function playMovie(evt:MouseEvent):void {
play();
}
function stopMovie(evt:MouseEvent):void {
stop();
}
The problem is when you say play(); or stop(); which object are you really commanding? Your playMovie function could be in theory used to control many MovieClips at once, in different ways, so be specific with your commands...
btn.play(); //start the playback of "btn" MC
btn.stop(); //stop the playback of "btn" MC
Also consider using MOUSE_OVER/OUT instead ROLL_OVER/OUT etc but whatever works for you.
For reversing you will use btn.prevFrame(); together with an ENTER_FRAME event function. This function reads your Document settings for the FPS. For example, if you set 30 frames-per-sec then whatever instructions you put inside the event function will be processed 30 times per second.
See this other Answer for advice about reversing the playback of a MovieClip.
#VC.One is correct in how you should implement a solve to your issue, however in response to your comment on their answer, I thought I would demonstrate how to implement this fully for you - incase they don't.
var removeUpdate = false;
btn.addEventListener(MouseEvent.MOUSE_OVER, playMovie);
btn.addEventListener(MouseEvent.MOUSE_OUT, stopMovie);
function playMovie(evt:MouseEvent):void {
// Stop rewinding the movie clip and play it
if(removeUpdate){
stage.removeEventListener(Event.ENTER_FRAME, update);
removeUpdate = false;
}
// play our button
btn.play();
}
function stopMovie(evt:MouseEvent):void {
// stop our button
btn.stop();
// ... and rewind it
stage.addEventListener(Event.ENTER_FRAME, update);
removeUpdate = true;
}
function update(evt: Event){
// moves the button movie clip backwards one frame.
btn.prevFrame();
// If we have finished rewinding the movie clip, then stop
if(btn.currentFrame == 1){
stage.removeEventListener(Event.ENTER_FRAME, update);
removeUpdate = false;
}
}
It is important that you remove the update event because if you don't, the movie will never play again, because it will go one frame forward and then back again every frame due to; btn.play(); btn.prevFrame();

Actionscript 3.0 - Making a sprite move after it has collided with another

I'm trying to code a movie clip object to move after it has been "hit" with another object. I can make it move like this:
if (bat.hitTestObject(ball)
{
bat.x += xMovement;
}
This only makes it move by xMovement which in this case is 5 when it has hit but I would like it to continue to move afterwards. Thanks for the help
To "keep moving" you need to increment over time, for example at each frame using enterFrame or at an arbitrary interval using a Timer.
For example:
if (bat.hitTestObject(ball)) {
addEventListener(Event.ENTER_FRAME, moveBat);
}
function moveBat(e:Event):void {
bat.x += xMovement;
}
To stop moving the bat at any point, remove the enterFrame handler:
removeEventListener(Event.ENTER_FRAME, moveBat);

Adding stop(); to a movieclip on the timeline is causing the tweens in said movieclip to not play, the movieclip just skips to the end

I've got a movieclip that is composed of 3 separate symbols. 2 of the symbols have their alpha tweened over 60 frames. 1 of the symbols is not tweened at all. All symbols are in separate layers, and there is a 4th, empty layer with a keyframe on frame 60 for actionscript.
The actionscript on frame 60 is simply "stop();" .
I am adding an instance of the movieclip to the stage dynamically from the document class. When I have "stop();" in there, the movieclip appears on the stage and skips straight to frame 60, where it succesfully stops.
Without "stop();" in there, the movieclip plays the alpha tweens perfectly, but obviously continuously loops.
Manually dispatching an Event.COMPLETE and listening for it does not work either and I would prefer not doing it that way anyway.
Here is the code that adds the movieclip to the stage:
//initialize the gameplay, remove title screen.
private function initialize_gameplay():void
{
//remove the title screen
initialize_title_screen(true);
this.screen_transition_obj = new tide_out_video();
this.addChild(this.screen_transition_obj);
this.game_board = new tidepool_gameboard();
this.screen_transition_obj.addEventListener(Event.COMPLETE,swap_transition_video_for_screen);
}
//replace the current transition video with the screen it was transitioning to
private function swap_transition_video_for_screen(e:Event){
this.addChild(this.game_board);
if(this.screen_transition_obj != null){
if(this.getChildByName(this.screen_transition_obj.name)){
this.removeChild(this.screen_transition_obj);
}
this.screen_transition_obj.removeEventListener(Event.COMPLETE, swap_transition_video_for_screen);
this.screen_transition_obj = null;
}
}
The movieclip's class is tidepool_gameboard and the property of the document class that stores the reference to it is game_board.
Any idea why putting stop(); on frame 60 of the movie clip is causing it to skip to the end without tweening?
UPDATE:
Adding the movieclip to the stage instantly instead of as the result of an event listener works properly, the problem only occurs when the movieclip is added in the event listner.
I can't believe I overlooked this, as it appears to be fairly obvious to me now.
In the code posted in the question, I've initialized a new instance of this.game_board, then added it to the stage after a delay based on an event listener for a video clip. The animation is playing, but it's playing before the clip ever is added to the stage.
Thanks go to alecmce who answered this question.
I did his Event.ADDED_TO_STAGE event listener, and it worked, which led me to realize that the MovieClip does not wait until it is added to the stage to start playing its own timeline, it simply starts the second you instantiate the object.
This is the new, fully functional code:
//initialize the gameplay, remove title screen.
private function initialize_gameplay():void
{
//remove the title screen
initialize_title_screen(true);
this.screen_transition_obj = new tide_out_video();
this.addChild(this.screen_transition_obj);
this.screen_transition_obj.addEventListener(Event.COMPLETE,swap_transition_video_for_screen);
}
//replace the current transition video with the screen it was transitioning to
private function swap_transition_video_for_screen(e:Event)
{
this.game_board = new tidepool_gameboard();
this.addChild(this.game_board);
if (this.screen_transition_obj != null)
{
if (this.getChildByName(this.screen_transition_obj.name))
{
this.removeChild(this.screen_transition_obj);
}
this.screen_transition_obj.removeEventListener(Event.COMPLETE, swap_transition_video_for_screen);
this.screen_transition_obj = null;
}
}

Making platform game, need method to stop running

I am making a platform game in flash.
I have a goal class(the class which contains code for the goal sprite, where when you hit it, it continues to next part of game).
Inside the goal constructor, 2 event listeners are added, they are as follows:
addEventListener(Event.ADDED, beginClass);
addEventListener(Event.ENTER_FRAME, eFrame);
The beginClass function is fine, and only runs once, but eFrame is what checks if the player has hit the goal, so it is constantly running. The problem is, once the player hits the goal, eFrame continues to run, while in a menu describing the next scene to the player. My eFrame function is below.
private function eFrame(event:Event):void{
if(hitTestObject(_root.mcMain)){
var lastScore:int = _root.mainScore;
_root.mainScore = lastScore;
while (_root.lvlHolder.numChildren > 0) {
_root.lvlHolder.removeChildAt(0);
}
_root.mcMain.removeChildAt(0);
_root.isInCut = true;
if (_root.lvlCurrent == 1) {
_root.gotoAndStop(2);
} else if (_root.lvlCurrent == 2) {
_root.gotoAndStop(3);
} else if (_root.lvlCurrent == 3) {
_root.gotoAndStop(4);
}
}
}
Frames 2, 3, 4, are frames with just text and a button that display a message to the player, and then the player hits continue. My problem is that eFrame is still trying to be run, but the class has not been instantiated, and the method is causing extreme amounts of lag once the player continues.
Inside Goal, what's the point of _root?
Anyway here's what I've done:
Change the event ADDED to ADDED_TO_STAGE, that way, when the event is fired we know this Sprite has a stage property.
addEventListener(Event.ADDED_TO_STAGE, beginClass);
Remove the eFrame event from the constructor. Add it to beginClass, with stage, like so:
stage.addEventListener(Event.ENTER_FRAME, eFrame);
Now in eFrame, you can awesomely remove the event with the stage reference. It didn't work earlier because the reference was wrong (whatever it was with the _root variable).
stage.removeEventListener(Event.ENTER_FRAME, eFrame);
BUT - remember to do it before this part of your code:
while (_root.lvlHolder.numChildren > 0) {
_root.lvlHolder.removeChildAt(0);
}
because when the sprite is removed, it won't have the stage property anymore. Just remember to clean up events in all possible scenarios. I'm not entirely sure stage is the right place to place your enter frame event, I just assumed so because of what you earlier called _root.
Inside eFrame() stop the event listener:
removeEventListener(Event.ENTER_FRAME, eFrame);
you're adding eventListener to stage so try this:
stage.removeEventListener(Event.ENTER_FRAME, eFrame);
or
parent.removeEventListener(Event.ENTER_FRAME, eFrame);
or
event.target.removeEventListener(Event.ENTER_FRAME, eFrame);

Method won't stop running when I switch to new frame, why? [duplicate]

I am making a platform game in flash.
I have a goal class(the class which contains code for the goal sprite, where when you hit it, it continues to next part of game).
Inside the goal constructor, 2 event listeners are added, they are as follows:
addEventListener(Event.ADDED, beginClass);
addEventListener(Event.ENTER_FRAME, eFrame);
The beginClass function is fine, and only runs once, but eFrame is what checks if the player has hit the goal, so it is constantly running. The problem is, once the player hits the goal, eFrame continues to run, while in a menu describing the next scene to the player. My eFrame function is below.
private function eFrame(event:Event):void{
if(hitTestObject(_root.mcMain)){
var lastScore:int = _root.mainScore;
_root.mainScore = lastScore;
while (_root.lvlHolder.numChildren > 0) {
_root.lvlHolder.removeChildAt(0);
}
_root.mcMain.removeChildAt(0);
_root.isInCut = true;
if (_root.lvlCurrent == 1) {
_root.gotoAndStop(2);
} else if (_root.lvlCurrent == 2) {
_root.gotoAndStop(3);
} else if (_root.lvlCurrent == 3) {
_root.gotoAndStop(4);
}
}
}
Frames 2, 3, 4, are frames with just text and a button that display a message to the player, and then the player hits continue. My problem is that eFrame is still trying to be run, but the class has not been instantiated, and the method is causing extreme amounts of lag once the player continues.
Inside Goal, what's the point of _root?
Anyway here's what I've done:
Change the event ADDED to ADDED_TO_STAGE, that way, when the event is fired we know this Sprite has a stage property.
addEventListener(Event.ADDED_TO_STAGE, beginClass);
Remove the eFrame event from the constructor. Add it to beginClass, with stage, like so:
stage.addEventListener(Event.ENTER_FRAME, eFrame);
Now in eFrame, you can awesomely remove the event with the stage reference. It didn't work earlier because the reference was wrong (whatever it was with the _root variable).
stage.removeEventListener(Event.ENTER_FRAME, eFrame);
BUT - remember to do it before this part of your code:
while (_root.lvlHolder.numChildren > 0) {
_root.lvlHolder.removeChildAt(0);
}
because when the sprite is removed, it won't have the stage property anymore. Just remember to clean up events in all possible scenarios. I'm not entirely sure stage is the right place to place your enter frame event, I just assumed so because of what you earlier called _root.
Inside eFrame() stop the event listener:
removeEventListener(Event.ENTER_FRAME, eFrame);
you're adding eventListener to stage so try this:
stage.removeEventListener(Event.ENTER_FRAME, eFrame);
or
parent.removeEventListener(Event.ENTER_FRAME, eFrame);
or
event.target.removeEventListener(Event.ENTER_FRAME, eFrame);