Removing a child from the stage with active event listeners - actionscript-3

I have an enemy object that fires missile objects, like so;
public function fire():void {
var missile:Bullet = new Bullet();
stage.addChild(missile);
}
No problem there.
Now, when any missile objects leave the stage area, I want to remove them. Seems simple enough. So in my Bullet class, I've done the following;
I've used the standard method of calling this in my constructor;
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
Which then triggers init();
public function init(e:Event = null):void {
trace("init");
removeEventListener(Event.ADDED_TO_STAGE, init);
addEventListener(Event.ENTER_FRAME, actions);
}
So actions(); is triggered by Event.ENTER_FRAME;
public function actions(e:Event):void {
this.move();
trace(stage.stageWidth); // this works fine
stage.removeChild(this); // this throws Error #1009:
}
I'm just using this is an example. My actions(); function will eventually contain code to remove the object when it leaves the stage, not just when the function is called. I can trace the stageWidth property, no problem. So why is stage.removeChild(this); throwing this error?
[Fault] exception, information=TypeError: Error #1009: Cannot access a
property or method of a null object reference.
Now, this is where it gets really baffling.
If I move stage.removeChild(this); into init();, it works perfectly. So why would it work there, and not in actions(); which is always called after init();?

I never thought to check for this, as I assumed once an object was removed from the stage, all of its event listeners would be as well.
Removing a child from the stage, however, does not mean the object has been deleted, so stage.removeChild(this); was working within actions();, but even though I'd removed the bullet object from the stage, it was still calling actions();, which was then calling stage.removeChild(this); again, which was trying to reference the object when it no longer existed on the stage.
if (this.y > stage.stageHeight) {
stage.removeChild(this);
removeEventListener(Event.ENTER_FRAME, actions);
}
All I had to do was remove the event listener so actions(); would stop being called after I removed the bullet object from the stage.
Hopefully someone else can learn from my mistake, here. Still, I'm a bit surprised that Event.ENTER_FRAME still triggers even when you remove the child from the stage.

Related

AS3 Error #1009 in my constructor?

So I'm working on a 2d platforming game, and I'm getting a #1009.
In my Pickup() class, in the constructor, I'm trying to set this.x and this.y to the center stage, but it's saying the stage a null object reference.
public function Pickup() {
// constructor code
bitmapData.draw(_displayObject);
mSprite = new Bitmap(bitmapData);
addChild(mSprite);
this.x =
stage.width/2;
}
I separated the this.x and the stage.width to see which part was triggering the null, and it's definitely the stage.
It's probably something so horribly obvious I'm going to beat myself up for not noticing it.
Anyways, any help is greatly appreciated.
Cheers
The stage property is null on any DisplayObject, unless it is actually on the Stage.
This means you'll need to add an event listener to the object listening for Event.ADDED_TO_STAGE, and then work with the stage in the handler.
Alternatively, you could just pass a reference to the Stage to the constructor of Pickup:
public function Pickup(stage:Stage)
{
// Your code.
}
Add an event listener of add to stage
public function Pickup() {
// constructor code
bitmapData.draw(_displayObject);
mSprite = new Bitmap(bitmapData);
addChild(mSprite);
this.addEventListener(Event.ADDED_TO_STAGE, onAddToStage);
}
protected function onAddToStage(event:Event):void
{
this.x = stage.width/2;
}

ActionScript3, moving objects of type movieclip

Here i am trying to create a new movieclip type object, which is moved when function mvBall is called. When i run the code i get this err: implicit coercion of a value with static type object to a possibly unrelated type flash.display:MovieClip. Later on i want to be able to make the ball bounce back when it colides with another object. I'm new to action script and don't really know how things work so any help would be appreciated. Here's the code:
private function frame(x:Event):void {
var ball:MovieClip = new MovieClip();
ball.addEventListener(Event.ENTER_FRAME, animate);
ball.graphics.beginFill(0xff0000);
ball.graphics.drawCircle(100, 100, 15);
ball.graphics.endFill();
stage.addChild(ball);
}
private function animate(ev:Event):void {
mvBall(ev.target);
}
private function mvBall(mc:MovieClip) {
mc.x += 10;
}
You need to cast the target to MovieClip
private function animate(ev:Event):void {
mvBall(ev.target as MovieClip);
}
With that said it is better to just have one ENTER_FRAME handler and animate your objects in there.
stage.addEventListener(Event.ENTER_FRAME, animate);
private function animate(ev:Event):void
{
mvBall(myBall);
//other object animations
}
You are getting this error because the target property of the Event class is of type object.
In order to not throw the error, you need to cast it as a MovieClip:
mvBall(ev.target as MovieClip);
or
myBall(MovieClip(ev.target));
Something else to consider, is the difference between an Events target and currentTarget properties. If you ball had multiple layers/object inside it (sprites or other movieClips), the target would be whichever one of those sub-elements had the mouse over it during the click. currentTarget refers to the object that you've attached the listener to. In your case they may be the same (if your ball doesn't have any movie clips inside it), but your code could have unexpected results if you have sub-movieClips inside your ball.

'Error #1009: Cannot access a property or method of a null object reference.' in Flash CS5?

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at src::Game/onClick()
This is the full error^, however it doesn't give me the error on the timeline, but the output, when the flash game is played. Here's the code: http://pastebin.com/FnjWCQJ8 , the error's in line 35 or 49.
Thank you.
Its because blue1,blue2,and blue3 are not defined anywhere.
private function onClick(m:MouseEvent):void{
blue1.startme = true;
blue2.startme = true;
blue3.startme = true;
}
Probably line 31 - your stage instance in the Game constructor. Your MovieClip is probably not on the stage yet. Use an ADDED_TO_STAGE event listener, then add listeners to stage on added to stage handlers.
/*
* Constructor.
*/
public function Game()
{
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
protected function addedToStageHandler(event:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
// Listeners.
stage.addEventListener(Event.ENTER_FRAME, _update);
stage.addEventListener(MouseEvent.MOUSE_DOWN, _mouseAction);
stage.addEventListener(MouseEvent.MOUSE_UP, _mouseAction);
stage.addEventListener(MouseEvent.CLICK, onClick);
// Helicopter.
_helicopter = new Helicopter();
stage.addChild(_helicopter);
}

AS3 - Error #1009: Cannot access a property or method of a null object reference

I'm making a game where if the enemy's bullet hits the user, the bullet disappears. Everything works fine except that I keep getting,
'Error #1009: Cannot access a property or method of a null object
reference'
Once the bullet hits the user (bullet disappears though). It confuses me because I've used almost exact the same code in another class where it works perfect.
package classes.enemy
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;
import classes.Main;
public class Bullet extends MovieClip
{
var speed:Number;
public function initialize()
{
var stageReff:Stage = this.stage as Stage;
stage.addEventListener("enterFrame", enterFrame);
}
//code
function enterFrame(e:Event):void
{
this.x += speed;
if(this.hitTestObject(Main.user))
{
removeEventListener("enterFrame", enterFrame);
this.parent.removeChild(this);
// line above gives the error.
}
}
}
}
I have no clue what could be wrong.
Thanks in advance.
My guess is it has to do with the fact that you're adding an enter frame event listener to the stage, yet try to remove it from the listening object itself.
Try changing
var stageReff:Stage = this.stage as Stage;
stage.addEventListener("enterFrame", enterFrame);
to
addEventListener("enterFrame", enterFrame);
you're not removing the event listener from the stage, but the object itself :)
I would not recommend doing it like this, create one listener in your main game class, and call an update function on all objects!
The reason why it fails is because you're removing your Bullet from it's parent. So when you're referencing this.parent it returns null because there simply isn't a parent anymore. You're trying to remove the ENTER_FRAME event but because you set it on the stage the original ENTER_FRAME event keeps running. You can simply fix it like so:
if(this.x > 30)
{
stage.removeEventListener("enterFrame", enterFrame);
this.parent.removeChild(this);
}
But like #RasmusWriedtLarsen already pointed out, it's better to handle these events more globally. And also let the parent handle the removing of the Bullet.

Loading an external SWF throw an error

I am trying to load an External swf.
But it throws an error when I compile.
ArgumentError: Error #1063: Argument count mismatch on Main/init(). Expected 0, got 1.
at flash.display::DisplayObjectContainer/addChild()
at flash.display::Stage/addChild()
at MainSWF/onLoadedAction()
Swfloader Class
public function MainSWF():void
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
_loader = new Loader();
_my_url = new URLRequest("Main.swf");
_loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgressAction);
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadedAction);
_loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, IOErrorAction);
_loader.load(_my_url);
}
private function onLoadedAction(e:Event):void
{
var mc:Sprite = new Sprite();
mc.addChild(_loader.content);
trace(stage);
stage.addChild(mc);
_loader.removeEventListener(ProgressEvent.PROGRESS, onProgressAction);
}
Init is being called from somewhere else without passing the Event as an argument. Simple solution is to change your init code to look like this:
private function init(e:Event = null):void
{
}
Also you should change your ADDED_TO_STAGE code to look like this:
public function MainSWF():void
{
if(stage){
init();
}else{
addEventListener(Event.ADDED_TO_STAGE, init);
}
}
If you're already added to the stage before you've added the listener, (which is why we check and see if stage is define) then you're never going to fire the ADDED_TO_STAGE event again, unless you add/remove your main swf from the timeline which you most likely won't be doing. So, if you do include that bit of code then it only makes sense to modify the following code as well:
removeEventListener(Event.ADDED_TO_STAGE, init);
to
if(hasEventListener(Event.ADDED_TO_STAGE)){
removeEventListener(Event.ADDED_TO_STAGE, init);
}
Obviously the reason for checking to see if the listener exists is because we may have just jumped right to the init function inside the constructor, because the stage was already present (meaning this swf class was already added to the display list while or before our constructor code executed).