1
\$\begingroup\$

I'm working on my first Unity project, which (maybe naively) I decided to make a shmup.

I've been doing a lot of reading about Unity, and about object pools, and about using components to control behaviors of game objects.

Right now my idea for how a bullet works is that each bullet should be a game object, with a component that controls how it moves, and another component that controls what happens when it collides with something it can damage. Depending on the enemy or player shooting the bullet, however, the way it moves or how it deals with collisions may be entirely different, which means that a bullet from enemy A may need one component to control motion, but a bullet from enemy B may need a different type of component. (And the same for damage-dealing.)

If I want to pool bullets, since a shmup tends to need a lot of bullets all the time, I'm not sure how to handle "resetting" the bullets when I'm done with them and grab them out of the pool to use the next time.

So my question is, what is the ideal way to design a bullet system for a shmup in Unity, from the point of view of an expert in Unity instead of my beginner perspective? Am I going about using components wrong? Should I have a completely different pool for each possible type of bullet (which may not be feasible since I want a good amount of variety in the game)? Should I just have one monolithic motion control component that has a ton of code and can control every imaginable type of motion a bullet could ever need (I hope not)? Should I just forget about pooling and use Instantiate and Destroy? Is there a good way to reset what components are attached to a GameObject to the state of its prefab when I'm done with it?

I'm afraid my beginner-ness to this ecosystem makes it hard to even know what the right question is.

\$\endgroup\$
  • \$\begingroup\$ Are we talkiinng about 2d or 3D? If you're also talking about bullet hell considering a custom particle system might be a better option too ( you'd have to implement a way to process collider data ). Spawning lot's of game objects might not be performance friendly. \$\endgroup\$ – Sidar Mar 18 '18 at 2:20
  • \$\begingroup\$ 2D. I am worried about performance as I add more bullets, hence my desire to do it "right" from the outset. \$\endgroup\$ – StrixVaria Mar 18 '18 at 2:22
  • \$\begingroup\$ Right and are you going for a bullet hell or more like something along the lines of R-Type? \$\endgroup\$ – Sidar Mar 18 '18 at 3:06
  • \$\begingroup\$ Bullet hell. Not sure how crazy I want to get overall but at least hundreds of bullets at once. \$\endgroup\$ – StrixVaria Mar 18 '18 at 9:33
3
\$\begingroup\$

Your idea with various movement components and damage components isn't bad.

However, if you want to combine this with object pools, then removing and adding the appropriate movement components whenever you reuse a bullet makes object pools less useful. You still have expensive teardown and setup. I see two options to prevent this:

  • Use a separate object pool for each kind of bullet
  • Put all your movement-components on the bullet but only activate one at a time. Your bullets will now consume more memory, but we are talking about a few byte per bullet.
\$\endgroup\$
  • \$\begingroup\$ I think I'll reign in my vision for the game and go with the first option here and see if I really need to get any fancier than that. \$\endgroup\$ – StrixVaria Mar 18 '18 at 18:59
0
\$\begingroup\$

So if we were talking old school smhups I really wouldn't bother with trying to optimize much as you'd only have a few bullets on screen at a time. But with bullet hell it gets a bit more trickier as the engine would be dealing with a lot of objects that need to be enabled and disabled and unitys build in 2d physics.

A while ago I found a post on shmups.system11 that showed a neat implementation ( not unity tho ), unfortunately my google search can't find the thread but Ill update this answer once I do.

I don't know the exact implementation but the idea is to have your own custom particle system that updates each point ( in this case points represent bullets ). The elaborate part on this particle system is that you need a way to draw the visuals at each point and you need to handle collision yourself.

Unity offers an API to make custom draw calls and simple rectangle/circle collision isn't complex. I'm pretty sure you can also make use of the physics engine Unity provides but this is something you'd have to discover yourself ( I don't have the proper knowledge )

I can not say how much performance you win by this but I'm sure that if done correctly:

  • There is potentially less overhead ( instantiating game objects, registering events, firing events, etc vs adding a much simpler data object to represent a bullet).

  • Could be more cache friendly, making use of flat data ( a continuous array representing your particles ), meaning you can let the cpu do more in one cycle.

Now it should go without saying that depending on your needs and implementation your code affects performance as well. All this should be measured. If you work with just instantiating and pooling game objects and it runs well on your lowest target you could consider just going that route.

\$\endgroup\$
  • 1
    \$\begingroup\$ Only a few bullets on screen at a time? \$\endgroup\$ – Philipp Mar 18 '18 at 23:40
  • \$\begingroup\$ @Philipp Im talking about R-type styled shmups, not bullet hell. The concept of bullet hell came later in the shmup life. \$\endgroup\$ – Sidar Mar 19 '18 at 1:04
  • \$\begingroup\$ The question author said in a comment that they want to go for bullet hell. \$\endgroup\$ – Philipp Mar 19 '18 at 9:32
  • \$\begingroup\$ @Philipp That was a reply to me, I'm a well aware. The first line is about traditional shmups. What follows is about bullet hell. \$\endgroup\$ – Sidar Mar 19 '18 at 14:00
-2
\$\begingroup\$

I suspect you are wasting your time.

Unity is garbage collected. This means:

  • Allocation is fast.
  • Deallocation is, on average, fast.

The downside of garbage collection is that the collector must examine every object in memory, which means:

  • Potentially long pauses.
  • Speed is proportional to the amount of memory you are wasting.

However, a collection cycle that examines a few thousand objects is likely to be very quick, and you will probably never have more than a few thousand live objects in a bullet hell game. Long pauses occur when you have an application that stores millions of objects.

Similarly, the memory footprint of a few thousand bullets is likely to be rather trivial, probably less than 1MB.

I suggest quickly making an enemy that spams say 5000 bullets a second and seeing what effect this has on performance.

\$\endgroup\$
  • 2
    \$\begingroup\$ Unfortunately this is not true. Garbage Collection has overhead, and Unity's choice about when to perform GC isn't the smartest and will cause occasional frame hiccups where the delta-time will go from 15ms (60 FPS) to 120 (8 FPS) for one frame and cause a noticable stutter. \$\endgroup\$ – Draco18s Mar 18 '18 at 18:26
  • 2
    \$\begingroup\$ I just ran a test where I spawned 200 bullets/second (not even close to your 5000) figure and it wasn't pretty. I'm going to need to optimize. \$\endgroup\$ – StrixVaria Mar 18 '18 at 18:58
  • \$\begingroup\$ Oh dear. That is sad. Maybe use Go instead?? \$\endgroup\$ – James Hollis Mar 18 '18 at 19:10
  • \$\begingroup\$ You can avoid the garbage collection problem in Unity when you avoid creating too much garbage. Object pooling is a good way to achieve that. \$\endgroup\$ – Philipp Mar 18 '18 at 23:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.