I’m creating a bullet hell/shoot 'em up and I want at least a thousand bullets on screen, which can cause performance issues, especially on lower-end hardware.
My main questions are:
What is the most performant way to handle collisions when you have so many GameObjects on screen?
Does having a Collider2D and Rigidbody2D on every bullet inherently cause a performance loss, even with something like object pooling?
For context:
Right now, I’m using a Collider2D that is attached to the player and every enemy to check for collisions every frame with Collider2D.OverlapCollider. My main problem with this is that every bullet needs a Collider2D and Rigidbody2D attached to it. The Collider2D is necessary for obvious reasons. As for the Rigidbody2D, I think it’s necessary because from what I’ve heard, if you move the bullet with transform.Translate, it causes the 2D physics engine to do some extra calculations for the collider. Maybe this was a bug that was fixed recently?
I’m thinking of maybe sticking maybe a dozen or less raycasts on every bullet, from the original point to the point where it moves, and see if those intersect with another object. To be honest, this doesn’t sound that much better, but it would mean I wouldn’t need the Collider2D or Rigidbody2D on the bullets.
If you want to have large numbers of projectiles on screen the best way is to simply not use GameObjects. Unity’s particle systems support collisions and can be modified after they’ve been emitted to change their behavior.
Why not use physics queries? This is the kind of thing they were created for i.e. detecting contacts with stuff in various ways that don’t require a physics component to do so. Raycast, circle cast etc.
I was initially avoiding the particle system because I wanted full control over each individual bullet, however, it seems that the ParticleSystem has ways to iterate over each particle, which might be interesting, although maybe slow?
I get sold on DOTS quite often, and I do think it’s pretty neat. I just wish it had the widespread use of “classic” Unity. Plus, I’m always iffy on using tools that are in beta. I’ll try it anyways just because I think it’s cool.
Do you mean something like Physics2D.CircleCastAll? Wouldn’t that require either the bullets having a BoxCollider or the bullets themselves making the collision checks against the player/enemies?
No, those cast methods work on their own, only interacting with other colliders that exist in the world. You can cast from anywhere. It’s as if you place a virtual collider (just for this frame) at the position you provide in the call, and check what it would collide with. Same principle as with Raycast, except with said shape instead of an infinite line.
Nevertheless, looking into particles or DOTS is a good idea for your usecase, since thousands BoxCollider casts every physics frame still sound rather on the heavy side and so many SpriteRenderers are a burden too.
You can also use particles together with this: https://docs.unity3d.com/Manual/particle-system-job-system-integration.html
That way you can quite nicely iterate through many thousands of particles. I would recommend this over calling GetParticles and SetParticles manually in Update(), because that would be slower. You can unfortunately not affect singular particles without using the SetParticles method to set all.
What physics behavior do you want to give the bullets?
Particles can bounce and be affected by gravity without any additional scripts.
I think I understand, but wouldn’t this mean every enemy bullet would CircleCast against the Player, for instance? Assuming there is no BoxCollider on the bullets.
Actually nothing besides collisions. I’m moving the bullets through Rigidbody2D.MovePosition right now, so it’s a little annoying to have so much of a performance hit just for collisions against a few objects. Hopefully this would make working with ParticleSystems even easier.
Yes, exactly, but in the end that will have to happen in some shape or form, whether you let colliders do it, cast manually, or have the particle system handle it. I mentioned those in order of speed, I think.
Do they move in a special way? because particles also have velocity, orientation and rotational speed which are all applied automatically every physics frame.
The main thing they do not have compared to rigid bodies is mass (which allows for inertia) and in collisions they are represented as circles\spheres.
Here isn’t the place to write a tutorial (there are lots online) and there isn’t a specific query I’m telling you to use. Use CircleCast or Raycast, it’s kind of irrelevant. Often things like bullets/projectiles use a query to see what they’re going to hit in a future step by casting a shape/line in-front of them and then responding to that.
A query like raycast detects colliders, it doesn’t require a collider to work itself. Cast a ray from the bullet position to where you’re moving it to, filter by enemies or whatever. Use those results.