Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
Tags

20k bullets in Unity! Optimised bullet spawning system, free for you guys to use Sticky

A topic by WayfarerGames created Apr 09, 2021 Views: 2,026 Replies: 17
Viewing posts 1 to 5
Submitted (3 edits) (+15)

I'm making my bullet spawning system available for anyone in the jam to use! https://wayfarergames.itch.io/bulletfury 

Let me know if there are issues, this is an early version of the package so there may be some minor bugs.  However, it has gone through some quite rigorous testing, so it should be stable enough for you to use in the jam!

I managed 20k bullets at 60fps on a macbook - should be FAR more than you need 馃槈

Submitted

Do you use Jobs system? Object pooling? both?
just asking out of pure interest <.<

I hope this will help people especially beginners, i for myself will write an own system just to learn ^^

Submitted(+1)

It does use the jobs system - it should be commented so you can see what's going on!

There are actually no gameobjects at all, so pooling isn't needed. The bullets are all rendered with one draw call per bullet manager, it's about as optimised as I can make it at the minute. It should be ok with around 20,000 bullets on-screen and stay above 60fps 馃榿 obviously you'll never need that many, but it means you've got a lot of performance budget for other things like  post-processing.

You're welcome to have a look and see how it works - that's half the reason I've put it up here and made sure it's so well commented 馃槀

Submitted(+1)

one last question; does this also work for 3d or is this just intended for 2d usage?

does it use Graphics.DrawMeshInstancedIndirect? anyway i will first try for myself and then look into it to learn from it. looks very good ^^
very kind to share the work to other people.

Submitted(+1)

it is actually intended for top-down 3D because that's the game I'm currently working on 馃槀 it should work with any meshes. The demo uses quads, but there's no reason you can't use a sphere or something else!


It uses DrawMeshInstanced, not InstancedIndirect. Couldn't get indirect to work before the jam, not going to have time unfortunately! That just means there's a cap of 1023 bullets per manager. I don't think you should need that!

(1 edit)

Does this build for WebGL/run in browsers?

Submitted

It seems to work on WebGL, yeah! However, as with all things WebGL, there may be issues that I haven't seen. The core tech seems to work, at least! I haven't tried collisions yet, but I don't think they're doing any that differently 馃槀

I see! That's really awesome - I've been working myself on making ECS/DOTS (with Jobs and Burst) work in WebGL, which was an ordeal especially because the Hybrid Renderer does not yet support WebGL so I'm using Companion GameObjects for now (with all logic applied to entities and just the transform of the GameObject synced every frame).

There were a few other gotchas if you're interested, but at this point your approach seems way more feasible (also for not using preview packages~) Good work, thank you for sharing~!

Submitted

it does use jobs, which is a preview package! But seems to be stable enough at this point 鈽猴笍 

Sounds like we're doing mostly the same thing, essentially just rendering differently 馃槀 most of it should be commented pretty extensively (except the editor tooling) so you should be able to work out what I've done.

Submitted

I prefer to code my own system, but can you give some insight into how yours works? I crashed my computer by spawning 1000 objects (but my computer is a bowl of egg salad anyway) 

Submitted(+3)

You're welcome to download it and check it out - it's all commented. Easier to answer specific questions when you've actually seen it 馃槀

As for some tips on making your own system more performant:

  • Are you object pooling? If not, learn how to do that.
  • Do your bullets have rigidbodies? Remove them 馃槈 rigidbodies are REALLY slow, and you can get away with just having rigidbodies on the colliders on your players/enemies.
  • If that's still too slow, you can actually get rid of the rigidbodies on the players/enemies and use Physics2D.OverlapCircle in FixedUpdate - I'd actually recommend the non-allocating version because you want to minimise your garbage collection.
  • Check your bullet spawning code for any unnecessary allocations - that's anywhere you've got "new". You can, for example, make a list a member variable and use list.Clear to clear it.
  • Check the profiler!! This is a big step, it'll show you where the majority of your performance issues are. You might, for example, be using Linq in your object pooling code to check if there are any available bullets. I was doing that, removing that linq code sped it up about 3x 馃槄

If that's still not enough, there are some major changes you can make to do it like I do:

  • You can rewrite it so all of the movement code is done from one object, and it just updates the positions of the gameobjects rather than the bullet gameobjects themselves having unnecessary monobehaviours attached
  • Once you've done that, it's fairly straightforward to use Jobs and multithreading to move the bullets
  • Once you've done that, you can try getting rid of Unity's physics entirely, and coding your own circle/circle collision detection as a Job
  • Finally, you can remove gameobjects entirely and use command buffers and a custom render pass. This is how I get to 20k bullets at 60fps 馃槈

If 20k bullets at 60fps isn't enough, you can go full ECS. You probably don't have to do any of the last section, though, the first lot should be plenty to get 1000 on any hardware :)

Aren't you amazing I am an artist I try to code a lot but I just can't understand its logic properly. Can you give some tips on how I can improve as a dev. I did appreciate that man.

Submitted

just practice! Practice, practice, practice 馃槈 game jams are a good way of doing that.

Try things. Don't be afraid to just get stuck in: if something works, figure out why it worked. If something doesn't work, figure out why it didn't. 

All this comes over time. You'll get there!

Submitted(+1)

You might, for example, be using Linq in your object pooling code to check if there are any available bullets. I was doing that, removing that linq code sped it up about 3x

It is SUCH a shame that LINQ is so slow >_<

Especially if you then compare the performance of LINQ with what Rust offers and you see that in Rust using map/reduce is almost always as fast as a normal foreach loop and often faster than using a normal for loop to loop over your structure. And then there are even moments where it wins from both unless you try VERY hard. 

Submitted (1 edit) (+1)

Hi it looks great thanks a lot! But in web build, it seems the post-processing light around bullets is not rendered. Is that expected or I missed some steps? It works fine in the studio. and the bloom effect works on other items too in web build, just not on bullet.

Submitted(+1)

WebGL can cause weird issues like this 馃槱 in one of the two render feature files, there should be something like "BeforeRenderingPostProcessing" - maybe try changing that to one of the other values? I can have a look properly after the jam, but probably won't have time before then 馃槄

Submitted

Thanks for replying! I tried AfterRendering, BeforeRenderingPostProcessing, and AfterRenderingPostProcessing but neither works... Any other suggestions I can try? Thank you very much!!

Submitted (1 edit)

Hello!

I was able to solve the bullet post-processing in WebGL by going to Project Settings > Quality. Then I just removed all settings except for High Quality so it was forced to use that. The problem was that for WebGL it was set to medium quality which made it not render the bullets (from playing around with it)


As an example, here is my WebGL build with the effect fully working. The framerate is also pretty decent Thank you so much for creating this package, it's amazing and looks incredible =)