Search code examples
actionscript-3movieclip

How to deal with multiple referencing of movieclips


im currently looking for both an efficient and effective way to create, control and delete movieclips in an effective manner. What i have thought about doing is to create a controller class which will handle the creation and deletion of movieclip using arrays and this script...

private static var enemyShips:Array = new Array();
public static function addEnemy(ship:MovieClip):void
    {
        enemyShips.push(ship);
        trace(enemyShips.length);
        ship.id = enemyShips.length - 1;
        Globals._stage.addChild(ship);          
    }
    public static function getEnemy():Array
    {
        return enemyShips;
    }

    public static function removeEnemy(i:int):void
    {
        var ep:ExplosionParticle;
        for(var j:int = 0; j < 150; j++)
        {
            ep  = new ExplosionParticle(enemyShips[i].x, enemyShips[i].y);
            Globals._stage.addChild(ep);
        }
        Globals._stage.removeChild(enemyShips[i]);
        updatePositions(enemyShips, i+1);
        enemyShips.splice(i, 1);
    }
private static function updatePositions(array:Array, position:int):void
    {
        for(var i:int = position; i < array.length;i++)
        {
            array[i].id -=1;

        }
    }

For a quick and simple explanation of some variables, Globals is there to allow the creation of instances inside a class with no direct access to the stage.

This script works fine until two cases occur.

The first case is when two movieclips are being created in the same frame, and the second case is deletion.

I know this is because of when the the first movieclip is created or removed in the frame, the sorting of the array occurs, making the second movieclip position null. My question however is, what is a more effective way to control such instances to prevent this occurance?

Keep in mind this is to control dynamically created movieclip instances.

Much obliged,

Raider00321


Solution

  • Try to separate your Model and your Controller classes. Leave everything that manipulates your ship appearance to your controller. Make sure when your model changes it notifies everyone, that wants to be notified, by dispatching events.

    This is your Model:

    package
    {
    import flash.events.EventDispatcher;
    
    public class ShipService extends EventDispatcher
    {
        private var ships:Array = new Array();
    
        public function add(ship:Ship):void
        {
            var index:int = ships.indexOf(ship);
            if (index >= 0) { // check if we already have this ship
                return;
            }
            ships.push(ship);
            ships.forEach(setNewIndexes);
            dispatchEvent(new ShipEvent(ShipEvent.ADDED, ship));
        }
    
        public function remove(ship:Ship):void {
            var index:int = ships.indexOf(ship);
            if (index < 0) { // check if we don't have this ship
                return;
            }
            ships.splice(index, 1);
            ships.forEach(setNewIndexes);
            dispatchEvent(new ShipEvent(ShipEvent.REMOVED, ship));
        }
    
        public function getAllShips() {
            return ships;
        }
    
        private function setNewIndexes(ship:MovieClip, index:int, arr:Array):void {
            ship.id = index;
        }
    }
    }
    

    This is your simple Controller:

    package  
    {
    import flash.display.DisplayObjectContainer;
    public class ShipController 
    {
        private var shipService:ShipService;
        private var battleField:DisplayObjectContainer;
    
        public function ShipController(battleField:DisplayObjectContainer, shipService:ShipService) 
        {
            this.battleField = battleField;
            this.shipService = shipService;
            this.shipService.addEventListener(ShipEvent.ADDED, onShipAdded);
            this.shipService.addEventListener(ShipEvent.REMOVED, onShipRemoved);
        }
    
        private function onShipAdded(e:ShipEvent):void 
        {
            battleField.addChild(e.ship);
            e.ship.x = 15;
            e.ship.y = 15;
            ship.sayHello(); // sayHello must be implemented
        }
    
        private function onShipRemoved(e:ShipEvent):void 
        {
            e.ship.blow(); // blow must be implemented
            battleField.removeChild(e.ship);
            var ships:Array = shipService.getAllShips();
            for each (var ship:Ship in ships) 
            {
                ship.cry();
            }
        }
    
    }
    }
    

    This is your Event class that will fly through your application and notify everybody about everything:

    package  
    {
    import flash.events.Event;
    
    public class ShipEvent extends Event 
    {
        public static const REMOVED:String = "ship_removed";
        public static const ADDED:String = "ship_added";
    
        public var ship:Ship;
    
        public function ShipEvent(type:String, ship:Ship; bubbles:Boolean = false, cancelable:Boolean = false) 
        { 
            super(type, bubbles, cancelable);
            this.ship = ship;
        } 
    
        public override function clone():Event 
        { 
            return new ShipEvent(type, ship, bubbles, cancelable);
        } 
    }
    
    }
    

    This is simple(and little) part of MVC pattern. Use it or make your own, and you will see big advantages soon.


    About dictionaries: why do you want to use it? As I remember it is implementation of HashMap (in AS3 HashMap that use simple-type objects as keys is Object() ) that uses Object as keys. I don't clearly understand what benefits it could give you.