what if you have a taser that deals no damage but still causes the player to play a flinching animation? what about if the player is in a poison cloud that doesn’t stunlock the player but constantly damages them over time? by having Hit call Damage you’re locking down the code.
what you would actually want to do is just have both Hit and Damage as separate calls. and even better in separate scripts. Hit() shouldn’t call Damage(), nor should Damage() call Hit(). you’ll want to keep them decoupled if you can.
have the triggering class just check if the script is IHittable and is IDamageable in separate if checks.
here the bullet is fully decoupled yet can still pass the info that’s needed for the scripts catching it. if the bullet has a noticable effect on what it collided with, then it can use the Hit(). if the bullet can damage the target then it can call Damage(). they are two calls exclusive to each other and are only linked due to being called in the same onTriggerEnter event. while on the other hand the player script isn’t programed specifically to handle the bullet, the two effects have been decoupled allowing all sorts of cool scenarios to come into play.
if you want your character be even more flexible then you’d write the handler scripts for IHittable and IDamageable into separate scripts as separate components. that way you can, during runtime, remove/disable/ or decorate(cool concept, look up decorator pattern when making buffs/debuffs) the IDamageable component to make the player invincible cause he picked up a power star. and when the powerup fades you re-enable/re-add/revert that IDamageable script back to normal.
I tend to think SRP in terms of game jobs I.E. Handing damage related
functionality because I'm a bit lazy and because I tend to code with YAGNI.
I'd just have one abstract class that deals with Health related stuff because
that is as specific as I generally need to get. What I mean by this is that when you are dealing with Damage and hitting you are generally going to have to deal with much of the same logic. The use cases when hitting and damaging aren't overlapping is generally pretty small so I'd have them fall under the same responsibility.You could just possibly rejigger have Damageable inherit from the interfaces if you like but I really don't see a need to go that deep.
public abstract class Damageable
{
public int HP;
public Animator Anim;
AudioSource audio;
public AudioClip LameHitSound;
public AudioClip HealSound;
public AudioClip DamageSound;
//maybe some cooldown timer logic, particle effects, damage sprites etc..
public virtual void TakeDamage(int amt)
{
HP-=amt;
if(HP<=0)
{
Death();
}
}
public virtual void Hit(int amt)
{
if(amt==0)
{
//play sound effect for lame damage
audio.PlayOneShot(LameHitSound, 0.7F);
Anim.SetTrigger("TakeLittleDamage");
}
else if(amt<0)
{
//play effects and such for healing
audio.PlayOneShot(HealSound, 0.7F);
Anim.SetTrigger("Heal");
}
else
{
//shake screen, preform screen shake and other effects for damage
audio.PlayOneShot(DamageSound, 0.7F);
Anim.SetTrigger("TakeSolidDamage");
}
}
public abstract void Death();
}
//and Inherit from it
public class PlayerHealth : Damageable
{
public override void Death()
{
//Call Game Over logic
}
}
//and override as you need
public class EnemyHealth : Damageable
{
public override void Death()
{
//play death anim, set death variables
}
}
public class BoxHealth : Damageable
{
void Start(){
HP = 1;
}
public override void Death()
{
//Provide player with Item;
}
public override void Hit(int amt)
{
if(amt>0)
{
audio.PlayOneShot(DamageSound, 0.7F);
Anim.SetTrigger("TakeSolidDamage");
}
}
}
Another option is to pass in an IDamageDealer (from the weapon) to the Hit function. Passing the damage amount alone maybe doesn’t make sense conceptually, but passing in the thing that hit it does.
public void Hit(IDamageDealer damageDealer)
{
damageable.Damage(damageDealer.Amount);
Debug.Log(damageDealer.Name + "hit me for " + damageDealer.Amount + " damage");
}
Also, look into the new UnityEvent variable. And sometimes it’s just easier to use components for this type of thing.