Question

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);
        }
    }
}
Was it helpful?

Solution 4

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;
    }
}

OTHER TIPS

The following code is causing the problem, basically you are calling removeChild twice for the same object.

 if (tiles.contains(target)){
     trace("Contained!");
     tiles.removeChild(target);
 }
 tiles.removeChild(target);

In your code, I notice that you have the ability for the tile to be removed, and then try to remove it again at the end of this block :

        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);
            }
            // this is going to throw an error
            tiles.removeChild(target);

Make it easy on yourself and create a class for Tile with a remove method. Something like this:

class Tile extends Sprite
{
    public function remove():void
    {
        if(parent) parent.removeChild(this);
    }
}

This way, you can simply do:

tile.remove();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top