Francesco
Francesco

Reputation: 85

Removing objects of different types from the stage in AS3, using one method only

I am making a space invader kind of game in ActionScript3 and I have created a method to remove bullets from the stage:

private function removeBullet(bb:Bullet = null):void {

    var leng:uint = bulletVector.length;
    if (bb)
    {
        for (var i:uint = 0; i < leng; i++)
        {
            if (bulletVector[i] == bb) 
            {
                bulletVector.splice(i, 1);
                break;
            }                   
        }

        // Remove bullet from the Display List
        removeChild(bb);

        // Return the bullet to its object pool
        bulletPool.returnObject(bb);    

    } else {

        // Remove all existing bullets currently on screen
        for (var j:uint = 0; j < leng; j++)
        {
            var bullet:Bullet = bulletVector[j];
            removeChild(bullet);
            bulletPool.returnObject(bullet);
        }
        bulletVector.splice(0, leng);   
    }
}

bulletVector is a Vector that contains all the bullets that are currently displayed and bulletPool is an object pool class to return bullets to when they're not used on the stage anymore. If no argument is passed to the method, the method removes ALL the bullets on screen.

Now, I have an identical method to remove enemies from the screen:

private function removeEnemy(ee:Enemy = null):void {

    var leng:uint = enemyVector.length;
    if (ee)
    {
        for (var i:uint = 0; i < leng; i++)
        {
            if (enemyVector[i] == ee) 
            {
                enemyVector.splice(i, 1);
                break;
            }               
        }

        // Remove enemy from the Display List
        removeChild(ee);

        // Return the enemy to its object pool
        enemyPool.returnObject(ee); 

    } else {

        // Remove all existing enemies currently on screen
        for (var j:uint = 0; j < leng; j++)
        {
            var enemy:Enemy = enemyVector[j];
            removeChild(enemy);
            enemyPool.returnObject(enemy);
        }
        enemyVector.splice(0, leng);    
    }
}

Both 'bullets' and 'enemies' are classes that extend the Sprite class. My question is: is it possible to merge these two methods into one that handles both bullets AND enemies, depending on which one is passed as an argument?

[EDIT] What I have in mind is something like this: (pseudocode)

if (ee is Bullet) 
{ 
    var s:String = "bullet" 
} else if (ee is Enemy) 
{ 
    var s:String = "enemy" 
} 

eval[s+"Vector"].splice(i, 1); 
eval[s+"Pool"].returnObject(ee);

[/EDIT]

In other words, is there a syntax that allows to access Vectors and/or Classes (the object pools) without having to hardcode their name into the method?

Thanks in advance for any help.

Upvotes: 0

Views: 744

Answers (3)

JulianG
JulianG

Reputation: 4765

On second thought, I would now favour soft-typing over using Arrays, because it would not force you to change the rest of your application (e.g. you can keep your Vectors)

public function removeItem(list:*, pool:ObjectPool, item:Sprite):void
{
    // remove item from specified list
    var indx:int = list.indexOf(item);
    if (indx >= 0) 
    {
        list.splice(indx, 1);
    }
    // remove display object from display list
    if (this.contains(item))
    {
        this.removeChild(item);
    }           
    // return itemitem to specified pool
    pool.returnObject(item);
}

Note how you don't need to iterate the Vector to find out which index to remove (splice). You can use the indexOf method instead.

Upvotes: 0

JulianG
JulianG

Reputation: 4765

Short answer: Use Array instead of Vector for the lists of enemies and bullets.

Create a method that takes 3 arguments: a list:Array and an item:Sprite, and a pool:Array then remove the item from the specified Array, instead of 'hardcoding' the instance and ending up with two identical methods.

/**
 * Removes item from specified list
 * @param   list
 * @param   item
 */
public function removeItem( list:Array, item:Sprite, pool:Array ):void
{
    // implement here
}

Long Answer:

It's tricky because you're using Vectors.

My first impulse was to create a generic function taking 2 arguments, a list and an item: (let's ignore the pool for now)

/**
 * Removes item from specified list
 * @param   list
 * @param   item
 */
public function removeItem( list:Vector.<Sprite>, item:Sprite ):void
{
    // implement here
}

But I'm guessing your list of bullets is of type Vector. and your list enemies is of type Vector., right?

So even if both Bullet and Enemy extend Sprite, if you were to call this method using an instance of Vector., for instance:

var list:Vector.<Bullet>;
var item:Bullet; // extends Sprite
removeItem( list, item );

This wouldn't compile. You'd get:

Error: Implicit coercion of a value of type __AS3__.vec:Vector.<Bullet> to an unrelated type __AS3__.vec:Vector.<flash.display:Sprite>.

On a separate note

Your removeItem method seems to be doing two things. Removing a specified item and/or removing all items. I would keep these separate for safety and clarity. Each method should perform only one thing.

Also, with this setup, if at runtime your reference to an item is accidentally null, you'll end up removing all items from the list. Probably not what you wanted.

I would declare two functions:

function removeItem(...)

function removeAllItems(...)

Upvotes: 1

crooksy88
crooksy88

Reputation: 3851

Something like this might work for you...

private function removeItem(ee:* = null):void {

if (ee) {
//ee has a value

if (ee is Bullet) {
//remove bullet

} else if (ee is Enemy) {
//remove Enemy

}

} else {

//ee is null so remove all bullets and emenies

}
}

Upvotes: 3

Related Questions