Search Unity

How to make a subclass of Enemy script?

Discussion in 'Scripting' started by Pixitales, Jun 6, 2019.

  1. Pixitales

    Pixitales

    Joined:
    Oct 24, 2018
    Posts:
    227
    I have an enemy script that inherits from character script. The player also uses character scripts. I have a lot of different enemies that does different things and Unity doesn't allow me to inherit from multiple classes (character and enemy script). I want to make a script called "Stumpy" as one of my enemies that likes to sleep most of the time. What is a good way to organize this?
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    If you Enemy class inherits from Character, then your Stumpy class will get that inheritance automatically when you inherit from Enemy.
     
  3. Pixitales

    Pixitales

    Joined:
    Oct 24, 2018
    Posts:
    227
    I already tried that, it gives me all sorts or errors like it doesn't know enemy script inherits from character script.

    public class Character: MonoBehavior

    public class Enemy: Character

    public class Stumpy:Enemy
     
  4. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Such as?
     
  5. Pixitales

    Pixitales

    Joined:
    Oct 24, 2018
    Posts:
    227
    like my animator, movement, rigidbody (everything from character script), doesn't exist once you write and only have this line of code:
    protected override void Update()
    {
    base.Update(); //Get inherit from enemy script Update
    }

    i think Unity is pretty smart to know that you're trying to inherit from multiple class which is not allowed.
     
    Last edited: Jun 6, 2019
  6. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    OK, so Update is a special case (which I learned the hard way), and Unity does not respect overrides for Update at all. Or really, any of Unity's builtin function calls (Start, OnEnable, etc). So for the builtin functions, do something like:
    Code (csharp):
    1. //base class ONLY
    2. public class Character : MonoBehaviour {
    3. void Update() {
    4. CharacterUpdate();
    5. }
    6. protected virtual void CharacterUpdate() {
    7. Debug.Log("Base class update");
    8. }
    9. }
    10.  
    11. //inherited class
    12. public class Enemy : Character {
    13. protected override void CharacterUpdate() {
    14. Debug.Log("Enemy Update");
    15. base.CharacterUpdate();
    16. }
    17. }
    And so on. That will allow you to use inheritance to alter the behavior of those functions properly.
     
  7. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    Because of the special behaviour of Unity's callback functions, I like to only put method calls in them and never any logic. With inheritance, I typically have a structure that is somewhat like this:
    Code (CSharp):
    1. public abstract class BaseClass : MonoBehaviour {
    2.    private void Awake() => Initialize();
    3.    private void OnEnable() => Enabled();
    4.    private void OnDisable() => Disabled();
    5.    private void Update() => OnUpdate();
    6.    private void OnDestroy() => Destroy();
    7.    //...Any other callback functions I might need for whichever purpose this class has...
    8.  
    9.    protected virtual void Initialize() { }
    10.    protected virtual void Enabled() { }
    11.    protected virtual void Disabled() { }
    12.    protected virtual void OnUpdate() { }
    13.    protected virtual void Destroy() { }
    14. }
    Then just have any child classes implement these methods whenever necessary:
    Code (CSharp):
    1. public class ChildClass : BaseClass {
    2.    protected override void Initialize() {
    3.       //Maybe get some component references here...
    4.    }
    5.  
    6.    protected override void Enabled() {
    7.       //Maybe assign some event handlers here...
    8.    }
    9.  
    10.    protected override void Disabled() {
    11.       //Maybe unassign some event handlers here...
    12.    }
    13.  
    14.    protected override void OnUpdate() {
    15.       //Maybe read user-inputs here...
    16.    }
    17.  
    18.    protected override void Destroy() {
    19.       //Maybe play some kind of particle effect here...
    20.    }
    21. }
    I find this tends to eliminate some of the awkward behaviour between Unity's callback functions and inheritance.
     
    Last edited: Jun 6, 2019
    Amon, StarManta and halley like this.
  8. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Oh I like the use of that syntax. Very clean and clear. Gonna have to use that in the future.
     
  9. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    Unity is built based on concept of using composition instead of inheritance. With inheritance there's common pitfall when you create base class character, when inherit a mage and a warrior, and then you want to add warrior mage, you can't ibherit both. To avoid that, create Character component. Then create Warrior component, what relies on character methods and events to fulfill it's purpose. This way you may combine your code units freely as you wish.
     
  10. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Just a note to anyone doing this (i also define virtual methods in this way). Defining these magic methods will have all of your derived objects firing those callbacks even if not needed. Empty Update callbacks are still cached and iterated over each frame. The performance hit will be negligible unless you have a absolute ton of objects (or run your game on a toaster) but it's good to be aware of that behavior and not haphazardly update every object in your game.
     
    SparrowGS and palex-nx like this.
  11. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    There's no reason to not use inheritance if it can be applied. It's still a very powerful way to reuse code and classify objects without redundancy.
    Unity's built-in components even use inheritance. BoxColliders, for instance, inherit from Collider, which inherits from Component.

    True, I should have clarified that in the example I posted, but I meant to imply that I would only implement the callback functions that I plan on all child objects using.
    If only some need Update() and others don't, I would still just define Update() in their scripts, rather than their inherited scripts.
     
    SparrowGS and LiterallyJeff like this.
  12. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    I use inheritance all the time just fine, for example:

    Part "base" class that inherit ScriptableObject (that inherit from object)
    Part_Chasis, Part_Engine, Part_Accessory, Part_Armor and Part_Turret all inheriting from Part obviously
    Part_Turret_Ballistic and Part_Turret_Raycast inheriting Part_Turret
    Part_Turret_Raycast_Scattershot
    inheriting from Part_Turret_Raycast

    just to name a few of the weapons system in my game.
     
  13. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    How would you implement Part_Turret_Ballistic_Scattershot?
     
  14. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    You can't in my case, you'll have to restructure.

    you'll have to make another class, but in the specific case of the scatter shot all it does is hold one extra variable (shotNum) and on the fire function it loops over the call.
    (in practice theres a bit more code for the visuals, but that's pretty much all)
     
  15. Grankor

    Grankor

    Joined:
    Mar 2, 2015
    Posts:
    14
    Just an idea... You could use something along the lines of Dependency injection using interfaces.

    You wouldn't carry over logic, but you would have a interface you could use to make sure you're including all the methods that you need.
    In addition, similar to use abstracts, you can call the method via the interface.

    The added benefit to using interfaces, is that you aren't limited to how many you can use. (And you can always leave a method empty, or send some kind of generic return if not needed)


    Code (CSharp):
    1. public interface IBaseCharacter
    2. {
    3.      void GetHitpoint(float hitpoints);
    4.     bool IsDead();
    5. }
    6.  
    7. public class Character : IBaseCharacter
    8. {
    9.     void GetHitpoint(float hitpoints)
    10.     {
    11.          _hitpoints += hitpoints;
    12.     }  
    13.  
    14.      bool IsDead()
    15.      {
    16.           return isDead;
    17.      }
    18. }
    19.  
    20.  
    21.  
    22. public class Something
    23. {
    24.       IBaseCharacter _player;
    25.  
    26.       void Start()
    27.        {
    28.              _player =  FindObjectOfType<IBaseCharacter >();
    29.        }
    30.  
    31.        void Update()
    32.        {
    33.               Debug.log($"Character dead? {_player.IsDead()}");
    34.        }
    35.  
    36. }