Collidable Particles

Developer
Aug 13, 2008 at 3:10 AM
Is any one interested in adding particles that will collide with all the shapes they already have. I had a slightly modified version of the engine that would use regular bodies as particles but did not perform the rotation calculations. It was pretty fast. On an old POS laptop I was easily getting 1000 particles with almost no lag. I did a performance test using the particles as rain and with 750 constantly pouring onto my objects it looked a lot like real rain. If anyone is interested I will try find the code or just redo it so you can play with it.

Also very interested in the Inactivity Controller dp2208.
Coordinator
Aug 13, 2008 at 8:33 PM
I would like to see a demo if you could produce one. It might be worth looking into.

I'm using the mercury particle engine (from codeplex) as particle engine. It can do a LOT of particles and has some nice features. It used to have a farseer modifier in development, but I don't think it ever saw the light. I send an email to the developer some time ago asking for it, but never got it.

If you want, you could look into it and maybe create something similar?
Developer
Aug 14, 2008 at 1:31 AM
The key feature of my mod was to allow for realistic collisions between the particles and existing geometry. It's definitely not fast enough to do the huge number of particles you can with mercury. However I don't think mercury ever integrated with farseer's geometry shapes. My mod would work great for say casings from a machine gun or dirt particles flying up from a wheel. All see if I can find my code and post it up here. 
Developer
Aug 14, 2008 at 11:20 PM
I couldn't find my original implementation, but I have reproduced it for the most part. I add a flag to the Body object that determines whether it is a particle or not. If it is no angular calculations are done. I still need to add another flag maybe ParticleHasMass ? so I can let particles affect other objects or not. If you were making sparks for instance they should collide with objects other then themselves but should not cause any movement in any other objects. I am also considering making a Controller that automatically emits particles.

Without turning off particle mass I am still getting at least 500 particles with no drop in frame rate. I should double for triple this with mass-less particles.

Also creating several hundred particles within a few frames would cause a huge performance hit on the Xbox so you may have to keep a pool of reusable particles.

How would you like me to send my current work to you? I prefer email.   mattbettcher@gmail.com
Coordinator
Aug 17, 2008 at 4:40 PM
Thanks for the demo Matt.

It seems pretty nice and would properly be of use to many others.

I have some tips for you on the development of your game engine:

1) Abstact all the particle stuff away from Farseer engine instead of doing direcly implementation.
 - As an example, the only thing you have added to Geom.cs is a property. This is fine, but if you later add a lot more stuff, it could become confusing. Make the Geom class partial instead and add all your updates to another file that extends the class.
- You could properly also make the arbiter class methods overridable and create a ParticleArbiter class instead that contains your implementation. This would make the development of your code much easier.

2) Use the newest version of farseer. It has a lot of bug fixes and improvements.

3) Implement a lifetime on the particles so that you only have a number of particles live at one time. Have a look at Mercury Particle Engine, it has a very nice concept of lifetime and constant particle count.

4) As you write in your comments, you should properly seperate the implementation of debug view from farseer. In the newest version of farseer, there is a decupled debug view in the demoes. Makes life a lot easier.

5) Get your project under source control such as SVN or Team foundation. I can see that you are working on a mac with OS X, with souce control you can keep your project clean of .DS_Store files. Makes it easier to work with and gives a lot of flexibility.
Developer
Aug 18, 2008 at 12:52 AM
These are some really good ideas genbox. I do apologize for using an outdated version of Farseer engine I just used one I had on a spare hard drive. I also apologize for .DS_Store files. I use an iMac and often run OS X and Win XP concurrently. I do apologize as I whipped this up in just a few hours.

So just to be clear on your ideas. I should not use bodies as particles but create a whole new type? 

Possibly completely separate the particles from Farseer except for say the Geometry list to provide the particles with the data they need to collide with other objects. 

Is the particles ability to affect other objects something you would be interested in?

Also when I begin the real implementation I will definitely include lifetime and collision counts as well as individual gravity's and anything else anyone requests.

Also I have used Xcodes source control to download projects but never anything from Microsoft. What is a very user friendly technique to load your project onto a source control server?


As a final note I am attending college and am quite busy so if anyone would like to submit suggestions or code to help with integrating particle systems into Farseer please let me know in this discussion or at my email - mattbettcher@gmail.com
Coordinator
Aug 18, 2008 at 4:06 PM
"So just to be clear on your ideas. I should not use bodies as particles but create a whole new type?"

Not create a whole new type, but maybe create a type that inherited from the body class instead. It might not be possible, but going that direction instead of directly implementing particle stuff in Farseer would make your code easier to maintain in the future.

Just have a look at it when you refactor your code when you are done with it.

Oh by the way, I saw some code in the arbiter I wanted to change a bit. Instead of repeating the same code 3 times with little differences i changed it to run the code only once, and the changes depends on the state of the geoms instead.

[CODE START]
        internal void PreStepImpulse(float inverseDt)
        {
            Contact contact;
            if (!geometryA.CollisionResponseEnabled || !geometryB.CollisionResponseEnabled)
            {
                return;
            }

            for (int i = 0; i < contactList.Count; i++)
            {
                contact = contactList[i];
                //calculate contact offset from body position
                Vector2.Subtract(ref contact.Position, ref geometryA.body.position, out r1);
                Vector2.Subtract(ref contact.Position, ref geometryB.body.position, out r2);

                //project normal onto offset vectors
                Vector2.Dot(ref r1, ref contact.Normal, out rn1);
                Vector2.Dot(ref r2, ref contact.Normal, out rn2);

                //calculate mass normal
                float invMassSum = geometryA.body.inverseMass + geometryB.body.inverseMass;
                Vector2.Dot(ref r1, ref r1, out float1);
                Vector2.Dot(ref r2, ref r2, out float2);
                kNormal = invMassSum + geometryA.body.inverseMomentOfInertia * (float1 - rn1 * rn1) +
                          geometryB.body.inverseMomentOfInertia * (float2 - rn2 * rn2);
                contact.MassNormal = 1f / kNormal;

                //calculate mass tangent
                float1 = 1;
                Calculator.Cross(ref contact.Normal, ref float1, out tangent);
                Vector2.Dot(ref r1, ref tangent, out rt1);
                Vector2.Dot(ref r2, ref tangent, out rt2);
                kTangent = geometryA.Body.InverseMass + geometryB.Body.InverseMass;

                Vector2.Dot(ref r1, ref r1, out float1);
                Vector2.Dot(ref r2, ref r2, out float2);
                kTangent += geometryA.body.inverseMomentOfInertia * (float1 - rt1 * rt1) +
                            geometryB.Body.InverseMomentOfInertia * (float2 - rt2 * rt2);
                contact.MassTangent = 1f / kTangent;

                //calc velocity bias
                min = Math.Min(0, allowedPenetration + contact.Seperation);
                contact.NormalVelocityBias = -biasFactor * inverseDt * min;

                //Compute the restitution, we average the restitution of the two bodies
                //restitution = (2.0f + _geometryA.RestitutionCoefficient + _geometryB.RestitutionCoefficient) * 0.5f;
                restitution = (geometryA.restitutionCoefficient + geometryB.restitutionCoefficient) * .5f;

                //calc bounce velocity
                geometryA.body.GetVelocityAtWorldOffset(ref r1, out vec1);
                geometryB.body.GetVelocityAtWorldOffset(ref r2, out vec2);
                Vector2.Subtract(ref vec2, ref vec1, out dv);

                //calc velocity difference along contact normal
                Vector2.Dot(ref dv, ref contact.Normal, out vn);
                contact.BounceVelocity = vn * restitution;

                //apply accumulated impulse
                Vector2.Multiply(ref contact.Normal, contact.NormalImpulse, out vec1);
                Vector2.Multiply(ref tangent, contact.TangentImpulse, out vec2);
                Vector2.Add(ref vec1, ref vec2, out impulse);

                if (geometryA.body.affectsOthers && geometryB.body.affectsOthers)
                {
                    geometryB.body.ApplyImpulseAtWorldOffset(ref impulse, ref r2);

                    Vector2.Multiply(ref impulse, -1, out impulse);
                    geometryA.body.ApplyImpulseAtWorldOffset(ref impulse, ref r1);
                }
                else if (geometryA.body.affectsOthers && !geometryB.body.affectsOthers)
                {
                    geometryB.body.ApplyImpulseAtWorldOffset(ref impulse, ref r2);
                }
                else if (!geometryA.body.affectsOthers && geometryB.body.affectsOthers)
                {
                    Vector2.Multiply(ref impulse, -1, out impulse);
                    geometryA.body.ApplyImpulseAtWorldOffset(ref impulse, ref r1);
                }
                contact.NormalImpulseBias = 0;
                contactList[i] = contact;
            }
        }
[CODE END]

I have not testet it and I might have forgotten something.
Coordinator
Aug 18, 2008 at 4:20 PM
"Is the particles ability to affect other objects something you would be interested in?"

Your demo already have that functionality? The pendulum hits the objects and affect them.

"Also when I begin the real implementation I will definitely include lifetime and collision counts as well as individual gravity's and anything else anyone requests."

Nice. Keep us posted on your progress.

"Also I have used Xcodes source control to download projects but never anything from Microsoft. What is a very user friendly technique to load your project onto a source control server?"

I've only used Xcode twice. I really like the distributed build system, but I think that Xcode chews a bigger bite that it was designed for.
I personally like SVN on small projects with the client TortoiseSVN. TortoiseSVN only works on the Windows platform, but there is a plugin for Finder in Mac OS X called scplugin.

SCPlugin Homepage

I've made a small tutorial on SVN in this thread:

Performance improvements made

Good luck at college by the way.
Developer
Aug 18, 2008 at 9:55 PM
By affects objects I mean that the particles would have mass and could
cause an object to move. Say a fountain spraying water straight up and
a ball tries to bounce through the water the fountain would cause the
ball to up.

If you change AffectOthers to true in the demo I send then when you
move the ball over the stream of particles it will float and be pushed
away.
Coordinator
Aug 18, 2008 at 11:21 PM
Arh okay. That's a nice feature.

I suppose the particle stuff for farseer is for your own game? If you develop further on the particle system for farseer, please keep us posted on the updates. We love new and exciting stuff here on the forums. :)

To everyone who want's to see the particles in action:

Particles in farseer