2
\$\begingroup\$

I have a simple shooter game with a GameLevel class and a Shooter class. The shooter has a set amount of ammo, and every time the shoot() function is called, the ammo variable in the shooter decreases.

My question is about when the shooter runs out of ammo. Should the shoot() function be keeping track of ammo and simply stop shooting when ammo is 0, or should the GameLevel class call some sort of canShoot() function and have complete control over whether the weapon shoots or not?

This also applies to for example movement limitations i.e. if (in a simple 2D game) the shooter hits a wall, should the shooter itself prevent any movement or should the GameLevel class check for this first?

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Think about it from the real world perspective (this is how we typically do OOP design):

What decides the ammo limit on a gun, the gun's design or the whole world's design? If it is specific to the gun, keep it in the gun class. Make things as specific as possible.

From an external perspective, pulling the trigger doesn't necessarily shoot a gun, it only tries to shoot, because whether a round is chambered or not is entirely internal to the gun, and unknown to the outside world (hence people sometimes die by accident, e.g. Brandon Lee in The Crow).

So from the world, or the player, or what have you, you would call gun.tryShoot(). Internally to the Gun class, this would be something like:

class Gun
{

    tryShoot()
    {
        if (this.hasAmmo()) this.shoot();
        else this.goClick(); 
    }

    shoot()   
    {
        this.sendProjectileFrom(parent.transform); //pass position / direction the gun has according to the holder;
        this.ammo--;
        //play a bang sound
    }

    hasAmmo()
    {
        return this.ammo > 0;
    }

    goClick() { /*play a click sound*/ }
}

Collision detection, however, is usually handled by a separate subsystem that considers collisions between all (or subsets of) physical objects, collectively, often treating all of these in some generic fashion and notifying when a collision between pairs of these has occurred (each according to their own fashion, for example a barrel may explode while a player may lose life points).

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Great answer, thanks. I'm new to this stuff! \$\endgroup\$
    – Gary Allen
    Commented May 22, 2021 at 20:30
  • 1
    \$\begingroup\$ I find the Single Responsibility Principle is a helpful razor for this kind of thing too. Asking myself "Is ammo management the main responsibility of the game level class?" gets a pretty emphatic "no!". The game level class should only change when I change the level itself. \$\endgroup\$
    – DMGregory
    Commented May 22, 2021 at 20:36
  • 1
    \$\begingroup\$ I like this answer in general; ammo for a gun should very likely be internal to the gun (with a getter for UI update purposes), but should the gun class be responsible for playing sounds? Also, if two guns share the same ammo type (e.g. chaingun and pistol in DOOM), it seems likely there'd be an ammo object for that type of ammo passed into constructors for both guns, which introduces potential design complexity. Following that train of thought, ammo could be just another inventory item or attribute on a player (but then if guns can be dropped with some ammo inside of them... it gets dicey). \$\endgroup\$
    – ggorlen
    Commented May 25, 2021 at 21:50
  • 1
    \$\begingroup\$ @ggorlen Good questions; I'd agree that for any larger game, there should generally be a sound "service" which listens on program events or callbacks in order to play the necessary sounds. This reduces coupling and clutter through what should be pure simulation code (incidentally I also strongly support a clean separation of model/controller vs view code). Naturally, an individual instance of class AmmoClip (or concrete subclass thereof) would be held within the Gun instance, recording its own state (ammo count). This is hierarchical delegation of responsibility as we move down the model tree. \$\endgroup\$
    – Engineer
    Commented May 26, 2021 at 1:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .