I am having a problem removing a MovieClip from an array.
I am getting this error :
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Spiker/loop()".
The spike (Spiker) is getting removed, but the error still annoys me.. Any idea how to fix this?
Here is my code :
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Spiker extends MovieClip {
public var spikeDirection:int = 1;
private var removed = false;
public function Spiker() {
// constructor code
trace("Spiker added");
addEventListener(Event.ENTER_FRAME, loop);
}
private function loop (evt){
this.x += spikeDirection * 10;
for(var i:int = 0; i < this["parent"].enemyList.length; i++){
if(removed == false){
if(this["parent"].enemyList[i].hitTestObject(this)){
trace("Spikerhit");
removed = true;
remove(evt);
}
}
}
}
public function remove (evt){
removeEventListener(Event.ENTER_FRAME, loop);
this["parent"].removeChild(this);
}
}
Your problem is coming from your for loop, this line exactly :
for(var i:int = 0; i < this["parent"].enemyList.length; i++){
because when your current object has touched an enemy it is removed from its parent, and for the next iteration of the for loop (if there is one), this["parent"] is null and that's why that error is fired as the for loop is verifying every iteration the conditional statement that determines when the looping ends (this["parent"].enemyList.length in your case).
To avoid that, you can use a variable, for example, to store the number of enemies to be used in the for loop.
You can also use the break statement inside your for loop after removing your object to exit that loop.
Hope that can help.
Related
I'm a beginner of the flash as3. I'm trying to create a game but in the beginning of my game project. A error comes. This is the error --> Line 48: 1013: The private attribute may be used only on class property definitions.
I don't know what is the problem, is anyone else know what is this problem if anybody know please tell me.
This is the code:
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class Main extends Sprite
{
public function Main()
{
// variables and constants
const NUMBER_OF_TILES:uint = 20;
const TILES_PER_ROW:uint = 5;
var tiles:Array=new Array();
var tile:tile_movieclip;
// end of variables and constants
for (var i:uint=0; i<NUMBER_OF_TILES; i++)
{
tiles.push(Math.floor(i/2));
trace("My tiles: "+tiles);
// end of tiles creation loop
// end of tiles creation loop add the following code:
// shuffling loop
var swap,tmp:uint;
for (i=NUMBER_OF_TILES-1; i>0; i--)
{
swap = Math.floor(Math.random() * i);
tmp = tiles[i];
tiles[i] = tiles[swap];
tiles[swap] = tmp;
trace("My shuffled tiles: "+tiles);
// end of shuffling loop
//tile placing loop
for (i=0; i<NUMBER_OF_TILES; i++)
{
tile=new tile_movieclip();
addChild(tile);
tile.cardType = tiles[i];
tile.x=5+(tile.width+5)*(i%TILES_PER_ROW);
tile.y=5+(tile.height+5)* (Math.floor(i/TILES_PER_ROW));
tile.gotoAndStop(NUMBER_OF_TILES/2+1);
tile.buttonMode = true;
tile.addEventListener(MouseEvent.CLICK, onTileClicked);
// end of tile placing loop
}
private function onTileClicked(e:MouseEvent) {
trace("you picked a "+e.currentTarget.cardType);
e.currentTarget.gotoAndStop(e.currentTarget.cardType+1);
}
}
}
}
}
}
Your private function onTileClicked is inside your Main method. Access modifiers have to be used at the class level (the same level as your Main method), not inside other methods.
You should either remove the private modifier, or move the function to the class level. As it is, the function can't be accessed outside Main, so it doesn't need to be private.
I'm making a game as a project for school and have recently encountered a little problem in as3. I'm making a game where you are maneuvering ship avoiding asteroids, and just added the function so that when you hit an asteroid your ship is removed from the stage via stage.removeChild. Everything is fine until you actually hit something, then this error comes up(and I mean alot, like it keeps repeating itself for as long as the game is on):
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/removeChild()
at Function/com.asgamer.basics1:Engine/private:loop/com.asgamer.basics1:krash()[C:\Users\nti\Desktop\Ship game\com\asgamer\basics1\Engine.as:54]
Here's the code(I marked out line 54):
package com.asgamer.basics1
{
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
public class Engine extends MovieClip
{
private var numStars:int = 80;
private var enemyList:Array = new Array();
private var ourShip:Ship;
public function Engine() : void
{
ourShip = new Ship(stage);
stage.addChild(ourShip);
ourShip.x = stage.stageWidth / 2;
ourShip.y = stage.stageHeight / 2;
for (var i:int = 0; i < numStars; i++)
{
stage.addChildAt(new Star(stage), stage.getChildIndex(ourShip));
}
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
private function loop(e:Event) : void
{
if (Math.floor(Math.random() * 14) == 5)
{
var enemy:Asteroid = new Asteroid(stage);
enemy.addEventListener(Event.REMOVED_FROM_STAGE, removeEnemy, false, 0, true);
enemyList.push(enemy);
stage.addChild(enemy);
stage.addEventListener(Event.ENTER_FRAME, krash);
function krash(e:Event):void{
if (enemy.hitTestObject(ourShip)==true){
stage.removeChild(ourShip); <-------------------------- LINE 54
}
}
}
}
private function removeEnemy(e:Event)
{
enemyList.splice(enemyList.indexOf(e.currentTarget), 1);
}
}
}
Please do remember that I'm sort of a beginner to coding, which would explain other possible "faults" in the code. :)
The problem is, as was mentioned a while ago, is that you don't clean up your ourShip after actually removing it from stage. See, once you call stage.removeChild() the ship is no longer on stage, but collision check still goes because you didn't remove the enter frame listener. You should add the remove listener statement to the code branch where you remove the ship.
stage.addEventListener(Event.ENTER_FRAME, krash);
... // other code
function krash(e:Event):void{
for each (var enemy in enemyList)
if (enemy.hitTestObject(ourShip)==true){
stage.removeChild(ourShip);
stage.removeEventListener(Event.ENTER_FRAME, krash); // THIS line
}
}
EDIT: first, move the addEventListener(Event.ENTER_FRAME, krash) line to the point where you add a loop listener, because you don't want to have more than a single one of these, and second, make a complete loop for hitTestObject versus enemyList. The code above is updated.
Note: Some validity checks may need to be present in the listener code, for example, if ourShip is already removed you might just return from the event listener function, or skip the hit test checks. This will also help you once you'll start advancing to a single master enter frame listener - it's generally faster having one function as event listener than many for the same event, and also helps you consolidate every bit of code you want to be executed in response for a particular event in one place, instead of searching where did you place that statement that bugs out. This also helps to not fiddle with adding/removing listeners on a regular basis, although sometimes playing with listeners can do you better.
Problem is caused by the fact that you're trying remove ourShip from the stage several times. More precisely on each Event.ENTER_FRAME event.
I'm getting an error I can't seem to fix. I think I know kind of what is going on but I'm not sure enough to be able to fix it. I keep getting error
"TypeError: Error #2007: Parameter hitTestObject must be non-null.
at flash.display::DisplayObject/_hitTest()
at flash.display::DisplayObject/hitTestObject()"
Basically I fire an attack in my game. It hits an enemy and he is killed just fine. BUT, he has an animation as he dies that takes a couple seconds. It seems if I fire another attack during his animation, my attack IMMEDIATELY gives this error (before striking anything, that is). Once the animation is over, everything is fine again. Also, the game was working 100% fine before I put in this animation.
Here is my document class
package com.classes
{
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
public class DocumentClass extends MovieClip
{
// we need to keep track of our enemies.
public static var enemyList1:Array = new Array();
// moved stickobject1 to a class variable.
private var stickobject1:Stickman2;
public function DocumentClass() : void
{
//removed the var stickobject1:Stickman2 because we declared it above.
var bg1:background1 = new background1();
stage.addChild(bg1);
stickobject1 = new Stickman2(stage);
stage.addChild(stickobject1);
stickobject1.x=50;
stickobject1.y=300;
//running a loop now.... so we can keep creating enemies randomly.
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
//our loop function
private function loop(e:Event) : void
{
//run if condition is met.
if (Math.floor(Math.random() * 90) == 5)
{
//create our enemyObj1
var enemyObj1:Enemy1 = new Enemy1(stage, stickobject1);
//listen for enemyObj1 being removed from stage
enemyObj1.addEventListener(Event.REMOVED_FROM_STAGE, removeEnemyObj1, false, 0, true);
//add our enemyObj1 to the enemyList1
enemyList1.push(enemyObj1);
stage.addChild(enemyObj1);
}
}
private function removeEnemyObj1(e:Event)
{
enemyList1.splice(enemyList1.indexOf(e.currentTarget), 1);
}
}
}
And here is my attack1 class
package com.classes {
import flash.display.MovieClip;
import flash.display.Stage;
import com.senocular.utils.KeyObject;
import flash.ui.Keyboard;
import flash.events.Event;
public class attack1 extends MovieClip {
private var stageRef:Stage;
private var bulletSpeed:Number = 16;
public function attack1 (stageRef:Stage, x:Number, y:Number) : void
{
this.stageRef = stageRef;
this.x = x;
this.y = y;
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
private function loop(e:Event) : void
{
//move bullet up
x += bulletSpeed;
if (x > stageRef.stageWidth)
removeSelf();
for (var i:int = 0; i < DocumentClass.enemyList1.length; i++)
{
if (hitTestObject(DocumentClass.enemyList1[i].hit))
{
trace("hitEnemy");
removeSelf();
DocumentClass.enemyList1[i].takeHit();
}
}
}
private function removeSelf() : void
{
removeEventListener(Event.ENTER_FRAME, loop);
if (stageRef.contains(this))
stageRef.removeChild(this);
}
}
}
Don't think you should need any other of my classes to figure out what's going on, but let me know if you do! Thanks very much =)
You don't want to do a hit test against any object that may have been removed from the scene (or from the enemyList array). The extra condition added to attack1.loop's for loop should get rid of your error. A better fix is to splice out the items you remove, so they are never tested against in the loop.
The break line will make it stop trying to hit other enemies after the bullet is removed. If the line "DocumentClass.enemyList1[i].takeHit();" removes the item from the enemyList1, you need to make sure you use "i--;" at the bottom of the loop as well, if you plan on looping through the remainder of the enemies. "i--" or "break", you will probably need one of them in that loop.
Double check the order in which you are executing your removal methods. Sometimes it's better to flag the items for removal and remove them in a separate loop than to remove an item that may be needed later in the same loop.
for (var i:int = 0; i < DocumentClass.enemyList1.length; i++){
if(DocumentClass.enemyList1[i] && DocumentClass.enemyList1[i].hit){
if (hitTestObject(DocumentClass.enemyList1[i].hit)){
trace("hitEnemy");
removeSelf();
DocumentClass.enemyList1[i].takeHit();
break;
}
}
}
Not the correct solution in this question. You can always do != null in a conditional statement.
if(object!=null){
party.drink();
}
so I'm still fairly new to AS3 and I'm getting my head around the errors and stuff and I'm trying to figure out why this is not working how it should, the function still executes but it leaves an error on my console. Here is my code:
import flash.events.MouseEvent;
import flash.display.MovieClip;
stop();
var activeHitArray:Array = new Array(word_select_box);
var activeDropArray:Array = new Array(answer1_word, answer2_word, answer3_word);
var hitPositionsArray: Array = new Array();
for (var numi:int = 0; numi < activeDropArray.length; numi++) {
activeDropArray[numi].buttonMode = true;
activeDropArray[numi].addEventListener(MouseEvent.MOUSE_DOWN, mousedown1);
activeDropArray[numi].addEventListener(MouseEvent.MOUSE_UP, mouseup1);
hitPositionsArray.push({xPos:activeDropArray[numi].x, yPos:activeDropArray[numi].y});
}
function mousedown1(event:MouseEvent):void {
event.currentTarget.startDrag();
setChildIndex(MovieClip(event.currentTarget), numChildren - 1);
}
function mouseup1(event:MouseEvent):void {
var dropindex1:int = activeDropArray.indexOf(event.currentTarget);
var target:MovieClip = event.currentTarget as MovieClip;
target.stopDrag();
if(target.hitTestObject(activeDropArray[dropindex1])){
// target.x = activeHitArray[dropindex1].x;
//target.y = activeHitArray[dropindex1].y;
if(answer1_word.hitTestObject(word_select_box)){
gotoAndStop("6");
}
} else {
target.x = hitPositionsArray[dropindex1].xPos;
target.y = hitPositionsArray[dropindex1].yPos;
}
}
And the Error I'm getting through is:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at game_flv_fla::MainTimeline/frame6()
at flash.display::MovieClip/gotoAndStop()
at game_flv_fla::MainTimeline/mouseup1()
The only thing I can think of is that it is something to do with the gotoAndPlay() because when I place a trace into it's place I get no errors.
I copied your code, compiled and lauched it in Flash IDE. It works! :)
There were no errors.
But I know where the isue may lay. The addEventListeners are still on, no matter if there still are the objects they were linked to. You need to clean all active things before going to next frame:
if(target.hitTestObject(activeDropArray[dropindex1])){
if(answer1_word.hitTestObject(word_select_box)){
for (var i:uint = 0; i < activeDropArray.length; i++) {
activeDropArray[i].removeEventListener(MouseEvent.MOUSE_DOWN, mousedown1);
activeDropArray[i].removeEventListener(MouseEvent.MOUSE_UP, mouseup1);
}
gotoAndStop("6");
}
}
I have a class that controls an enemy. From within that class, it checks for collisions with an array on the main timeline. I've done it this way before and it works fine, so I have no idea what I've done wrong this time. It keeps giving me an
ReferenceError: Error #1069: Property
bulletArray not found on
flash.display.Stage and there is no
default value.
error from within the enemy class.
Here's my code (shortened to remove the unimportant parts):
On timeline:
var bulletArray:Array = new Array();
function shoot(e:TimerEvent)
{
var bullet:MovieClip = new Bullet(player.rotation);
bullet.x = player.x;
bullet.y = player.y;
bulletArray.push(bullet);
stage.addChild(bullet);
}
In class:
private var thisParent:*;
thisParent=event.currentTarget.parent;
private function updateBeingShot()
{
for (var i=0; i<thisParent.bulletArray.length; i++) {
if (this.hitTestObject(thisParent.bulletArray[i]) && thisParent.bulletArray[i] != null) {
health--;
thisParent.bulletArray[i].removeEventListener(Event.ENTER_FRAME, thisParent.bulletArray[i].enterFrameHandler);
thisParent.removeChild(thisParent.bulletArray[i]);
thisParent.bulletArray.splice(i,1);
}
}
Any help would be greatly appreciated! Thanks.
My guess is that event.currentTarget is the instance where you declared the bulletArray variable. Using event.currentTarget.parent will refer to stage outside your scope. I donĀ“t know how you declare the listeners. Try using event.target instead of event.currentTarget and see if you get the same error.
My advice is that you put all your code in a class.
If you are going to do it this way you need to pass in a reference to the timeline.
private var _timeline:Object;
// constructor
public function YourClass(timeline:Object) {
_timeline = timeline;
}
private function updateBeginShot() {
// ..
trace(_timeline.bulletArray); // outputs [array contents]
// ..
}