OOP design question

Started by
3 comments, last by cozzie 8 years, 9 months ago

I want to create many ammo types and obviously a gun uses a particular ammo type so I need an easy way to look it up for ammo consumption. I am creating a inheritance system for a factory that takes data from files and convert them to objects so if I end up going to add crazy amount of types everything stays in good order. Now I am wondering how far I should take this in the OOP sense.

Say I have many different types of bullets should I create a Bullet class that holds these bullets and compare by a int or string identifier if the weapon can fire that bullet? Creating a class for every bullet type seems over kill but does compare it easily.

Bullets will mostly have the same behavior so I should probably stop at the Bullet class. Rockets however behave a bit differently from each other. Some will be guided, they have different damage types and some other behaviors. Still these could be implemented within the same class.

The point is what would be a good way to look these up? I can create a weapon that uses ammo of the type [bullet] with a string "5.56mm". So I should firstly look in my inventory if I have ammo of the type bullet and then check if that ammo has the string with "5.56mm". This is kind of error prone though. What about using "static final int"?

In the weapon factory I would get a ammo type from a file and assign the value to "int ammoType" to the corresponding global. In the ammo factory I can do the same. Then I would compare the ammo [class] first and second these global types. I still have the readability in my data files and besides much quicker look ups they are error prone (as long as the data files are consistent).

I'd like to here some thoughts about this, I'm having a hard time wrapping my head around the wole subject but I think I am getting there.

Advertisement

As a game developer who has faced this decision in the past I would recommend making generic classes, like Bullet, that encapsulate all of the generic functionality and data of all the game's bullets, and then extending the classes for any custom bullets that need it. The alternative is to have one class that contains large branching structures, something that will become a nightmare to maintain as the game continues to grow. Additionally, the multi-class structure allows you to easily determine which ammo is usable with what weapons. For example, a "BFG" type gun might support explosive shells and regular bullets so in the gun class' header you would define an "allowableBullets" array that has a reference to all of the allowable bullets:

var allowableBullets = [ExplosiveShell, RegularShell];

Here the two array items are references to the actual classes that you can use for comparison when "loading" the gun later:

function loadBullets (bulletType) {

for (counter=0; counter<allowableBullets.length; counter++) {

if (bulletType == allowableBullets[counter]) {

putBulletsInGun();

}

}

bulletsNotAllowed();

}

This should also work with class instances but you'll need to see exactly how that's handled in your language of choice.

Finally, most programming languages have functions that will allow you to dynamically find classes at runtime (usually using a standard string), so this should be extensible to allow you to match guns and ammo via external data like XML.

If you take some time to ensure that your top-level classes encapsulate as much generic functionality and data as possible it should be easy to create numerous extending classes that change the data or functions only slightly. Should you choose to go with the single-class approach you'd still need to write all of this various functionality, etc., but will also have to contend with managing it in the ever-growing file - unless this is a one-off, quick-and-dirty project I would highly recommend going full OOP; you'll be glad you did later!

Hi there!

So I don't dislike the inheritance scheme or necessarily have anything against that design. For me, and what I've seen in the past is to treat a projectile just like a chunk of data and have a separate modules handle the simulation of projectiles. I guess something like below is how i'd do it:


struct Projectile
{
  unsigned int id;
  unsigned int type; // <- maybe?

  float speed;
  float size;
  // ... Plenty of other things ... //

  bool flags;
};


In some sort of simulation module or class.


for (auto proj : projectiles)
{
  if (proj.flags & LINEAR)
    applyLinearSimulation(proj);


  // Do specific simulation things here


  if (proj.flags & PROJ_HOMING)
    applyHomingSimulation(proj);


  // etc ...


  // etc ...
}

You can achieve the same exact thing by giving the projectile knowledge on how to simulate itself via an update function and have it inherit from some sort of base class. I guess what's nice about above is you can easily mix and match different behaviors and to create a new projectile often doesn't take any new code but rather different data.

As an example. Say you had a rocket projectile class that had its inheritance scheme and also had an acid spray projectile, or something. Now you want to create a new rocket acid spray projectile shot. Well it's possible in the inheritance scheme but you'd probably make a new sub class for it. If you treat the projectile like data you could just create a projectile and set the flags for both rocket and acid spray. Obviously, in practice, it may not always be so simple but that's the idea.

As for selecting items. I'd just give projectiles an ID or type and check on that for knowing what you have selected.

I'm sure there's lot of right designs for this problem. This is how I'd approach it though.

This is almost a perfect example of where you want composition.

In a perfectly OOP sense, you'd make your generic GameObject just be a collection of Component classes. You can then make Component derivates like ExplodeOnContactComponent, DamageComponent, BulletPhysicsComponent, GuidedMissileComponent, etc., and then mix and match those components however you like to make the specific projectile you're wanting.


You can then make those specific component combinations and their data read from a file, allowing a designer (possibly via a custom tool you provide) to make up new types of projectiles without ever having to modify any code (assuming they don't need any new features).

Then specific types of projectiles that a gun fires can be stored as game object templates/blueprints. e.g. the DumbRocket.template file might have BulletPhysics, ExplodeOnContact, etc. The gun itself could have a GunWeaponComponent that contains a list of ammo templates and ammo counts for each template. Either GunWeaponComponent or the PlayerInputComponent or whatever can switch active ammo types on the appropriate key press, handle picking up ammo, and handle firing the gun when the fire key is pressed. You might choose to split up GunWeaponComponent into smaller components if you feel it's doing too many different things (so you might have an AmmoListComponent to note which types of ammunication a gun can use, a GunWeaponComponent that handles firing an active ammo type, and an InventoryComponent on the player that notes which guns and ammo amounts the player has and which ones are actively selected).

Sean Middleditch – Game Systems Engineer – Join my team!

I would go for a base/ parent class for both weapon and ammunition, since lots of properties among different weapons and ammo types are shared.

Then you can derive classes for the different types of weapons and ammo (and link them with a member property or some defined ID, like you said int ammoType, maybe add some #define's for the different types). That way you can reuse most of the shared properties without duplicating code/ functionality.

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

This topic is closed to new replies.

Advertisement