Need advice on how to implement weapons of different kind (inheritance or not?)

Hello!
I’m trying to implement various kinds of weapons in my game. These weapons can be different and have different features (ranged/melee, shotgun spread/single bullet, … ).
My original idea was to implement weapons’ classes using inheritance beause some guns share features, and depending on the name of the gun, the corrisponding stats would be assigned by a script, modifing the classes’ variables.
But i’m running into some trouble…
How do i memorize the weapons’ scripts (to indicate the players’ primary and seconday weapon) if the classes can be different depending on the type of weapon?
How can i set the right stats for the right gun without an horrible mess of methods that have lots of parameters passed by reference?
Is using subclasses even worth it?

If you have any tips on the matter i would really appreciate it…
Thanks in advance

This is a really broad question you are asking and there are many different ways to go about this. Each studio and each designer will have their own take on it. Inheritance is a powerful feature of C# but I would look into interfaces as well. They are what I use to make many of my systems work. For example, I would look at my desired behaviors and see what systems are going to interact with the weapons (hit detection is a good example). Then determine exactly what I would need from the weapon for that system(Base Damage, Physics Impulse, HitType, etc). Those things are what I would put in an IHitSource interface and each thing that could cause a hit would implement that interface. So when ever a hit occurred (physics collision, raycast, or whatever) I know exactly what interface to look for on the hitting object. Inheritance can be used for this use case just as easily, but in my experience it is more fragile and if your class structure starts to get more complicated it is much easier to add another interface to a class than restructure your inheritance tree to accommodate a new set of features.

Prefabs are the easiest way to get different values in variable fields for your assets.

3 Likes

I wouldn’t use inheritance for that. Inheritance is usually a bad approach if you are modeling game related objects. Especially if you are going to make deep inheritance hierachies, or have very different behaviour for all weapons.

Composition is less rigid and give you more flexibility while making your code simpler.
Shared functionality should go to another components. Specific functionality should be specific enough so you don’t need inheritance, and can use interfaces only.

Your composition hierachy can look like this (-> has reference to):
Minigun:
→ RangedWeaponCore → WeaponCore (Weapon shared script)
← MinigunView (Animation, sound and other stuff that doesn’t affect game)
→ IAttackStrategy (HitscanAttackStrategy)

RocketLauncher :
→ RangedWeaponCore → WeaponCore
← RocketLauncherView
→ IAttackStrategy (RocketProjectileAttackStrategy)

Sword:
→ MeleeWeaponCore → WeaponCore
← MeleeView
→ IAttackStrategy (MeleeAttackStrategy)

With such approach you can reuse some components or can create something completely new. Sword which casts fireballs, or ranged weapon with optional melee attack will be pretty easy to do. Your class can compose as many objects as needed, can use many strategies at the same time, can have two views for left and right hand, and stuff like that.

2 Likes

Thanks to @Lekret and @DejaMooGames for the advice! I will retry making the system keeping in mind your tips!

A quick question for @Lekret , how should i go about setting the variables for components, like “WeaponCore” in your example, from the classes that contain them?
Let’s say i have a shotgun object with the Shotgun class. The Shotgun class has a int pellets variable, and a reference to the BaseGun class (BaseGun baseGunClass = new BaseGun() ). The BaseGun class has an int ammo variable.
How do i set the int ammo variable? Do i use BaseGun’s constructor from the Shotgun class? If so how can i pass it the value for the ammo variable without having an ammo variable also for the Shotgun class?

Thanks for your time

Also P.S. question:
If the referenced class has a variable that i need, is it better to just having it public or having an “public var GetValue()” method in the referenced class?
I’m sure that having the variable public is way faster and easier to do, but maybe in the long run having all variables of core classes private and having methods that return them is more tidy and less conflictable?

You may make BaseGun as unity component, so you will be able to set ammo via inspector.

Or if you want to use usual class you can add [Serializable] on top of BaseGun class, create [SerializeField] BaseGun in your Shotgun and configure its fields from inspector.

Another variant is to create WeaponConfig class, which will contain readonly data, and will be configured from the inspector of Shotgun, then all you need is to pass single parameter to new BaseGun(config).

Making public fields is mostly a bad idea for classes. You can’t make public interface to your field. Your can’t put a debug breakpoint on a public field. You usually don’t want to change public fields, or may want to add some additional behaviour when field was changed.
All these problems are solved with properties. Just put get-only properties if you want to expose something.

1 Like