PDA

Просмотр полной версии : Проблема с доступом к объекту при вызове removeChild


EndoCrinologist
04.11.2015, 01:19
Изучаю AS3. Пытаюсь перевести игру Atary Asteroids из AS2 на AS3.
Вот класс Asteroids:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.utils.setTimeout;
/**
* ...
* @author Volodin Alexandr Sergeevich
*/
public class Asteroid extends Sprite
{
public static var THIS:Asteroid = null;

public var velX:Number = Math.random() * 6 - 3;
public var velY:Number = Math.random() * 6 - 3;
public var rotSpeed:Number = Math.random() * 3;
public var rotDir:Number = chooseDir();
public var frame:Number = 0;

public function Asteroid()
{
graphics.beginFill(0xabc098);
graphics.lineStyle(1);
graphics.moveTo(-50, -50);
graphics.lineTo(50, -50);
graphics.lineTo(50, 50);
graphics.lineTo(-50, 50);
graphics.lineTo(-50, -50);
graphics.endFill();

addEventListener(Event.ENTER_FRAME, onAstMove);
}

private function onAstMove(e:Event = null):void
{
this.x += this.velX;
this.y += this.velY;

if (this.x > Main.THIS.StageX + this.width) this.x = 0 - this.width;
if (this.y > Main.THIS.StageY + this.width) this.y = 0 - this.width;
if (this.x < 0 - this.width) this.x = Main.THIS.StageX + this.width;
if (this.y < 0 - this.width) this.y = Main.THIS.StageY + this.width;

this.rotation += this.rotDir * this.rotSpeed;

frame++;

if (frame % 10 == 0)
{
//Main.THIS.graphics.beginFill(0x00ffaa);
//Main.THIS.graphics.drawCircle(this.x, this.y, 3);
//Main.THIS.graphics.endFill();
}

if (this.hitTestPoint(Main.THIS.ship.x, Main.THIS.ship.y, true))
{
Main.THIS.isDead = true;
Main.THIS.shipDestroy();
}
}

private function chooseDir():Number
{
var rnd:Number = Math.random();
if (rnd > 0.5){return 1;} else return -1;
}

}

}

Вот класс Main:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;


/**
* ...
* @author Volodin Alexandr Sergeevich
*/
public class Main extends Sprite
{
public static var THIS:Main = null;

public var rotate:Number = 0;
public var thrust:Number = 0;

public var StageX:Number = 800;
public var StageY:Number = 600;

public var frame:Number = 0;

public var isDead:Boolean = false;

public function Main()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}

public var ship:Ship = new Ship();
private var ast_sprite:Sprite = new Sprite();

private function init(e:Event = null):void
{
THIS = this;

removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point

ship.x = StageX / 2;
ship.y = StageY / 2;

addChild(ship);

stage.addEventListener(KeyboardEvent.KEY_DOWN, shipControl);
stage.addEventListener(KeyboardEvent.KEY_UP, shipDecontrol);
ship.addEventListener(Event.ENTER_FRAME, onShipMove);

addChild(ast_sprite);

frame++;

for (var i:int = 0; i < 5; i++ )
{
var ast:Asteroid = new Asteroid();
addChild(ast);
}

}

private function shipDecontrol(e:KeyboardEvent):void
{
rotate = 0;
thrust = 0;
}

private function shipControl(e:KeyboardEvent):void
{
switch(e.keyCode)
{
case 37:
rotate = -1;
break;
case 38:
thrust = 0.3;
break;
case 39:
rotate = 1;
break;
case 40:
thrust = -0.3;
break;
}
}

private function onShipMove(e:Event = null):void
{
if (rotate) ship.rotation += rotate * 5;
if (Math.abs(thrust) > 0)
{
var rad:Number = ship.rotation * Math.PI / 180;
ship.thrustX = Math.cos(rad) * thrust;
ship.thrustY = Math.sin(rad) * thrust;

ship.velX += ship.thrustX;
ship.velY += ship.thrustY;
}

ship.x += ship.velX;
ship.y += ship.velY;

if (ship.x > StageX + ship.width) ship.x = 0 - ship.width;
if (ship.x < 0 - ship.width) ship.x = StageX + ship.width;

if (ship.y > StageY + ship.width) ship.y = 0 - ship.width;
if (ship.y < 0 - ship.width) ship.y = StageY + ship.width;
}

public function shipDestroy()
{
removeChild(ship);
}

}

}

Вот класс Ship:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;

/**
* ...
* @author Volodin Alexandr Sergeevich
*/
public class Ship extends Sprite
{
//private var spr : Sprite = new Sprite();

public var velX : Number = 0;
public var velY : Number = 0;
public var thrustX : Number = 0;
public var thrustY : Number = 0;

public function Ship()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, onStageShip);
}

private function onStageShip(e:Event = null):void
{
/*spr.graphics.beginFill(0x00ff00);
spr.graphics.lineStyle(1);
spr.graphics.moveTo(-20,-20);
spr.graphics.lineTo(20, 0);
spr.graphics.lineTo(-20, 20);
spr.graphics.endFill();*/

graphics.beginFill(0x00ff00);
graphics.lineStyle(1);
graphics.moveTo(-20,-20);
graphics.lineTo(20, 0);
graphics.lineTo(-20, 20);
graphics.endFill();

//addChild(spr);
}

public function shipDead():void
{
removeChild(this);
}
}

}

При соприкосновении астероида и корабля возникает такая ошибка:
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/removeChild()
at Main/shipDestroy()[Main.as:113]
at Asteroid/onAstMove()[Asteroid.as:58]


Что не так?

alexandrratush
04.11.2015, 10:52
Может быть в этом проблема: The supplied DisplayObject must be a child of the caller.

caseyryan
04.11.2015, 11:30
removeChild(this);
Эта запись эквивалентна такой:

this.removeChild(this);

Не может объект удалить самого себя из себя

EndoCrinologist
04.11.2015, 12:08
Я понял, что что-то не так с родителями/детьми. Я также пробовал способ удаления самой ship, когда в Main создавал функцию, удаляющую ship, но она вызывала такую же ошибку..
Класс Main:
public function shipDestroy()
{
removeChild(ship);
}

Вызов из Asteroids:
if (this.hitTestPoint(Main.THIS.ship.x, Main.THIS.ship.y, true))
{
Main.THIS.isDead = true;
Main.THIS.shipDestroy();
}

Или, я так понимаю, он всё равно из себя не сможет вызвать какую-то стороннюю функцию для удаления себя?

caseyryan
04.11.2015, 19:22
Не буду говорить на сколько сам код плохо написан, для новичка простительно. Поэтому сразу скажу по делу. Чтобы он мог удалиться из дисплей листа сам, можно сделать так:

if (parent) parent.removeChild(this);


Собственно делаем проверку на то есть ли у него родитель, и если есть, удаляем. Проверка нужна, чтобы он не падал с ошибкой, если он не находится в дисплей листе во время попытки удаления.

п.с. Таким образом объект никуда не удаляется, и продолжает и висеть в памяти и жрать ресурсы процессора (пока на него сохраняются ссылки). Он просто перестает отображаться