Creating a game with a large number of dynamic bodies

Topics: User Forum
Mar 5, 2012 at 1:09 AM
Edited Mar 5, 2012 at 7:06 AM

I am looking to create a "bullet hell" style side scrolling shooter using farseer as a possible physics engine. I have created a few test programs and everything works fine except I get performance issues when creating a large number of bodies for projectiles. I have tried setting IgnoreCCD and IsSensor to true along with setting the collision group for all projectiles to -1, so that projectiles don't detect collisions between each other. After all of this I still am having problems. I need to be able to generate around 2000 projectiles and as it stands can only get around 350 to work well. Any suggestions?

Mar 5, 2012 at 2:30 PM

Are you deleting the bullets after you don't need them (i.e. After they leave the viewable area of the screen or when they hit an object)?

Developer
Mar 5, 2012 at 3:17 PM
Edited Mar 5, 2012 at 3:18 PM

2000 active bodies on the screen is quite a lot for Farseer to handle and seems a bit overkill to me. Im not sure how much faster world::TestPoint(Vector2 position) is, but would try that instead of having 2000 moving sensors. Just add a skin the size of your bullets around your fixtures (like player sprite and so on) and test the bullets' positions against the world.

That should save you at least some performance overhead... I have no idea if it is enough, though ;)

Mar 5, 2012 at 3:44 PM
Edited Mar 5, 2012 at 3:46 PM

I too have issues with more than 300 "slow" bodies (with joints) but the bullets problem is simpler and probably solvable :) Might I suggest to also look at a simple particle system with raycasts. It's similar to what elsch suggested only TestPoint might lead to tunnelling and misses since the projectiles are fast. Also raycasts are quite inexpensive - probably if you limit them a bit in length you could handle a few thousand per frame or with some other tricks even more. 

http://www.youtube.com/watch?v=C-ScURIRTGA (10k raycasts per frame, box2d)

http://www.youtube.com/watch?v=Ap_sCU-NG2w&feature=related (17k particles)

http://box2d.org/forum/viewtopic.php?f=4&t=77

For special bullets like ones that would add some force to the rigid body with which they collide you could turn the particle into a normal body just at the right moment and let the engine take it from there.

Mar 5, 2012 at 8:03 PM
Edited Mar 5, 2012 at 8:23 PM

Yes jcicero09, I give them a lifetime that deletes them when expired. Like jerrysb hinted at, I can't use raycast because my projectiles are slow and move in different irregular patterns. I'm leaning heavily towards scrapping farseer for my projectiles and using a simple if(Rectangle.Intersects( rect ){} method that I know can give me upwards of 4000 projectiles on the screen. I'm thinking that's kind of what elsch was talking about. I was hoping there was some setting I could change in my projectile's body that would strip farseer down to pretty much this, but apparently not. If anyone has any more ideas I'll clarify a few of my requirements for projectiles.

  • 2000+ projectiles must exist on screen at any one time.
  • Projectiles must be able to move at varying velocities.
  • Projectiles must support different patterns of movement (ie not a straight line)
  • Projectiles must only fire an event on collision, no physics needed

Thanks for your help guys.

Mar 5, 2012 at 10:35 PM
Edited Mar 5, 2012 at 10:35 PM

If it would help: for a sufficiently small time step AND low velocity motion is linear (bodies can also rotate but that's not relevant here). Since we are dealing with a physics engine that uses discrete time steps we're in that situation for common scenarios. Curving motion over time is approximated with small linear movements and rotation over multiple time steps. So if you implement your bullets with some form of integration (i'd reccomend Verlet) your code might looks like this:

In update method:

foreach bullet{

ApplyForces()

find new position with Verlet (or with Euler but you'll have to keep track of velocity too): 

cast Farseer ray between old position and new position - if there is a fixture hit add to list

}

foreach (hit): boom - delete particle and explode body

finally call World.Step()

If you would decide to extend your requirements one day with fancy physics projectiles (e.g. a water jet, blast bomb, elastic balls or whatever worms-style weapon) instead of deleting them you could add them to the world with their properties, ApplyForce() to them before calling World.Step() and get the physics engine to do the work for you.

The main point is that if you implement your own system you could always stay one step ahead of the physics (make sure you use fixed time step) and this makes it possible to have priority in your logic since you're lucky to need only one way collision.