Summary
Every Unity script that inherits from MonoBehaviour has access to a set of lifecycle methods that the engine calls automatically at specific moments. The two most important for beginners are Start, which runs once when the scene begins, and Update, which runs every frame while the scene is playing. Understanding when each method runs — and which type of logic belongs in each — is the foundation of all Unity scripting.
Key ideas
Start() — runs exactly once, when the GameObject first becomes active in the scene. Use it for:
- Logging initial state to verify the script is attached and configured correctly
- Caching component references (e.g. storing a
Rigidbody2Din a field soUpdatecan use it without callingGetComponentevery frame) - Any one-time initialisation
Update() — runs every frame, as long as the scene is playing and the GameObject is active. Use it for:
- Reading player input
- Moving objects
- Ticking timers
- Anything that must respond to the passage of time
Time.deltaTime — the number of seconds that elapsed since the last frame. Multiplying any per-frame value by Time.deltaTime converts it from “per frame” to “per second”, making it frame-rate independent. A machine running at 60fps calls Update 60 times per second with a small deltaTime; a machine at 30fps calls it 30 times with a larger deltaTime. The product is the same either way.
gameObject.name — the name of the GameObject this script is attached to. Including it in Debug.Log messages is useful when multiple objects share the same script.
In practice
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
private float logTimer = 0f;
// Runs once when the scene begins
void Start()
{
Debug.Log("[" + gameObject.name + "] PlayerController ready. Speed: " + moveSpeed);
}
// Runs every frame
void Update()
{
HandleMovement();
LogPositionPeriodically();
}
private void HandleMovement()
{
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
// Time.deltaTime makes movement speed-per-second, not speed-per-frame
transform.Translate(h * moveSpeed * Time.deltaTime, v * moveSpeed * Time.deltaTime, 0f);
}
private void LogPositionPeriodically()
{
logTimer += Time.deltaTime;
if (logTimer >= 2f)
{
Debug.Log("[" + gameObject.name + "] Position: " + transform.position);
logTimer = 0f;
}
}
}Keep Update() short: delegate logic to named private methods rather than writing everything inline. A long Update body is hard to read and debug. The HandleMovement / LogPositionPeriodically pattern above is the recommended style.
Other lifecycle methods
| Method | When it runs |
|---|---|
Awake() | Before Start, even if the script is disabled. Use for self-initialisation that other scripts’ Start may depend on. |
OnEnable() / OnDisable() | When the GameObject is enabled or disabled. Useful for resetting state. |
FixedUpdate() | At a fixed time step (default 50 times/second). Use for physics calculations instead of Update. |
LateUpdate() | After all Update calls this frame. Use for camera follow logic. |
OnDestroy() | Just before the GameObject is destroyed. Use for cleanup. |
Gotchas
- Never call
StartorUpdateyourself. Unity calls them. If you want to run initialisation code manually, extract it into a separate method and call that. - Variables declared inside
StartorUpdateare local. They exist only for that call. Fields (declared at class level) persist between frames. Updatedoes not run if the GameObject is inactive or the script component is disabled.- Physics-based movement belongs in
FixedUpdate, notUpdate, to avoid erratic behaviour when frame rate fluctuates.
Practice
Create a GameObject named LifecycleProbe. Add a script with:
- one
Debug.LoginStart - one timer in
Update - one private method called from
Update - one field that stores elapsed time
Success test:
Startlogs once when Play mode begins- the timer logs every two seconds
- the log includes
gameObject.name - no local variable is expected to remember a value between frames
Extension:
- disable the script component during Play mode and observe that
Updatestops running
Self-test
- Which method runs once:
StartorUpdate? - Why should movement usually multiply by
Time.deltaTime? - A variable declared inside
Updateresets every frame. Where should it go if it needs to remember a value? - Which lifecycle method is normally better for physics movement?
- Why is a short
Updatemethod easier to debug?
Answers
Startruns once when the script first becomes active.Time.deltaTimeturns movement into units per second, so speed stays consistent across different frame rates.- It should be a field, declared at class level.
FixedUpdate, because Unity runs physics on a fixed timestep.- A short
Updatepoints you to named helper methods, so the likely fault is easier to find.
Related
- csharp-methods - the method syntax used in lifecycle methods
- unity-input - reading player input in
Update - unity-transform - moving objects in
Update - unity-getcomponent - caching component references in
Start - unity-inspector-references - assigning references before
Startruns