How do I get a function of a derived class of a child game object to activate AFTER the Start method from during the instantiation of its parent gameobject?

I wanted to make a base class component for animating sprites by a selected sequence, followed by a derived class that initializes the sequence data for each game object containing a sprite. I have succeeded in doing so and I wanted to apply this to some animated arrows that are children of a root menu screen. Upon instantiating the root menu screen, however, I have come across a problem with triggering a function that selects a sequence while compiling all the necessary data in the Start method of the root menu script. For some reason, the base component of the sprite animator is activating the assigned outside function BEFORE it runs its Start method. This causes the sequence to read as null and create null reference errors. Is there a specific reason the Start methods of both the base and derived animator classes are not being triggered in time before other functions? Does it have something to do with the derived component being attached to a child object while the root or parent is running first? Here is some example code to clarify what I’m going through:

//Base class of the sprite animator
public abstract class AnimateSprite : MonoBehaviour {

    [SerializeField] protected bool animateOn = true;
    [SerializeField] public int animState;
    public Dictionary<int, AnimData> animSeq;
    public Dictionary<int, AnimNext> animSkip;
    SpriteRenderer sprend;
    Sprite[] spr;

    protected bool loopOn = false;
    protected int loopCount = 0;

    int frame = 0;
    int renderFrame = 0;

    public class AnimData
    {
        public int[] phase;
        public int[] speed;
        public string spriteName;
    }
    public class AnimNext
    {
        public int nextPhase;
        public bool loopPhase;
        public int loopAmount;
    }

    // Use this for initialization
    protected virtual void Start () {
        StartCall();
        sprend = gameObject.GetComponent<SpriteRenderer>();
        spr = Resources.LoadAll<Sprite>(sprend.sprite.name.Substring(0, sprend.sprite.name.Length-2));
        frame = 0;
        renderFrame = 0;
        if (animSeq != null)
        {
            sprend.sprite = spr[animSeq[animState].phase[renderFrame]];
        } else
        {
            sprend.sprite = spr[0];
        }
    }

    protected abstract void StartCall();

    void FixedUpdate()
    {
        //Animation in progress
    }

    public void setAnimation(int nAnimState)
    {
        animState = nAnimState;
        //ERROR STARTS BELOW
        string nSprite = animSeq[nAnimState].spriteName;
        sprend = gameObject.GetComponent<SpriteRenderer>();
        spr = Resources.LoadAll<Sprite>(nSprite);
        sprend.sprite = spr[animSeq[animState].phase[0]];
        loopOn = animSkip[animState].loopPhase;
        loopCount = animSkip[animState].loopAmount;
        frame = 0;
        renderFrame = 0;
    }
}

//Derived class of sprite animator
public class AnimateGlowArrows : AnimateSprite {

    // Use this for initialization
    protected override void Start () {
        base.Start();
    }

    protected override void StartCall()
    {
        initializeAnimation();
    }

    public void initializeAnimation()
    {
        animSeq = new Dictionary<int, AnimData>
        {
            { 0, new AnimData{ phase = new int[1]{ 0 }, speed = new int[1]{ 1 }, spriteName = "MenuScreenArrow1" } },
            { 1, new AnimData{ phase = new int[6]{ 1, 2, 3, 4, 3, 2 }, speed = new int[6]{ 2, 2, 3, 3, 3, 2 }, spriteName = "MenuScreenArrow1" } },
            { 2, new AnimData{ phase = new int[1]{ 5 }, speed = new int[1]{ 1 }, spriteName = "MenuScreenArrow1" } }
        };
        animSkip = new Dictionary<int, AnimNext>
        {
            { 0, new AnimNext{ nextPhase = 0, loopPhase = false, loopAmount = 1 } },
            { 1, new AnimNext{ nextPhase = 1, loopPhase = false, loopAmount = 1 } },
            { 2, new AnimNext{ nextPhase = 2, loopPhase = false, loopAmount = 1 } }
        };
        loopOn = animSkip[animState].loopPhase;
        loopCount = animSkip[animState].loopAmount;
    }
}

//Component of root menu screen where animator is being called within
public class MenuScreenRoot : MonoBehaviour {

    //Initializing fields here


    void Start()
    {
        //After certain code, assign animator HERE
gameObject.transform.Find("MenuScreenArrows").gameObject.transform.Find("MenuScreenArrowLeft").GetComponent<AnimateGlowArrows>().setAnimation(0);
    StartCoroutine("summonMenu", endMoveY);
    }
}

For the record, I can bypass this issue if I use a coroutine that waits for the sequence to no longer be null before activating, but I don’t want to rely on that as a default, as I believe this would eventually slow down processing time. Could I get a solution regarding the order around functions and Start methods sometime soon?

A couple of things:

It’s generally a bad idea to implement the MonoBehaviour event methods ( Awake, Start, Update, etc) as abstract/virtual or to override them. Unity calls these methods via reflection, so you can just add the vanilla event methods to your AnimateGlowArrows class directly.

As for guaranteeing that the subclass fires it’s Start event first, you could do a couple things:

  • Edit the script execution order for your base class and all its inheritors
  • Remove the Start event from the base entirely and move that logic to a protected void Initialize () method to do your initialization, then have the derived classes call that from their Start events.