unity-game-agent / unity_agent /knowledge /entries /unity_fundamentals.md
ryzerrr's picture
Upload folder using huggingface_hub
40c0886 verified
|
Raw
History Blame Contribute Delete
3.94 kB
# Unity Fundamentals
## MonoBehaviour Lifecycle
Every gameplay script in Unity derives from `MonoBehaviour`. The engine calls
a fixed sequence of messages; understanding the order is the difference
between code that runs smoothly and code that stutters or races.
```
Awake() -> OnEnable() -> Start()
|
v
FixedUpdate() (physics, fixed timestep) --+
|
Update() (input, gameplay) --+
|
LateUpdate() (camera follow, post-sim) --+
|
OnDisable() -> OnDestroy()
```
| Message | When it runs | Typical use |
|----------------|-----------------------------------------------|-----------------------------------------------|
| `Awake` | Once, when the script instance is loaded | Cache components, set up singletons |
| `OnEnable` | Every time the component is enabled | Subscribe to events |
| `Start` | Once, before the first Update | Cross-object references (other objects' Awake have run) |
| `FixedUpdate` | Fixed timestep (default 0.02 s = 50 Hz) | Rigidbody physics forces |
| `Update` | Every rendered frame | Input polling, gameplay logic |
| `LateUpdate` | After all Update calls have finished | Camera follow, post-processing |
| `OnDisable` | When the component is disabled | Unsubscribe from events |
| `OnDestroy` | When the GameObject is destroyed | Cleanup native resources |
> **Gotcha:** `Camera.main` searches the scene by tag every call in 2022.3.
> Cache it in `Awake` if you call it more than once per frame.
## GameObjects and Components
A `GameObject` is an empty container. Behaviour is added through
**components**:
```csharp
var go = new GameObject("Enemy");
go.transform.position = Vector3.zero;
go.AddComponent<Rigidbody>();
go.AddComponent<CapsuleCollider>();
var ai = go.AddComponent<NPCController>();
ai.player = GameObject.FindGameObjectWithTag("Player").transform;
```
* Every GameObject always has a `Transform` (or `RectTransform` under a
Canvas). You cannot remove it.
* Use `GetComponent<T>()` / `GetComponentInChildren<T>()` /
`GetComponentInParent<T>()` to reach related components. Cache the result
in `Awake` instead of calling it every frame.
* `RequireComponent(typeof(T))` makes Unity auto-add the required component
when the script is added in the inspector.
## The Component pattern in practice
```csharp
[RequireComponent(typeof(Rigidbody))]
public class PlayerController : MonoBehaviour
{
private Rigidbody _rb;
private void Awake()
{
_rb = GetComponent<Rigidbody>(); // safe: RequireComponent guarantees it
}
}
```
## Coroutines
Coroutines let you write asynchronous-looking code that runs across multiple
frames:
```csharp
private IEnumerator RespawnAfterDelay(float seconds)
{
yield return new WaitForSeconds(seconds);
transform.position = _spawnPoint;
}
private void OnDeath() => StartCoroutine(RespawnAfterDelay(2f));
```
* `yield return null;` waits one frame.
* `yield return new WaitForFixedUpdate();` waits until the next physics step.
* `yield return new WaitUntil(() => _isGrounded);` waits for a condition.
## Inspector best practices
* Use `[Header]`, `[Tooltip]`, `[Range]`, `[SerializeField]` to keep the
inspector tidy.
* Prefer `private` + `[SerializeField]` over `public` for fields that should
not be touched by other scripts but should be editable in the inspector.
* Use `[System.Serializable]` on structs/classes to make them expandable in
the inspector.