Execution order of the Start() method after Instantiate

I don’t understand why we are not getting a Null reference exception after moving the transform.LookAt() to the Start() method. As I understand, the Start() method gets executed when the script is enabled. So now we are calling GetPosition() in the Start() method, and GetPosition contains a call to target.GetComponent(), which just after the instantiation should be null, since we will assign it in Weapon.cs after the call instantiate de Projectile (see code below).

The only reason I see for us not getting the exception is that the Start() method on Projectile is called after

            projectileInstance.Target = target;

in Weapon.cs.

Which messes my understanding of the execution order. Is that what is happening?

    public class Projectile : MonoBehaviour {

        private Health target;
        private float damage;
 
        // ...

        public Health Target { get => target; set => target = value; }
        public float Damage { get => damage; set => damage = value; }

        private void Start() {
            transform.LookAt(GetPosition()); // This is now executed after instantion
        }

        void Update() {
            if (target != null) {
                //transform.LookAt(GetPosition());
                transform.Translate(Vector3.forward * speed * Time.deltaTime);
            }
        }

        private Vector3 GetPosition() {
            CapsuleCollider targetCollider = target.GetComponent<CapsuleCollider>(); 
            // This line above I believe should raise the exception
            if (targetCollider != null) {
                return target.transform.TransformPoint(targetCollider.center);
            } else {
                return target.transform.position;
            }
        }
        //...
    }

Back in Weapon.cs, we call the instantiation here:

        public void LaunchProjectile(Transform rightHand, Transform leftHand, Health target) {
            Projectile projectileInstance = Instantiate(projectile, GetHandTransform(rightHand, leftHand).position, Quaternion.identity);
            projectileInstance.Target = target;
            projectileInstance.Damage = weaponDamage;
        }

PS. Ok, I made some “log debug” and verified that the Start() method in Projectile is called not just after instantiation, but instead after LaunchProjectile is finished… I guess my question is now, why exactly is the Start() method called?

I would think the object will be instantiated within the context of the first method and within that frame. on the next frame Start() will be run.
Have you tried adding an Awake() method with some debug output?

Also, check the Unity documentation on the lifecycle of a GameObject.

When you instantiate a new object or component, the Awake() method is run immediately, and then control is returned to the script that instantiated the object.

This gives you the opportunity to set the target and damage before the Start() method runs.
In the case of Instantiated items, Start() will run before the next Update() cycle (i.e. in the next frame).

1 Like

That confirms my interpretation of what’s going on… :slight_smile:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms