How to go about building systems?

Hello everyone, what would be the best way to program in a system that will have different variations of the same type? For instance:

-Different types of enemies
-Different types of weapons
-Different types of consumables
-different types of damage modifiers

  • etc.

Would inheritance help? I heard to keep away from inheritance but to instead go for composition.

What would be the best route for staying away from complexity and go for decoupling, reusable clean code?

You can use and combine both. Build the base-hierarchy using inheritance. Add shared behaviors using composition.
So you would, for example, have something like ‘Weapons’ and ‘Armor’ derive from ‘Equipment’. Maybe you would have some more specific weapon categories after that, like ShortRangeWeapon and LongRangeWeapon.

To add specific properties which could be shared between different of those classes, you would then use composition. So for example, if certain items could make your character slow, this behavior could be defined in an ISlowingEquipment interface, and then implemented in the HeavyWeapon as well as the HeavyArmor classes.

I believe people like to use scriptable objects for saving informations about these items, but since i never implemented an item / enemy hierarchy like described above in Unity so far, i cant really help on that :slight_smile:

I’ve tried many different ways over the years and really everything works to some extent, and then it all becomes too complicated and code smells start occuring. You will want to keep everything as open ended as possible, which means only define common variables/functions thats are 100% common, and even then it’s safer to have them as abstract rather than fixed behaviour. So while you might be certain that a Weapon.DealDamage might mean deal X damage, after many updates/changes you’ll notice to add modifiers or other features that are going to modify the base functionality. As such it’s better to not define the behaviour of DealDamage, but just note that the method needs to exist and define it customized for each object type.

Long story short - abstract classes and inheritance are a good way