I am trying to code a tile-based level editor, in which the Main class adds Tile class instances as children of the 'tiles' movieclip when clicking/dragging the mouse. I am able to add tiles to the container, and they show on stage, however I cannot remove any tiles when erasing them is enabled. It gives me the following error
Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/removeChild()
at Main/Draw()
at Main/::Go()
Also, when I check if the tile is inside the tiles container, it tells me that the parent is null.
So, a little help? I tried checking other questions with similar issues but none seemed to be close to mine.
package {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.Stage;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
//import flash.events.TimerEvent.updateAfterEvent;
public class Main extends MovieClip {
//containers
var lines:Sprite = new Sprite();
var tiles:Sprite = new Sprite();
// Grid data
var tileW:int = 20;
var tileH:int = 20;
var gridW:int = 20;//(inputWidth);
var gridH:int = 20;//(inputHeight);
var gridX:int = 50;
var grixY:int = 50;
var level:Array;
//Drawing variables
var go:Boolean = false;
var erase:Boolean = false;
var default_tile:int = 1;
var type:int;
var rect:Object = {x:100, y:50, width:(gridW * tileW)/100, height:(gridH * tileH)/100};
//menus
var sizeMenu:SizeMenu = new SizeMenu();
var current:Tile = new Tile();
public function Main():void {
//Flash alignment and resizing
stage.scaleMode=StageScaleMode.NO_SCALE;
stage.align=StageAlign.TOP_LEFT;
stage.addChild(lines);
lines.x = rect.x;
lines.y = rect.y;
stage.addChild(tiles);
tiles.x = rect.x;
tiles.y = rect.y;
stage.addChild(sizeMenu);
stage.addChild(current);
current.x = 50;
current.gotoAndStop(default_tile);
stage.addEventListener(MouseEvent.MOUSE_DOWN, Go);
stage.addEventListener(MouseEvent.MOUSE_UP, Go);
stage.addEventListener(MouseEvent.MOUSE_MOVE, Go);
stage.addEventListener(KeyboardEvent.KEY_DOWN, ToggleErase);
stage.addEventListener(KeyboardEvent.KEY_UP, ToggleErase);
Setup();
}
//Draws grid lines
private function Setup():void {
trace("Drawing Grid...");
// create an empty array
level = new Array(gridH);
for (var i=0; i < gridW; i++) {
level[i] = new Array(gridW);
}
// attach lines to create a grid
for (var k=0; k <= gridH; k++) {
var line = new Line();
line.name = "line"+k;
line.scaleX = rect.width;
line.y = tileH * k;
lines.addChild(line);
for (var j=0; j <= gridW; j++) {
line = new Line();
line.name = "line"+j+"_"+k;
line.scaleX = rect.height;
line.x = tileW * j;
line.rotation = 90;
lines.addChild(line);
}
}
type = default_tile;
trace("Done drawing grid!");
}
//Decided if drawing is possible
private function Go(e:MouseEvent):void {
if (e.type == "mouseDown") {
go = true;
Draw(e);
}
if (e.type == "mouseUp") {
go = false;
}
if (e.type == "mouseMove") {
if (go) {
Draw(e);
}
//e.updateAfterEvent();
}
}
//Toggles erase
private function ToggleErase(e:KeyboardEvent):void{
if (e.shiftKey){
erase = true;
}
if (e.type == "keyUp"){
erase = false;
}
}
// attaches the tiles when drawn on the grid
public function Draw(e:MouseEvent) {
var x = mouseX;
var y = mouseY;
var cx = Math.floor((x - rect.x) / tileW);
var cy = Math.floor((y - rect.y) / tileH);
if (cx >= 0 && cx < gridW && cy >= 0 && cy < gridH) {
var target = e.currentTarget;
if (!erase) {
if (tiles.contains(target)){
trace("Contained!");
tiles.removeChild(target);
}
var tile = new Tile();
tiles.addChild(tile);
tile.name = ("t_" + cy + "_" + cx);
tile.x = (tileW * cx);
tile.y = (tileH * cy);
tile.gotoAndStop(type);
level[cy][cx] = type;
} else {
if (tiles.contains(target)){
trace("Contained!");
tiles.removeChild(target);
}
level[cy][cx] = default_tile - 1;
}
}
}
//Cleans the grid and redraws it
private function ResetGrid():void {
level = null;
//Delete tiles
while (tiles.numChildren) {
tiles.removeChildAt(0);
}
//Delete lines
while (lines.numChildren) {
lines.removeChildAt(0);
}
gridW=20;
gridH=20;
rect.width = (gridW * tileW)/100;
rect.height = (gridH * tileH)/100;
}
// updates the current-clip
private function update() {
current.gotoAndStop(type);
}
}
}
I have resolved my issue! All tile instances are given a name based on their position on the grid when added. Instead of making target the object the mouse was pointing at, I used getChildByName(); to search if there was already an object with a specific name, and to erase it if it did.
if (cx >= 0 && cx < gridW && cy >= 0 && cy < gridH) {
var target = tiles.getChildByName("t_" + cy + "_" + cx);
if (!erase) {
if (target){
tiles.removeChild(target);
}
var tile = new Tile();
tiles.addChild(tile);
tile.name = ("t_" + cy + "_" + cx);
tile.x = (tileW * cx);
tile.y = (tileH * cy);
tile.gotoAndStop(type);
level[cy][cx] = type;
} else {
if (target){
tiles.removeChild(target);
}
level[cy][cx] = default_tile - 1;
}
}