Hey all. At the moment I’m working on a basic combat system. The current way I have it set up:
Player: has a combat script that when attacking checks nearby for enemies, and grabs their “enemy” component and runs the “takeDamage” function within that script.
Enemy: has an “enemy” script that runs its basic functions (chase player, attack when near player, stop moving when taking damage).
I’m wanting to have different enemy types with vastly different behaviours. For example, when this current simple enemy is hit, it simply stops moving and has its health reduced. But I want different behaviours, like if a different enemy was hit, instead of just taking it, it would block an attack or maybe counterattack.
I’ve run into a problem. The way I’m checking for enemies is by getting this specific “enemy” component and then calling its “takeDamage” function. So if I make a new component for a new enemy type, I would have to add code to additionally check for this other enemy component. I would imagine there is a more sensible way to do this?
So basically my question; what is a good way to go about this kind of thing? I’ve tried to look into it and come across suggestions for scriptableObjects, which I am somewhat familiar with but am not sure how it would apply in this case. If I used scriptableObjects I’d still have to check for the individual enemy types, unless there is some way to check for objects of a certain type/template? Honestly clueless lol. Cheers.
Use subclasses. Create additional scripts that extend the enemy script and inherit / override the base behaviour.
Use interfaces. Create an interface with the takeDamage method and use GetComponents with that interface.
Use composition. Create an additional damage script that handles receiving the damage and can be shared by all enemies scripts. The component would have an event or something to let the enemy scripts know when they’re damaged.
Use messages. Unity has the concept of messages (see GameObject.SendMessage), that allow to send a generic message to all components on a game object, regardless of their type.
I don’t think any of these approaches are inherently better or worse*, it depends on what you want to achieve and the complexity / lifecycle of your project. Using an interface is probably a good place to start.
(* except SendMesage using strings for message names and weak typing for the argument, which is easy but can get out of hand and be hard to refactor.)