stage.removeChild throwing an error - actionscript-3

I've built a simple snake game that uses a Main class (this is my document class), a Snake class and a Food class. The Main class makes a new object of the Snake class, and another of the Food class. Within both the Snake and Food classes, I'm making sprites like so:
var segment:Sprite = new Sprite();
segment.graphics.beginFill(0xFFFFFF);
segment.graphics.drawRect(0, 0, 10, 10);
segment.filters = [new GlowFilter(0xFF6699, .50, 3, 3, 2, 2, false, false)];
segment.graphics.endFill();
segment.x = x;
segment.y = y;
this.stage.addChild(segment);
this.segments.push(segment);
The snake's body is stored in an array of sprites called segments. You can see from that code I'm making a new sprite to extend the length of the snake and pushing it to the segments array. I do something similar for any food items, except within the food class I've defined the food sprite as public var foodSprite:Sprite; because I only need one on the stage at a time.
Now, when I call the gameOver() method from the Main class (where I have my game loop), I want to call stage.removeChild() on each of the snake segments and the food sprite. I tried doing this:
for(var i:Number = 0; i < this.snake.segments.length; i++)
{
stage.removeChild(this.snake.segments[i]);
}
But I get this error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Main/gameOver()
From what I know this should work, as this.snake.segments[i] points to a sprite, the one which I want to remove from the stage.
What could be going wrong here? Thank you.
EDIT: I guess it's also worth noting that segments is defined as:
public var segments:Array = new Array;

Please see comments on this answer for the actual solution.
Try this:
for(var i:Number = 0; i < snake.segments.length; i++)
{
var seg:Sprite = snake.segments[i] as Sprite;
if(seg.parent)
seg.parent.removeChild(seg);
}

Related

In Actionscript 3, how do I create movieclips through a looping statement?

The statement for takes a triple as an argument
(initial value of i, condition to cease looping, i increment)
I want to create a different movie clip each time the loop goes on.
So, I tried:
for (i = 0; i < 9; i++){
var Unit+i:MovieClip = new MovieClip()
}
But, this triggers the following error:
1086: Syntax error: expecting semicolon before plus"
What's the correct syntax, then?
To address the issue. You cannot create a var dynamically by using the var keyword. So doing var Unit+i will give you a syntax error.
You can create an array ahead of time and put your objects in that (as per #Panzercrisis's answer which is perfectly acceptable).
Other ways you can do this:
If you current context is dynamic (like if this is timeline code or part of a dynamic class like MovieClip), you do something like this:
this["Unit"+i] = new MovieClip();
From a compile time checking and code maintenance perspective, this is a little sloppy in my opinion, but for quick timeline projects it's certainly acceptable.
You could also just not store the clip anywhere but the display list:
for(var i:int=0;i<9;i++){
var mc:MovieClip = new MovieClip();
//do whatever you need to do to the clip
//like draw something for instance
mc.graphics.beginFill(0xFF0000);
mc.graphics.drawRect(0,0,100,100);
addChild(mc); //add to the display list so you can see it
}
If you never need to remove this clip, this way is great.
Or, you could add them to a container display object
var clipContainer:Sprite = new Sprite(); //Sprite is the same as movie clip but without the timeline stuff
addChild(clipContainer);
for(var i:int=0;i<9;i++){
var mc:MovieClip = new MovieClip();
//do whatever you need to do to the clip
//like draw something for instance
mc.graphics.beginFill(0xFF0000);
mc.graphics.drawRect(0,0,100,100);
clipContainer.addChild(mc);
}
The clipContainer would then act the same as an array, where you can access all it's children. Also, moving/scalling the container would in turn move/scale all it's children
Basically this is what you want to do:
var arrMovieClips:Array = new Array(9);
for (var i:int = 0; i < arrMovieClips.length; i++)
{
arrMovieClips[i] = new MovieClip();
}
This will create an array with nine elements, so you essentially have nine variables in a row:
arrMovieClips[0]
arrMovieClips[1]
arrMovieClips[2]
...
arrMovieClips[8]
Then it will go through and loop 0, 1, 2, etc. When it gets to the length of arrMovieClips, which is 9, then it'll stop. As it goes through 0-8, it'll create a new MovieClip and store it in each spot.

How to call function for object I want?

I didnt know how to exactly ask the question in the title but I can explain it here. So I have this class for pawns in my game.
And in my main program i call a bunch of instances of it with different names.
var z1:ZeleniPijun = new ZeleniPijun();
var z2:ZeleniPijun = new ZeleniPijun();
Basicly I have functions for movement and other variables that I use in my code in the class.
I'm making a multiplayer game and z1 and z2 would be pawns that I move around.
Until now I have used Switch and by knowing the ID of the player and the pawn that was clicked I moved them around the board. That means I have a switch for selecting a player and a switch inside that switch for selecting a pawn. And every time it goes trough the switch it goes to the same code but with a "different name".
For example if I roll a 4 for pawn number 1 it does
z1.movePawn(4);
z1.location += 4;
and other stuff that I need it to do
and if I roll a 3 for pawn number 2 it does
z2.movePawn(4);
z2.location += 4;
and other stuff that I need it to do
I have to copy the same code 16 times and just change the name from z1 to z2 to z3 etc...
Is there anyway I can make a function that would do that for me?
Something like this:
public function doStuff(pawnName:String, number:int):void{
pawnName.movePawn(number);
pawnName.location = number;
and other stuff that I need it to do
}
and then I can just give it the parameters I want 16 times instead of copying the same code everywhere.
send to the doStuff function the object that you want to do changes like
public function doStuff(theObj:ZeleniPijun ):void{
theObj.movePawn(number);
theObj.location = number;
and other stuff that I need it to do
}
if you have many objects, put them in a collection, like an array an iterate on it something like
foreach (obj in collection){
doStuff(obj);
}
this is just more or less pseudo-code, but you get the idea
You can use the object ZeleniPijun as parameter and call the method passing the instance you want.
// example creating multiples objects
var numObjs : uint = 5;
var objectsControl : Vector.<ZeleniPijun> = new Vector.<ZeleniPijun>(numObjs);
var zeleninPijun : ZeleniPijun;
for (var i : int = 0; i < numObjs; i++)
{
zeleninPijun = new ZeleniPijun();
objectsControl[i] = zeleninPijun;
}
// if you want to animate one object
doStuff(objectsControl[0], 4);
// if you want to animate them all
for each (var zeleninPijunObj : ZeleniPijun in objectsControl)
{
doStuff(zeleninPijunObj, 4);
}
function doStuff(pawnObj:ZeleniPijun, location:int):void
{
pawnObj.movePawn(location);
pawnObj.location = location;
}

AS3 Error 1063 - with (seemingly) correct number of Arguments

So I've been toying with the idea of building a game, and at this point I'm just trying to get a basic framework down for a tile-based over-world, like in Pokemon or others.
The issue I'm having now is an absurd one; after fixing several other errors I'm still getting ArgumentError #1063 in two different places, and in both cases I pass the right amount of arguments in (both are constructors) and the error tells me I passed in 0.
Here's pertinent code for the first one:
public function Main()
{
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, false, 0, true);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false, 0, true);
stage.addEventListener(Event.ENTER_FRAME, act, false, 0, true);
key = new KeyObject(stage);
overWorld = new Map(stage);
stage.addChild(overWorld);
}
(overWorld is a Map var, declared above with public var overWorld:Map;)
and:
public function Map(stageRef:Stage)
{
key2 = new KeyObject(stageRef);
currentMap = MapArrays.testMap;
x = 0;
y = 0;
initializeTiles();
}
I'm calling the Map() constructor with the stage reference that it needs, and it's spitting out this as the error:
ArgumentError: Error #1063: Argument count mismatch on Map(). Expected 1, got 0.
at flash.display::Sprite/constructChildren()
at flash.display::Sprite()
at flash.display::MovieClip()
at Main()
In addition, that initializeTiles() function holds the second of these two errors. Here's the code for that:
public function initializeTiles()
{
for(var i:int = 0; i < 25; i++)
{
for(var j:int = 0; j < 20; j++)
{
var temp:String = ("tile"+i+"_"+j);
this[temp] = new Tile(currentMap, (i+10), (j+10), (i * 30), (j * 30))
}
}
}
and the Tile() constructor:
public function Tile(mapArr:Array, inX:int, inY:int, xpos:int, ypos:int)
{
mapArray = mapArr;
arrX = inX;
arrY = inY;
x = xpos;
y = ypos;
determineTile();
}
This is the error that spits out (500 times, 20x25):
ArgumentError: Error #1063: Argument count mismatch on Tile(). Expected 5, got 0.
at flash.display::Sprite/constructChildren()
at flash.display::Sprite()
at flash.display::MovieClip()
at Map()
at Main()
Just to explain some, mapArr/mapArray/currentMap are Arrays of ints that describe the active mapset, inX/arrX is the x location of a given tile within the map (inY/arrY is of course the y location), and xpos and ypos are just where the tile sits on the screen (each tile is 30px by 30px). determineTile() just looks up the int mapArray[arrX][arrY] and changes the tile's attributes and image accordingly. MapArrays is a public dynamic class I created and imported in the Map class with import MapArrays;
Anyways, any help with this issue would be much appreciated. I can edit to post more code if someone thinks there may be an issue somewhere else, but these are the only places the constructors are called and the first 501 errors in my output (there are a few more, but they are because these constructors failed as they are null reference errors). I've been stuck here for a hefty chunk of time tweaking things slightly and nothing has worked thus far, and I don't see anywhere else where someone is getting this error while using the right amount of arguments.
Thanks in advance.
If you have any Tile or Map instances placed on the stage, those instances would be instantiated by Flash at run-time by calling the constructor (just like when you create an instance of Tile by calling new Tile(...).
Since your Tile and Map classes have custom constructors (that take parameters), Flash cannot create an instance of those display objects because it doesn't know what to pass as input parameters to the constructor - this is why you get the error.
Usually it's best not to put anything on the stage that has code backing it up - just create those instances from code and add them to the stage at run-time. This is extra work but it keeps your setup cleaner.

ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.

Please, I need help trying to remove bullets and enemies from my stage. I am very new to programming. Thank you.
I receive the following error message:
ArgumentError: Error #2025: The supplied DisplayObject must be a child
of the caller. at flash.display::DisplayObjectContainer/removeChild()
at Main/fl_EnterFrameHandler() at
flash.utils::Timer/_timerDispatch() at flash.utils::Timer/tick()
The code where debug sent me.
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
public class Main extends MovieClip
{
var enemyShipTimer:Timer;
var coinTimer:Timer;
var playerscore:Number = 0;
var enemies:Array;
var bullets:Array;
public function Main()
{
enemyShipTimer = new Timer(1000);
enemyShipTimer.addEventListener("timer", fl_EnterFrameHandler);
enemyShipTimer.start();
coinTimer = new Timer(1000);
coinTimer.start();
enemies = new Array ();
bullets = new Array ();
}
function fl_EnterFrameHandler(event:Event):void
{
var enemyinstance = new enemy_ks();
stage.addChild(enemyinstance);
enemies.push(enemyinstance);
trace(enemies.length);
for (var count=0; count<enemies.length; count++)
{
for (var bcount=0; bcount<bullets.length; bcount++)
{
if (enemies[count].hitTestObject(bullets[bcount]))
{
removeChild(enemies[count]);
enemies.splice(count, 1);
removeChild(bullets[bcount]);
bullets.splice(bcount, 1);
}
}
score_ks.text = " " + playerscore;
}
}
}
}
EDIT: Reread your code and noticed the real error is actually that you are adding to the stage but removing from your Main sprite. You need to match those up. You cannot remove an object from a parent if it is not actually a child of that object.
The points below still need to be addressed as well, otherwise you may end up with other errors.
Your issue is with your loop. In your loop, you adjust the array length on each successful hit test but you never adjust the count of the loop.
So think of it like this.
You start with:
count = 0;
length = 10;
Now say you run a loop for count < length and you splice at count == 4 and count == 7. In your current scheme, you will only hit the following objects (using the original index)
0 1 2 3 4 6 7 9
Notice that you don't hit index 5 or 8. When you modify the array like that and don't modify the count, you end up skipping over certain items. After splicing index 4, the original index 5 moves to 4 and everything else moves back one as well. So when you move to index 5, you are actually reading the original index 6.
Very simple fix for this is to just adjust your counts as you splice.
if (enemies[count].hitTestObject(bullets[bcount]))
{
removeChild(enemies[count]);
enemies.splice(count, 1);
count--; //subtract 1 from the count
removeChild(bullets[bcount]);
bullets.splice(bcount, 1);
bcount--; //subtract 1 from the bcount
}
That will ensure your count actually hits every object. You could also use a for each loop to handle this, though that type of loop is slower than a standard for loop depending on application.
Additionally, a DisplayObject can only be removed from a DisplayObjectContainer if it is actually a child of that container. If it is not, it will error out. So I believe you may also be running into an issue where your array does not fully line up with what is on the stage and you are trying to remove an object that doesn't actually exist as a child of the parent
As a minor aside, you should avoid adding children directly to the stage unless you have a real reason to do so. Instead, add it directly to the application object's display list using the this keyword, or simply addChild().

AS3: How to refer an object by his properties

Well, I'm doing a checkers game and I need to refer a piece by its position (x and y, both) and remove it from the screen (no problem with this).
I've been traying combinations with "this." but nothing.
How would you do that?
this.x and this.y are functional from the scope of your checkers pieces object; however, if you're accessing a piece outside of their scope, you must use a piece's instance name. Although not optimal, you could loop through children DisplayObjects.
// create a collection of your checker pieces
var checkers:Array = [];
// create a checker piece, whatever your DisplayObject class is.
var checker:Checker;
checkers.push(checker);
// add it to the stage, probably your game board
addChild(checker);
checker.x = 100;
checker.y = 100;
// loop through the children (from your game board)
for (var i:uint = 0; i < numChildren; i++)
{
var checker:DisplayObject = getChildAt(i);
trace(checker.x);
trace(checker.y);
}
Using coordinates to reference a piece may not be optimal for game play. You might want to consider a row / column or approach it from how your game board works.
If this is not clear, you should specify some code or expand your question with more detail.