Jump to content
  • Advertisement
Sign in to follow this  
Diaspora

A good way to handle managing bullets/projectiles

This topic is 799 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am working on a game in C++ where the various characters can fire various projectiles. After firing one, they need to take a moment to reload. Because of this restriction, any given character will never realistically have more than a few projectiles firing at once, before one goes out of range(a variable set by the firing character) or hits another object, in both cases being removed from play.

The "removed from play" is the part I'm concerned about.

My idea was to set an active boolean for each bullet, have them all in a vector, and when a character goes to fire, simply grab the first one that is set to "active == false". Inactive bullets wouldn't be drawn or updated. Since I don't at this time actually know how many bullets there would at most be, I worry that having a bunch of "inactive" bullets lying around could cause problems.

Should I be creating a new bullet when a character fires and deleting it when it hits something/goes out of range?

 

 

Share this post


Link to post
Share on other sites
Advertisement

Depends on the complexity of your game. For something basic it really won't be much of an issue to have an array/vector of 10 bullets and only draw/update active ones as you describe.  If you do need more you can always resize that vector. It's probably better than creating and deleting bullets each time. 

Share this post


Link to post
Share on other sites

Since I don't at this time actually know how many bullets there would at most be, I worry that having a bunch of "inactive" bullets lying around could cause problems.
If this is actually going to kill your CPU time, congratulations :)

 

Like Nanoha already said, it's highly unlikely to cause trouble, walking over a vector doing nothing but checking a boolean takes close to no time, unless you have several zillion bullets in there.

 

What you could do is check the last bullet in the vector on each loop, and reduce the vector by 1 if it's not used (just reduce the length, but not the capacity of the vector). Alternatively, you could track first and last active entry. While both options would work, I would not be surprised if adding this code is actually slower than just walking over everything and don't bother about it.

Share this post


Link to post
Share on other sites

What your describing is called pooling, it's a pretty common technique for games.  Generally, if you foresee a lot of bullets being fired over time, it's not a bad idea.  Having inactive objects shouldn't be too expensive, if you handle it right.  I'd probably go with an array or vector of bullets, and queue/stack of bullet indices (that index into that other array/vector), that's your inactive bullet queue.  When you disable a bullet, you put it back in that queue.  It's more memory to have that second container, but not all that much, and then you don't have to iterate over your bullet list ever.

Edited by ferrous

Share this post


Link to post
Share on other sites

Just use a vector of structs and work on the vector. You can do this through a function, or else encapsulate the vector in a class that manages it and does the work on it. When you iterate the vector to update the bullets and you find an object that's flagged as dead then swap and pop and continue processing from that point. If a new bullet is fired, just emplace it to the vector. Vector retains its memory and you'll avoid the costs that you'd otherwise get from constant allocations and releases. The only thing you need to make sure of is that you never increase the vector during iteration. In fact, if you like, you can set up your system to log the maximum size that the vector reaches during play and when you're satisfied that you've found a good upper-bound you can use vector.reserve() to allocate all the memory up-front (increase it by 50% just for kicks).

 

You're going to have a hard time finding a better pattern than this, and we're talking about something that almost certainly is not a performance issue in the first place.

Share this post


Link to post
Share on other sites

 You can do this through a function, or else encapsulate the vector in a class that manages it and does the work on it. 

 

I definitely second this.  This will let you completely change the underlying implementation and the classes that use the pool don't have to know about it.  (And they really shouldn't)

 

All the class really needs is two public functions like T* GetPooledObject() and ReturnPooledObject(T* pObject)  (You don't have to make this a templated thing, but you might find you want to use several different pools, depending on your game)

Share this post


Link to post
Share on other sites
Assuming the order the bullets are updated doesnt matter, you can use swap&pop to reduce the array/vector size to only contain active bullets. Swap the bullet you want to disable with the last bullet in the array, then reduce the array size. No need for an active flag or iterating over a vector with mostly disabled bullets

Share this post


Link to post
Share on other sites

All the class really needs is two public functions like T* GetPooledObject() and ReturnPooledObject(T* pObject)  (You don't have to make this a templated thing, but you might find you want to use several different pools, depending on your game)


Why should any individual bullet ever be singled out and removed from its context? Bullets don't really get up to much in terms of decision-making or individual behaviors. Anything that you're doing to one bullet probably needs to be done to all bullets, so the encapsulating class can manage it. There's no reason to "check out" and "check in" individual bullets. All that does is defeat contiguity and remove the ability of the class to maintain its invariants.

Share this post


Link to post
Share on other sites

I have used object pools combined with linked lists for this kind of thing in the past. Provided you don't need random access to a projectile it should work just fine.

Pool allocates and stores references to the objects, it can create a bunch upfront based on and educated guess and expanded if needed at runtime, uses a vector behind the scenes and a pointer to the last unused item.

Then you just run though your linked list in the update function advancing and collision testing. It is then extremely fast to add/remove projectiles from the linked list and return/retrieve them from the pool. Most of the time there will be 0 allocations and 0 vector resizing/copying. It is not as cache friendly as blasting though a flat vector but plenty fast enough and the ease of implementation is a real plus.

There are no doubt other ways, this is just something I have used successfully many times and is both easy on the GPU and minimises memory allocation/GC.

b

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!