Best way of handling enemy projectiles

Started by
8 comments, last by Strewya 9 years, 4 months ago

I'm working on a fantasy themed Flappy Bird clone, and I'm looking for advice on something. I have a skeleton enemy that throws bones at the player (though my question applies to any enemy that attacks with projectiles). The Skeleton class has a list of Bone objects, and it calls each Bone's update and draw methods within it's own respective methods. The problem is, when the skeleton dies after throwing a bone, the bone "dies" as well.

I ran into a similar problem with the bone's collider, as the main game loop was checking each object belonging to it's class - the hero and all monsters. Because the bones belong to the skeletons, I had to expose a list of the bones colliders through a getter so the main update loop could iterate over those as well. Should I try something similar for the bone objects themselves? If I grab the list of bones from each skeleton in the main loop, I can update and draw them independently of the skeleton - and I'll also have direct access to their colliders.

Typing out this question actually helped me come up with some ideas (don't you love when that happens?), but I'll pose my main question anyway. Should an enemy's projectiles (or any other game object that logically belongs to the enemy, or any other object for that matter) be members of the enemy class itself, or should they exist at the game loop level, next to the enemies? The latter seems like really poor design, and I'm not sure how I would handle the skeleton telling the main class that it should create a new bone. I prefer the former approach, but any input would be appreciated.

It shouldn't matter for this question, but I'm using libGDX.

Advertisement

I would handle it by having a list of projectile instances at the main game loop layer, and pass that list to a skeleton when it updates. If the skeleton decides to throw a bone, it will create a projectile instance, initialize it with the required data, such as the projectile velocity, direction, gravity scale, sprite image index, starting position, etc. (note: i would make the projectile a simple data struct, which has an updateType variable, which is used to determine if the projectile needs to arc, or move like a sine wave, etc. You could do it by making a lot of derived projectile types for the different types of projectiles, if you so prefer).

Then the main loop simply iterates over each projectile, updates it, checks collisions, does the proper response if collision is detected, and draws it later.

There is a question if the projectile needs to know who threw it (like if you need to grant experience to the thrower when the projectile kills something or play an animation on a successfull hit). In such a case, give it an entityID by which you can look up it's thrower, and do the proper behaviour.

devstropo.blogspot.com - Random stuff about my gamedev hobby

That sounds like a great approach, thanks for the ideas! One question though - all of my enemies subclass Monster, so I can iterate over all types at once. To pass the projectile list in, I'd need to add it to Monster's update method, but not all monsters throw projectiles. Would you suggest simply ignoring the list if I don't need it (easy enough), or separating my Monster list into individual subclass lists, so each monster type can have it's own update signature?

For my (small) games, I usually have an update(World) function. The game object can choose to interact with the world, e.g. query for interesting objects around them or adding new objects to the world, or it can just ignore this parameter if it is "dumb", like the projectiles you mentioned.

Hi.

You could try this.
When your object dies leave it in play but don't render it. This way it can still update it's projectiles then in it's process function you can check to see if it's dead and all projectile have reached there target if so then remove the object.
For something like projectiles that are frequently created and destroyed while you play the game it is usually better to pre-allocate a cache of projectile objects and re-use them. If you need to fire a projectile, ask the cache for one, set up its data, and let it do its thing. When the projectile dies, give it back to the cache instead of deleting it.

This helps avoid memory fragmentation and frequent allocation/deallocation which is bad even in languages like C++ and worse in languages with garbage collectors (like Java or C#) due to the massive amount of garbage that would be generated.

Caching the projectiles is a good idea and even if you have a reasonably high number pre-allocated to the cache (like 1,000 to 10,000) it would be better on the memory performance than to frequently de-allocate every frame.

Add projectiles starting from the beginning of the array and keep a variable to track the number of active projectiles. Then the game would know how far into the array it would need to iterate for each frame. When you need to "delete" a projectile, swap the projectile to be deleted with the last active projectile on the array, and reduce the number of active projectiles by one.

New game in progress: Project SeedWorld

My development blog: Electronic Meteor

Good call on the caching. I'll definitely do that.

For adding projectiles to the list, I ended up going with a modified version of Strewya's idea. Instead of passing the list in to the update method, I just pass it in to the Skeleton's constructor. Now the skeletons can just add the bone to their own list, and it's the same object in memory that the main loop uses so it works out.

Sounds to me like the bones belong to your skeleton class. If it's a flappy bird clone, the arrows should be constructed in a list belonging to the scene, not the individual skeletons.

Good call on the caching. I'll definitely do that.

For adding projectiles to the list, I ended up going with a modified version of Strewya's idea. Instead of passing the list in to the update method, I just pass it in to the Skeleton's constructor. Now the skeletons can just add the bone to their own list, and it's the same object in memory that the main loop uses so it works out.

That's another way to do it, yes.

Keep in mind that this prevents you from adding bones to a different list of projectiles (without destroying+recreating the skeleton or having a setter for the list), should you ever decide you need another list. Might not happen ever, but just something to be aware of. :)

devstropo.blogspot.com - Random stuff about my gamedev hobby

This topic is closed to new replies.

Advertisement