GetComponent() behaving oddly

So I am experiencing a strange issue.

I have 3 scripts: NPC, Enemy, Slime

  1. NPC:

    public abstract class NPC : MonoBehaviour {
    private void Awake(){
    rb = GetComponent();
    animatorr = GetComponent();
    }
    }

  2. Enemy:

    public abstract class Enemy : NPC
    {
    public void Start(){
    MoveNewLocation();
    }

    private void Update() {
       ... (Some irrelevant functions)
    }
    
    private void FixedUpdate()
    {
    rb.position = Vector2.MoveTowards(rb.position, newPosition, speed);
             animatorr.SetBool("attack", false);
             if (rb.position.x < newPosition.x){
                    animatorr.SetFloat("horizontalMotion", 1.0f);
                }
            else {
                    animatorr.SetFloat("horizontalMotion", -1.0f);
                }
            if (Vector2.Distance(rb.position, newPosition) < 1){
                MoveNewLocation();
            }
    }
    

Slime:

public class PurpleSlime : Enemy
{
    // Start is called before the first frame update
    void Start()
    {
        ... (some irrelevant functions)
    }  
}

However, during debugging, I found out that the animatorr and rb is null for the Enemy class. When I used Debug.Log, I found out that the FixedUpdate() for Enemy script is executed before the Start() function which does not make sense since Start() is always called prior to FixedUpdate().

Enemy script is meant to inherit from NPC because NPC defines some basic logic (E.g health, money, getting damaged, die). The reason why I created a separate Enemy script is because I can add unique enemy behaviors which my NPC should not be able to access (E.g Special attack).

Does anyone know why this error is occuring?

It looks like the issue is that you are trying to access the rb and animatorr variables in the FixedUpdate method of the Enemy class before they have been initialized in the Awake method of the NPC class. Since the FixedUpdate method is called by Unity before the Start method, the Awake method of the NPC class has not yet been called and therefore the rb and animatorr variables are still null.

One way to fix this issue would be to move the initialization of the rb and animatorr variables to the Start method of the NPC class instead of the Awake method. This will ensure that the variables are properly initialized before they are used in the FixedUpdate method of the Enemy class.

Another option would be to use the Awake method of the Enemy class to initialize the rb and animatorr variables, since the Awake method is called before the Start method. This way, you can ensure that the variables are properly initialized before they are used in the FixedUpdate method.

Overall, it’s important to consider the order in which methods are called by Unity when writing scripts that rely on inheritance and overridden methods. By understanding the execution order of different methods, you can avoid issues like the one you are experiencing and ensure that your scripts behave as expected.

Unity’s component system is meant to favour object composition over inheritance. There’s nothing wrong using inheritance per se, but if you use inheritance, use it correctly. In the end the class that you attach as component is a single class. That class may be derived from other classes, but the actual instance is one object that has one type. Unity is calling “magic methods” on your class automatically. However any class can only have a single implementation of a method. If you derive one class from another and you want to override the functionality of a method, that method needs to be virtual and you have to use the override keyword in the child class. Also such methods should be declared protected and not private, especially any “magic” method that should be called by Unity. If the base class has a private Awake method and the child class also implements an Awake method, the one of the base class would never be called. As I said, the final object only has one method implementation and Unity calls the method on that object.

Your Enemy class defines a Start method. However your PurpleSlime class which is derived from Enemy, implements a new Start method. So the one of the Enemy class would not be called.

Unity’s magic methods don’t really care about virtual and override since Unity directly calls the method on the object itself. However it generally helps to avoid mistakes. So you may want to do

public abstract class Enemy : NPC
{
    protected virtual void Start()
    {
        MoveNewLocation();
    }
    // [ ... ]

and implement your PurpleSlime like this:

public class PurpleSlime : Enemy
{
    // override the base Start method
    protected override void Start()
    {
        base.Start(); // call the base implementation
        // [ ... ]
    }  
}

That’s essentially OOP 101. You probably want to do the same for Awake and maybe Update / FixedUpdate so a derived class has the chance to override the functionality.