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?