Interesting problem I've run into with my particle cleanup. (WARNING:HUGE GIFS!)

Alrighty, so I’ve made this really fun “blood particle” system, after 2 straight days of coding/optimizing I’ve got it running crazy calculations on about 20k-30k of these little guys before the framerate starts to drop. They have full pixel-perfect collision detection, and even “drip” down off the objects they hit. Really fun stuff!

Well, part of my optimization steps are to remove any particles that are no longer moving that are overlapping another particle. Because there’s no point in rendering both if you can only see one, and when we’re talking 10k+ particles on average being tracked it’s really important to remove unneeded ones.

The way it currently works, is every time a particle “stops”. It records it’s X and Y coordinates to a HashSet. But, before that, if checks it’s X and Y against the values already in the HashSet, if those coordinates already exist, the particle deletes itself instead. It works like a champ, perfectly deleting every single overlapping particle.

But there’s only one problem, my blood “fades away” (Alpha levels drop slowly until it’s invisible, then it deletes itself), well, when “fresh” blood lands on almost completely invisible blood the fresh blood deletes itself. It would look a lot better if the OLD blood already on the ground is deleted and replaced with the new blood. :wink:

Here’s one showing off the issue I am describing above:

http://sixtygig.com/junk/bloodIssue.gif

Here’s the current code for when a blood particle stops:


	public void stopMoving() throws SlickException {

   		//BloodX and Y are floats, but now that we've stopped I want them to be a int value.
		bloodX = (int)bloodX;
		bloodY = (int)bloodY;

   		//100% sure the particle is no longer moving, just in case I fired and it still is.
		bloodSpeedX = 0;
		bloodSpeedY = 0;

   		//Start fading really slowly.
		bloodAlpha -= random.nextFloat()/600;
   		bloodColor = new Color(255,255,255,bloodAlpha);
   		
   		//I am not colliding with anything, and this is the first update sweep. Let's check and see if a particle already exists where I landed.
   		if ((!(hasCollided)) && (!(completedSweep))){
	   		if (BloodController.BLOOD_COLLECTOR.contains((int)bloodX+","+(int)bloodY)){
	   			BloodController.BLOOD_ARRAY.remove(this);
	   		}
		}

   		//Add me to the collector if I wasnt deleted by the above FORLOOP. Then, turn on the boolean so I don't record over and over again.
   		if (!(addToCollector)){
	   		BloodController.BLOOD_COLLECTOR.add((int)bloodX+","+(int)bloodY);
	   		addToCollector=true;
   		}

   		//The first sweep is completed, don't worry about processing all these loops every update now.
   		completedSweep = true;

   		//My alpha level has reached zero, time to be deleted and removed from the HashSet.
   		if (bloodAlpha <= 0){
   	   		BloodController.BLOOD_COLLECTOR.remove((int)bloodX+","+(int)bloodY);
   	   		BloodController.BLOOD_ARRAY.remove(this);
   	   	}
	}

The above code works great, but does anyone have any suggestions on how to make it delete the old particle instead of itself?

Here’s some GIFs to showoff my system, it was a blast (hah!) to make:

http://sixtygig.com/junk/blood1.gif

http://sixtygig.com/junk/blood2.gif

http://sixtygig.com/junk/blood3.gif