Removing objects from an array not working

I can’t use shift() or splice() and it’s driving me insane:

var glength:int = gatActivePool.length;
for (var a:int = 0; a < glength; a+=1) {
	var gatling:PBulletGat = gatActivePool[a];
	if (gatling.dead) {
	// If it's not already in the InactivePool, push it in
		if (gatInactivePool.indexOf(gatling) < 0) gatInactivePool.push(gatling);
		// Remove it from the ActivePool...
		// CAUSES NULL OBJECT ERROR:
		//gatActivePool.shift();
		// SAME:
		gatActivePool.splice(gatActivePool.indexOf(gatling), 1); // doesn't work with splice(a, 1) either				
	} else { 
		gatling.update();
	}
}

As you probably guessed, this is for a game. Elsewhere, in a shoot() method I have this:

var gat:Gat1 = gatInactivePool.shift();
gatActivePool.push(gat);
gat.spawn();

So while the player is shooting (adding to the active pool), the game will add the bullet back to the inactive pool if it leaves the screen. So there’s a lot of shifting going on, which is why I figured I was getting a null return when I used splice() (hard to get an index position if the index keeps changing), so I tried shift instead to blindly remove the first element, but that didn’t work either.

So does anyone have any idea why I can’t remove anything from the gatActivePool array at all? Is there a better way to recycle particles?

Did you checked if this returns positive value? ActionScript Code:
[LEFT]gatActivePool.[COLOR=#0000ff]indexOf[/COLOR]COLOR=#000000[/COLOR][/LEFT]

Meaning, you don’t always add gatling to gatActivePool, so how do you expect it always to be there?
Anyway, I’d use Array.filter() to remove multiple items from array based on some conditional statement.

var Gatling:Function = function():void {
 this.dead = false;
 this.setDead = function():void {
  this.dead = true;
 }
 this.toString = function():String {
  return '[Gatling dead='+this.dead+']';
 }
}
var gatlings:Array = [];
for(var i:int=0; i<100; i++){
 gatlings.push(new Gatling());
 if(Math.round(Math.random())){
  gatlings*.setDead();
 }
}
trace(gatlings);
trace('======================');
gatlings = gatlings.filter(filterGatlings);
function filterGatlings(o:*, i:int, a:Array):Boolean {
 if(o.dead) return false;
 return true;
}
trace(gatlings);

Here’s an example

Hi I think In the for loop when you are checking the index it will always return the last one.Try to use another variable so that you can keep the track of current bullet’s index

[quote=cold wolf;2334530]I can’t use shift() or splice() and it’s driving me insane:

 ActionScript Code:
 [LEFT][COLOR=#000000]**var**[/COLOR] glength:[COLOR=#0000ff]int[/COLOR] = gatActivePool.[COLOR=#0000ff]length[/COLOR];

[COLOR=#0000ff]for[/COLOR] [COLOR=#000000]([/COLOR][COLOR=#000000]var[/COLOR] a:[COLOR=#0000ff]int[/COLOR] = [COLOR=#000080]0[/COLOR]; a < glength; a+=[COLOR=#000080]1[/COLOR][COLOR=#000000])[/COLOR] [COLOR=#000000]{[/COLOR]
    var gatling:PBulletGat = gatActivePool[COLOR=#000000][[/COLOR]a[COLOR=#000000]][/COLOR];
    if COLOR=#000000[/COLOR] [COLOR=#000000]{[/COLOR]
    [COLOR=#808080]// If it’s not already in the InactivePool, push it in[/COLOR]
        if [COLOR=#000000]([/COLOR]gatInactivePool.[COLOR=#0000ff]indexOf[/COLOR]COLOR=#000000[/COLOR] < [COLOR=#000080]0[/COLOR][COLOR=#000000])[/COLOR] gatInactivePool.[COLOR=#0000ff]push[/COLOR]COLOR=#000000[/COLOR];
        [COLOR=#808080]// Remove it from the ActivePool…[/COLOR]
        [COLOR=#808080]// CAUSES NULL OBJECT ERROR:[/COLOR]
        [COLOR=#808080]//gatActivePool.shift();[/COLOR]
        [COLOR=#808080]// SAME:[/COLOR]
        gatActivePool.[COLOR=#0000ff]splice[/COLOR][COLOR=#000000]([/COLOR]gatActivePool.[COLOR=#0000ff]indexOf[/COLOR]COLOR=#000000[/COLOR], [COLOR=#000080]1[/COLOR][COLOR=#000000])[/COLOR]; [COLOR=#808080]// doesn’t work with splice(a, 1) either                [/COLOR]
    [COLOR=#000000]}[/COLOR] [COLOR=#0000ff]else[/COLOR] [COLOR=#000000]{[/COLOR]
        gatling.[COLOR=#000080]update[/COLOR]COLOR=#000000[/COLOR];
    [COLOR=#000000]}[/COLOR]
[COLOR=#000000]}[/COLOR]
[/LEFT]

As you probably guessed, this is for a game. Elsewhere, in a shoot() method I have this:

 ActionScript Code:
 [LEFT][COLOR=#000000]**var**[/COLOR] gat:Gat1 = gatInactivePool.[COLOR=#000080]shift[/COLOR][COLOR=#000000]([/COLOR][COLOR=#000000])[/COLOR];

gatActivePool.[COLOR=#0000ff]push[/COLOR]COLOR=#000000[/COLOR];
gat.[COLOR=#000080]spawn[/COLOR]COLOR=#000000[/COLOR];
[/LEFT]

So while the player is shooting (adding to the active pool), the game will add the bullet back to the inactive pool if it leaves the screen. So there’s a lot of shifting going on, which is why I figured I was getting a null return when I used splice() (hard to get an index position if the index keeps changing), so I tried shift instead to blindly remove the first element, but that didn’t work either.

So does anyone have any idea why I can’t remove anything from the gatActivePool array at all? Is there a better way to recycle particles?[/quote]

[QUOTE=wvxvw;2334658]Did you checked if this returns positive value? ActionScript Code:
[LEFT]gatActivePool.[COLOR=#0000ff]indexOf[/COLOR]COLOR=#000000[/COLOR][/LEFT]

Meaning, you don’t always add gatling to gatActivePool, so how do you expect it always to be there?[/QUOTE]

Yes, I’ve already checked and it does return a valid index position (0 and up). I forgot to mention I created 200 gatling particles and push them into the Inactive pool. And as you saw, every time I spawn one it gets shifted from the Inactive pool and pushed into the Active pool. This code is error-free, which makes sense, but when I try to get rid of an object in the Active pool, it returns the error, which doesn’t make sense. I’ve triple-checked and there is always a valid index, it just changes a lot–hundreds of times per second in fact.

[QUOTE=wvxvw;2334658]Anyway, I’d use Array.filter() to remove multiple items from array based on some conditional statement.

var Gatling:Function = function():void {
 this.dead = false;
 this.setDead = function():void {
  this.dead = true;
 }
 this.toString = function():String {
  return '[Gatling dead='+this.dead+']';
 }
}
var gatlings:Array = [];
for(var i:int=0; i<100; i++){
 gatlings.push(new Gatling());
 if(Math.round(Math.random())){
  gatlings*.setDead();
 }
}
trace(gatlings);
trace('======================');
gatlings = gatlings.filter(filterGatlings);
function filterGatlings(o:*, i:int, a:Array):Boolean {
 if(o.dead) return false;
 return true;
}
trace(gatlings);

Here’s an example[/QUOTE]

I’ve considered using filter but had to dismiss the option due to the performance hit it would cost to run it at the speed required. This is a game after all, and so every operation counts–function calls quadruply so :slight_smile: Thank you for your help though.

[QUOTE=sudhansurana;2334660]Hi I think In the for loop when you are checking the index it will always return the last one.Try to use another variable so that you can keep the track of current bullet’s index[/QUOTE]

Sorry, I don’t understand what you mean. In the code I posted I did a search for the index position of the object I was looking for and used that index in the splice() method. How would it always return the last one? Anyway, I’ve tested this before (and I just tested it again) and the code

gatActivePool.indexOf(gatling)

returns the correct index position, and it is the same code I use in the splice() method. Unless I completely misunderstood you…? Thank you for replying too :slight_smile:

I wanted to bump this thread since I found a solution, thanks to someone over at Actionscript.org forums.

The for loop was getting messed up when I tried to splice the array because the length was always changing. To solve this one should count backwards, like this:

for (var i:int = glength - 1; i >= 0; --i) {...}

To be honest, I’m not exactly savvy on the details of this solution, but I will definitely remember it.

Cheers.

Sorry to tell ya… but filter() works nearly 4 times faster than for loop… :wink:

var Gatling:Function = function():void {
	this.dead = false;
	this.setDead = function():void {
		this.dead = true;
	} 
	this.toString = function():String {
		return '[Gatling dead='+this.dead+']';
	}
}
var gatlings:Array = [];
for(var i:int=0; i<10000; i++){
	gatlings.push(new Gatling());
	if(Math.round(Math.random())){
		gatlings*.setDead();
	}
}
var gatlings_for:Array = gatlings.slice();
var gatlings_filter:Array = gatlings.slice();
//trace(gatlings);
trace('========= filter test ========');
var time:int = 0;
var t:int = getTimer();
gatlings_filter = gatlings_filter.filter(filterGatlings);
time = getTimer() - t;
trace('done in '+time+' s');
trace('========= end filter test ========');
function filterGatlings(o:*, i:int, a:Array):Boolean {
	if(o.dead) return false;
	return true;
}
trace('========= for test ========');
time = 0;
t = getTimer();
var g_length:int;
var gl:int = gatlings_for.length - 1;
for(g_length = gl; Boolean(g_length); g_length-=1){
	if(gatlings_for[g_length].dead) gatlings_for.splice(g_length, 1);
}
time = getTimer() - t;
trace('done in '+time+' s');
trace('========= end for test ========');

You may try it yourself…
I get these results for the above code:

========= filter test ========
done in 4 s
========= end filter test ========
========= for test ========
done in 16 s
========= end for test ========

That’s fantastic! Thank you very much for showing me this, I had no idea it would do that. I read somewhere that method calls were expensive in general, but I didn’t think for loops would be much of a concern. Very interesting. This once again proves that I should test test test–there’s an extremely high probability that I’ll be surprised :slight_smile:

Cheers mate!

Array methods are supposed to perform some routine operations faster than a general purpose algorythms (othervise there would be no sence in implementig them =) In general, saying that method calls are expensive would be true, but, technically, it depends on how many methods the called object has (the same goes for static against instance’s methods - while there are fewer statc methods they are accessed faster, but, once you have a bunch of static methods it’ll work the same =)
And, yes, untill you try - you can never be sure, what would work faster =)