Monthly Archives: August 2018

Progress Report: August 2018

During August, I mainly worked on ship-to-ship combat.

Here’s a short video demonstrating the currently implemented features, namely:

  • Wind direction (black arrow) affecting ship speed.
  • Detection if enemy ship is within cannon range.
  • Shooting of cannons.
  • Reload time for cannons.
  • Health model for ships with different graphics reflecting current condition the ship is in.
  • Various (placeholder) graphical effects:
    • Smoke from cannons being fired.
    • Cannonball trails.
    • Explosion when a cannonball hit a ship.
    • Water splashes when a cannonball crashes into the ocean.

Code Snippets #2: Not Quiet So Simple Pooling Manager

A while back, I posted my simple pooling manager. Unfortunately, it turned out to be too simple for me.
It didn’t cover a common use case I have: requesting objects but not using them immediately. At the core of the problem was the fact that the pools relied upon if the object was active or not to determine if it was in use or could be handed out by the pool. When handing out the object, the pool then set the object to active so it wouldn’t be handed out twice incidentally.

This however presented a problem in a common use case like this:

  • A ship fires its cannons.
  • Since the ship has 20 cannons, I need 20 cannonballs.
  • To add some more realism, not all cannons are fired exactly at once.
  • However, it is way more effective to get all 20 cannonballs in one call to the cannonball pool and not make 20 separate calls for one ball each.
  • Since the pool needs to set objects to “active” when handing them out, the cannonballs immediately became visible. That was ok for those that were initialized and fired directly. But those that weren’t fired in the same frame as the cannonballs were requested, just spawned in the place they were at when they were when they were put back into the pool/disable the last time. They just floated there, motionless, until the frame they were fired in came up, then they were teleported to the correct spot and started moving/were shot.
  • To prevent that problem, I had to write a lot of code that was triggered on initialization and also when the objects were disabled (turning colliders, sprite renderers, etc. on and off). It was a lot of work, prone to errors and something that needed to be done separately for every kind of pooled object that wasn’t immediately used.

That’s why I wrote a new pooling system that doesn’t rely upon if an object is active or not to determine if it can be handed out or is currently in use. That way, objects can be handed out inactive by the pool.
Since there are major changes, I decided against silently updating the old post and to write this new one. That way, people interested in using a simpler pooling manager or comparing the two, will be able to do so.

Here’s my new version of the pooling system:

Class to manage multiple pools:

Class representing a pool:

Class that is attached to pooled objects by the pool. This meta info helps the pooling manager to return objects to the correct pool:

Remarks

  • In my old pooling manager post, I mentioned that it was a lot more efficient to fetch n objects in one call than to fetch 1 object n times.
    While it’s still more effective to get all objects in one call, the differences in performance in this new pooling manager are a lot smaller
  • In some places the code looks a bit inelegant (using for instead of foreach, saving the amount of objects in a list to a variable instead of using Count(), etc.
    This design decisions are intentional. I did quite a bit of profiling and came to the conclusion that writing the code this way leads to much better performance when dealing with a lot of objects.