Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (539)
Games in Android Showcase (132)
games submitted by our members
Games in WIP (603)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Interesting problem I've run into with my particle cleanup. (WARNING:HUGE GIFS!)  (Read 1418 times)
0 Members and 1 Guest are viewing this topic.
Offline Rayvolution

« JGO Spiffy Duke »


Medals: 256
Projects: 2
Exp: 1 year


Resident Crazyman


« Posted 2014-03-14 01:59:08 »

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:
Click to Play


Here's the current code for when a blood particle stops:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
   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:
Click to Play


Click to Play


Click to Play

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Online LiquidNitrogen
« Reply #1 - Posted 2014-03-14 02:11:45 »

cant you just set the old particles alpha to the new one, and then delete the new one? that avoids adding and removing things from the set.

Offline BurntPizza

« JGO Bitwise Duke »


Medals: 289
Exp: 5 years



« Reply #2 - Posted 2014-03-14 02:13:33 »

If you're getting enough performance from a HashSet (I still cringed though), you could probably afford to store the object's BLOOD_ARRAY indices as values in a HashMap and get the same functionality and well as overwrite ability.

And what Liquid said. But that is how I would go about having overwrite ability with having to search anything.

And dear god don't index particle coords by Strings!  Shocked Pack integers, or something, anything but strings!

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
BLOOD_COLLECTOR = new HashMap<Long, Integer>(); //or use a Trove THashMap, then you won't be creating auto-boxed primitives, which are almost as bad as strings

...

private long pack(long x, int y) {
      return x<<32|y;
}

...

if (BloodController.BLOOD_COLLECTOR.containsKey(pack(bloodX, bloodY)){
      BloodController.BLOOD_ARRAY.set(BloodController.BLOOD_COLLECTOR.get(pack(bloodX, bloodY)), this); // or something
}


Alternative to Trove is HPPC: http://labs.carrotsearch.com/hppc.html
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Rayvolution

« JGO Spiffy Duke »


Medals: 256
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #3 - Posted 2014-03-14 02:27:24 »

If your getting enough performance from a HashSet (I still cringed though), you could probably afford to store the object's BLOOD_ARRAY indices as values in a HashMap and get the same functionality and well as overwrite ability.

And what Liquid said. But that is how I would go about having overwrite ability with having to search anything.

Yeah, Got to love HashSets, but in this case I couldn't think of any other logical way to easily store tens of thousands of variable coordinate values.

I am a bit of a noob with HashSets though, I'm not entirely following what you're saying. If I were to store the object in the BLOOD_ARRAY ID in the hash set, how would I be able to check if the new particle matches anything in the hash set? Wouldn't just about everything be a unique value and I'd never find a match?

A logical way (I think) to do it would be:
1> Check if this particle's X/Y matches something in the Hashset
2> If it does, fetch the old particle's object ID and run BloodController.BLOOD_ARRAY.remove(oldObjectIDHere);
3> If it doesnt match, add my X/Y coordinates and Object ID to the array.
4> Flick on some booleans so I don't have to do this check again while the update loop runs.
5> Delete myself if Alpha reaches zero.

I'm just unsure how I were to store the X,Y and ObjectID values in a single HashSet entry (IE:  x+","+y+","+objectID) how I would ever be able to find a match for step 1 to make step 2 fire?

I may be able to parse all the values into an array string and only compare the first 2 values in the array, but that would involving making a huge forloop that breaks down all the values one by one and compare them, and that'd be a crazy thing to do with 10k+ particles Sad

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Online LiquidNitrogen
« Reply #4 - Posted 2014-03-14 02:30:03 »

does it look wrong if you lower the number of particles and/or make them 2x2 pixels?

Offline BurntPizza

« JGO Bitwise Duke »


Medals: 289
Exp: 5 years



« Reply #5 - Posted 2014-03-14 02:42:56 »

@Ray

You missed my point: use a HashMap instead of HashSet.

HashSet: Collection of values. Used (in this case) to check if a value is already there.

HashMap: Collection of pairs of values. Used to check if a value is already there, and if so, replace it.

In this case, each pair is thus: (location, index)
The location functions exactly the same as before, to collision check. BUT we can then retrieve the particle (via it's array index) that we collided with at the same time.

Your code in pseudo: isParticleHere(x,y);
My code: getParticleIfHere(x,y); //and then remove() or reset it

The whole pack() thing is a more efficient way of storing the two coords in one entry: instead of string concatenation, it's bitwise concatenation. This works especially well in conjunction with a data structure that actually uses primitive values, (default Java ones do not) which can be found in the Trove or HPPC libs.

Look back at my code and see if it makes sense now.
Offline Rayvolution

« JGO Spiffy Duke »


Medals: 256
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #6 - Posted 2014-03-14 04:58:16 »

@Ray

You missed my point: use a HashMap instead of HashSet.

HashSet: Collection of values. Used (in this case) to check if a value is already there.

HashMap: Collection of pairs of values. Used to check if a value is already there, and if so, replace it.

In this case, each pair is thus: (location, index)
The location functions exactly the same as before, to collision check. BUT we can then retrieve the particle (via it's array index) that we collided with at the same time.

Your code in pseudo: isParticleHere(x,y);
My code: getParticleIfHere(x,y); //and then remove() or reset it

The whole pack() thing is a more efficient way of storing the two coords in one entry: instead of string concatenation, it's bitwise concatenation. This works especially well in conjunction with a data structure that actually uses primitive values, (default Java ones do not) which can be found in the Trove or HPPC libs.

Look back at my code and see if it makes sense now.

Hrm, it seems when I use HashMaps the game goes from running at a full 60 FPS with 8-9k particles landing on the ground (when the stopMoving() fires) to about 2 FPS. I'm thinking it's possibly because I am storing such large amounts of data that when it has to search for the values it's starting to crawl, it seems that HashSet is a *lot* faster to search through than HashMap is. :/

I do wonder if it's possibly bad implementation, but it seems like the problem is coming from when I search the existing Map for the X/Y coordinates, everything else runs fine. I imagine it's because when the "search" function fires it's having to dig through 10,000 or more (sometimes as much as 50k) values and it's chugging. But, HashSets didn't have this problem at all. I didn't see framerate drops until I was rendering around 50k particles, and I imagine that was actually mostly from rendering them, not the HashSet.

Although I can see how HashMap would be a lot better at storage/recall, but it seems like HashSet (even with strings) runs a bazillion times faster.

Here's my code though, in case I did something totally botched, and that's quite possible. I don't use HashSets *or* Maps very often. I was also storing the keys as hashCode, I know this isnt correct but it really wasnt an issue yet I just wanted a random Int value to set the key to for now. I hadnt even gotten past the search function before the code explodes anyway so I didn't make it to setting up more proper keys. A lot of this code doesn't actually "work" yet. But I line-by-line commented everything out, the big impacter is the .containsValue in the second IF statement, it's just way too CPU intensive with such a large HashMap Sad


EDIT: bloodMap is int[], 0 = x, 1 = y. By the way.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
         if ((!(hasCollided)) && (!(completedSweep))){
            // The big CPU killer
            if (BloodController.BLOOD_COLLECTOR.containsValue(bloodMap)){
               //System.out.println(BloodController.BLOOD_COLLECTOR.containsValue(bloodMap));
               BloodController.BLOOD_ARRAY.remove(this);
            }
      }
         if (!(addToCollector)){
            BloodController.BLOOD_COLLECTOR.put(this.hashCode(), bloodMap);
            addToCollector=true;
         }
         completedSweep = true;
         if (bloodAlpha <= 0.1){
            //This code doesnt work, I'm aware. Just hadnt gotten this far.
               BloodController.BLOOD_COLLECTOR.remove(this.hashCode());
               BloodController.BLOOD_ARRAY.remove(this);
            }


So, unless I botched up the use of the code (again, totally possible?), I'm back at square one since I can't pass the information with HashMaps without the game crawling. Cheesy

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 289
Exp: 5 years



« Reply #7 - Posted 2014-03-14 05:02:36 »

Did you try a map from HPPC or Trove? They should be far faster for this kind of work than the Java Collections.

You should also be using containsKey() on some hash of the coords, the value is the array index.

Is hashCode() overriden to my pack() function or similar, because it should be; otherwise you're not comparing the right things (the coords).

Fastest logic tree: (that I can think of, and assuming things about the rest of your code)

1> Check if this particle's X/Y matches something in the map
2> If it does, fetch the old particle's object ID and run BloodController.BLOOD_ARRAY.get(oldObjectIDHere).setAlpha(this.bloodAlpha); delete this;
3> If it doesn't match, add my X/Y coordinates and Object ID to the map.
4> Flick on some booleans so I don't have to do this check again while the update loop runs.
5> Delete myself if Alpha reaches zero.
Offline Rayvolution

« JGO Spiffy Duke »


Medals: 256
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #8 - Posted 2014-03-14 05:07:36 »

Did you try a map from HPPC or Trove? They should be far faster for this kind of work than the Java Collections.

I could give them a shot, that was my next step if I can't find another solution, I try to avoid tossing additional libraries in my code unless I need to. But reading about HPPC makes me think it would be something I'd want. Cheesy

Although to be honest, at the moment I'm happy with HashSet's speed, I just wish I had a logical way to access the object I "landed" on. My "Pixel Perfect" collision system (you can see it in-action in the gifs at the bottom of the OP) also uses HashSets and it seems to run like a champ as well.

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 289
Exp: 5 years



« Reply #9 - Posted 2014-03-14 05:30:01 »

Check my edit to the previous post.

Quick implementation that should be fast:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
class BloodParticle {
      float x,y, bloodAlpha;
     
      ...

      @Override
      //contains additional manipulation to shrink x and y to 16 bits
      //and pack them into a 32 bit int. Alternatively, use a custom,
      //non-overriding version that returns a long

      //Basically we just need a fast way to create a unique integer from
      //two, so that no different sets of input create the same output.
      public int hashCode() {
            return ((int)x&0xFFFF)<<16|((int)y&0xFFFF);
      }
}

...
//If using a hashCode that returns an int, have BLOOD_COLLECTOR be an IntIntMap, otherwise a LongIntMap, assuming HPPC

if (!hasCollided && !completedSweep){
      int hash = hashCode();
      if (BloodController.BLOOD_COLLECTOR.containsKey(hash){ //particle with same coords is already in the map
            BloodController.BLOOD_ARRAY.get(BloodController.BLOOD_COLLECTOR.get(hash)).bloodAlpha = bloodAlpha; //so set it's alpha to our alpha
            BloodController.BLOOD_ARRAY.remove(this); //CAREFUL: if BLOOD_ARRAY is a List, all the indices after this one will shift down when we remove(),
                                                      //so perhaps use a GapList or Bag type
      }
}

//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.put(hashCode(), /*index in BLOOD_ARRAY of current particle*/);
      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(hashCode());
      BloodController.BLOOD_ARRAY.remove(BloodController.BLOOD_COLLECTOR.get(hashCode())); //removing specifc index, way faster than searching;
                                                                                       //but, again, don't simply remove() with a List, will break our hashing system
}
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Rayvolution

« JGO Spiffy Duke »


Medals: 256
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #10 - Posted 2014-03-14 06:06:12 »

Check my edit to the previous post.

Quick implementation that should be fast:
<SNIP>

I'll give your version a shot in the morning, I'm too half-awake to process any kind of math/logic anymore. It looks very promising though. Wink

If it's still too slow though, I'll give HPPC a shot.

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline ewg

Junior Devvie


Medals: 8


Java games rock!


« Reply #11 - Posted 2014-03-14 06:58:35 »

Another approach you could try is when particles stop moving to immediately delete the particle object and write them to a tile of an overlay texture and render these blood and guts texture tiles over top of your existing map tiles.  This way you could pile up as much detail as you want in these overlay tiles for a constant cost and you would not need to fade out your particles, so you could make permanent bullet holes and such.

When a tile goes off screen you could decide if you want to save that overlay data so it will look the same when to player comes back, or to discard it and have it look like new when the player returns.
Online Roquen
« Reply #12 - Posted 2014-03-14 08:10:14 »

From a quick skim you is this what you want: a true or false for a given x,y coordinate?  Some 2->1 mapping (z-curve or just pack) and some BitSet.
Offline ctomni231

JGO Wizard


Medals: 99
Projects: 1
Exp: 7 years


Not a glitch. Just have a lil' pixelexia...


« Reply #13 - Posted 2014-03-15 21:34:22 »

Instead of deleting the particles, couldn't you just perform a replace. Store the value of new particles and delete the old ones instead. Maybe you can even blend the two colors. It looks really good, if Hashset is giving results best keep with that. I would just focus on the particles and making sure the colors combine, or the freshest particle is always given display priority.

Offline saucymeatman
« Reply #14 - Posted 2014-03-16 17:13:46 »

These blood partical effects are the coolest I've ever seen.
Great job, this game is going to be sick.
Offline Rayvolution

« JGO Spiffy Duke »


Medals: 256
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #15 - Posted 2014-03-16 17:30:48 »

Instead of deleting the particles, couldn't you just perform a replace. Store the value of new particles and delete the old ones instead. Maybe you can even blend the two colors. It looks really good, if Hashset is giving results best keep with that. I would just focus on the particles and making sure the colors combine, or the freshest particle is always given display priority.

That's the problem, I can't figure out how to access the first "particle object" on the ground because the new one doesn't know the other object's ID. I got distracted in FL Studio so I haven't gone back to this problem yet, but I am really curious if I can get it to work at full speed with the HPPC method. :/

Another approach you could try is when particles stop moving to immediately delete the particle object and write them to a tile of an overlay texture and render these blood and guts texture tiles over top of your existing map tiles.  This way you could pile up as much detail as you want in these overlay tiles for a constant cost and you would not need to fade out your particles, so you could make permanent bullet holes and such.

When a tile goes off screen you could decide if you want to save that overlay data so it will look the same when to player comes back, or to discard it and have it look like new when the player returns.

That was my first idea, and that works like a champ. Problem is it's a huge resource hog, because I have to load/write to the image buffer for every single particle that hits the floor, so I end up writing to the buffer up to 100-150 times almost all at once every time there's a blood splatter. Sad

To make matters worse, to "fade" each particle one by one with that method I have to run a forloop lowering the alpha value of each pixel separately, so I'm running a non-stop forloop for every single overlay that's active. Sad

It's a wonderful idea on paper though, it was the first thing I tried because I figured it would cut down on particles on the map, since once they stop moving they don't need to be "particles" anymore. Cheesy

These blood partical effects are the coolest I've ever seen.
Great job, this game is going to be sick.

Thanks! I actually improved it slightly since those GIFs too, it looks more more... bloody now. Wink

I'm half tempted to make a mini engine-goof-around game and release it, that's basically my naked guy in a room full of collision objects and you can play with blood splatters. Now that the system is functionally complete (aside from this issue, but the newest version of the blood actually hides it a bit incidentally) I find myself playing around with it in my game while I'm pondering what to do next. Tongue

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Offline ewg

Junior Devvie


Medals: 8


Java games rock!


« Reply #16 - Posted 2014-03-16 21:40:27 »


Another approach you could try is when particles stop moving to immediately delete the particle object and write them to a tile of an overlay texture and render these blood and guts texture tiles over top of your existing map tiles.  This way you could pile up as much detail as you want in these overlay tiles for a constant cost and you would not need to fade out your particles, so you could make permanent bullet holes and such.

When a tile goes off screen you could decide if you want to save that overlay data so it will look the same when to player comes back, or to discard it and have it look like new when the player returns.

That was my first idea, and that works like a champ. Problem is it's a huge resource hog, because I have to load/write to the image buffer for every single particle that hits the floor, so I end up writing to the buffer up to 100-150 times almost all at once every time there's a blood splatter. Sad

To make matters worse, to "fade" each particle one by one with that method I have to run a forloop lowering the alpha value of each pixel separately, so I'm running a non-stop forloop for every single overlay that's active. Sad

It's a wonderful idea on paper though, it was the first thing I tried because I figured it would cut down on particles on the map, since once they stop moving they don't need to be "particles" anymore. Cheesy

I assume you mean that you implemented it by writing the particles to a Pixmap(a texture that is in regular RAM and altered using the CPU) and then converting that to a texture and rendering it, which will be slow because the texture need to be repeatedly uploaded to graphics memory and because editing a texture with the CPU is slower than using the GPU.  It should perform better if you use an FBO(a texture that stays in graphics memory and is altered by rendering to it) like this:

for each tile of the map on the screen:
-render the map tile to the normal framebuffer
-render all stopped particles to the part of the FBO reserved for that map tile (and delete these stopped particles from the particle system)
-render the FBO texture region assigned to that map tile to the normal framebuffer
-render the moving particles to the normal framebuffer

If a map tile goes outside the screen you would reassign that portion of the FBO to the new tile that is shown on the opposite side of the screen.  You could save the contents of the reassigned FBO texture region if you wish by using glReadPixels. Since you would not be doing that every frame performance would probably be good.
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 289
Exp: 5 years



« Reply #17 - Posted 2014-03-16 22:11:55 »

@ewg
He's already got the rendering figured out, it's more or less what you describe (he's using Slick though, not sure how fine grained the control is there), his problem is how the particle engine manages particles that must interact with each other, which I posted a solution for. All that remains to be seen is if my solution performs acceptably.
Offline ctomni231

JGO Wizard


Medals: 99
Projects: 1
Exp: 7 years


Not a glitch. Just have a lil' pixelexia...


« Reply #18 - Posted 2014-03-19 06:00:06 »

Instead of deleting the particles, couldn't you just perform a replace. Store the value of new particles and delete the old ones instead. Maybe you can even blend the two colors. It looks really good, if Hashset is giving results best keep with that. I would just focus on the particles and making sure the colors combine, or the freshest particle is always given display priority.

That's the problem, I can't figure out how to access the first "particle object" on the ground because the new one doesn't know the other object's ID. I got distracted in FL Studio so I haven't gone back to this problem yet, but I am really curious if I can get it to work at full speed with the HPPC method. :/

Ahhh... okay.

In that case, I'd just look at the map for the data and grab the ground pixel color data once, when the particle stops moving. Then, I'd blend the "ground" color with the "blood" color moving from max blood color to 1/2 between each color until the pixel is halfway between both colors before merging the pixel with the background.

I'm just following up for the sake of following up at this point. Hopefully you are able to solve it using either BurntPizza's or the HPPC method.

Offline Rayvolution

« JGO Spiffy Duke »


Medals: 256
Projects: 2
Exp: 1 year


Resident Crazyman


« Reply #19 - Posted 2014-03-19 07:21:42 »

Instead of deleting the particles, couldn't you just perform a replace. Store the value of new particles and delete the old ones instead. Maybe you can even blend the two colors. It looks really good, if Hashset is giving results best keep with that. I would just focus on the particles and making sure the colors combine, or the freshest particle is always given display priority.

That's the problem, I can't figure out how to access the first "particle object" on the ground because the new one doesn't know the other object's ID. I got distracted in FL Studio so I haven't gone back to this problem yet, but I am really curious if I can get it to work at full speed with the HPPC method. :/

Ahhh... okay.

In that case, I'd just look at the map for the data and grab the ground pixel color data once, when the particle stops moving. Then, I'd blend the "ground" color with the "blood" color moving from max blood color to 1/2 between each color until the pixel is halfway between both colors before merging the pixel with the background.

I'm just following up for the sake of following up at this point. Hopefully you are able to solve it using either BurntPizza's or the HPPC method.

I actually just finished the system finally and was coming here to report the results. Cheesy

Oddly enough, I used a method a lot like your suggestion. (Maybe the final product was about what you were thinking?) I tossed out the entire HashSet concept, and instead made an ArrayList of Arraylists of 32x32 ImageBuffers that covered the map. The Array of Arrays was for X/Y coordinates basically, and the actual images are created on-demand as needed.

When there's a blood splatter, the moment the blood hits the ground it's deleted, and it's RGBA data is sent to the ImageBuffer object in that location, if no image has been created for that tile it generates one and draws the blood pixel to it, if one already exists it just adds to it. Then over time as the blood "decays", it detects when the image is fully transparent again and then deletes itself so there's not just a blank ImageBuffer sitting in memory wasting space.

The end result now is I have a much faster particle system. Basically once all the particles stop moving I'm only rendering a handful of 32x32 images *and* because I constantly just drawing on top of the existing image the fading issue is completely gone, because if a new particle lands on an almost decayed space the pixel data is just updated on the image. I still see framerate drops when I get to about 20-30k particles, but because everything is written to the image tiles so quickly there's really no realistic way to reach anything more than a few thousand particles at once anyway unless I do something silly like generate 100,000 in a forloop all at once. Chances are the player wont see more than a few hundred actively moving before they are written to the ImageBuffer, so I think the systems about as fast as it can be at the moment. Cheesy

Cool side effect is I can easily draw others things to the new ImageBuffer tiles, so in the future if I want to draw other particle effects like dirt, rain, snow, I can easily call up the same tiles and just draw different particles to them.

BurntPizza: Even though I didn't use your idea, I still appreciate the time writing up the code examples. I'll probably use a similar concept in the future. I have a few other places that use HashSets and I think your method will speed them up a bit. Wink

- Raymond "Rayvolution" Doerr.
Retro-Pixel Castles - Survival Sim/Builder/Roguelike!
LIVE-STREAMING DEVELOPMENT: http://www.twitch.tv/SG_Rayvolution
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

rwatson462 (33 views)
2014-12-15 09:26:44

Mr.CodeIt (23 views)
2014-12-14 19:50:38

BurntPizza (51 views)
2014-12-09 22:41:13

BurntPizza (84 views)
2014-12-08 04:46:31

JscottyBieshaar (45 views)
2014-12-05 12:39:02

SHC (59 views)
2014-12-03 16:27:13

CopyableCougar4 (59 views)
2014-11-29 21:32:03

toopeicgaming1999 (123 views)
2014-11-26 15:22:04

toopeicgaming1999 (114 views)
2014-11-26 15:20:36

toopeicgaming1999 (32 views)
2014-11-26 15:20:08
Resources for WIP games
by kpars
2014-12-18 10:26:14

Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!