# Game development rules

Follow these CodeWiki-derived rules when you work in this project.

- Reading a singleton field set by another object's `Awake` creates an undeclared cross-object ordering dependency.
  Why: As a scene grows, execution order changes, or an object is instantiated at runtime, that read can intermittently return `null`.
  Source: [MonoBehaviour lifecycle](https://codewiki.com/gamedev/unity-monobehaviour/)
- Subscribing in `Start` but unsubscribing in `OnDisable` disconnects the component permanently after its first disable.
  Why: `Start` does not run again when the component is re-enabled.
  Source: [MonoBehaviour lifecycle](https://codewiki.com/gamedev/unity-monobehaviour/)
- Do not treat `enabled = false` as coroutine cancellation lets an existing coroutine keep changing state.
  Why: Enabling the component later can then start a second instance alongside the first.
  Source: [MonoBehaviour lifecycle](https://codewiki.com/gamedev/unity-monobehaviour/)
- Applying physics forces in `Update`, or sampling a one-shot button only in `FixedUpdate`, mixes render-frame cadence with physics-step cadence.
  Why: A slow frame can contain several fixed steps, while a fast frame can have none.
  Source: [MonoBehaviour lifecycle](https://codewiki.com/gamedev/unity-monobehaviour/)
- Do not treat `OnDestroy` as a `finally` that every object must reach misses GameObjects that were never active and stakes external-resource correctness on application-shutdown behavior.
  Source: [MonoBehaviour lifecycle](https://codewiki.com/gamedev/unity-monobehaviour/)
- Do not assume this is safe: writing `OnEnabled`, giving `Awake` the wrong parameters, or generating `override void Start()` can silently omit a callback or fail compilation.
  Why: A method that looks like a lifecycle hook is not necessarily a Unity message.
  Source: [MonoBehaviour lifecycle](https://codewiki.com/gamedev/unity-monobehaviour/)
- Do not treat a coroutine as a background thread puts blocking I/O, `Thread.Sleep`, or a long CPU loop between two yields and stalls the main thread.
  Source: [Unity coroutines](https://codewiki.com/gamedev/unity-coroutines/)
- Do not assume this is safe: using `WaitForSeconds` in a pause screen means the wait does not finish while `Time.timeScale = 0`.
  Source: [Unity coroutines](https://codewiki.com/gamedev/unity-coroutines/)
- Do not assume this is safe: starting a fresh coroutine on every event without retaining its handle lets old and new flows mutate the same object together.
  Source: [Unity coroutines](https://codewiki.com/gamedev/unity-coroutines/)
- Do not assume that disabling a `MonoBehaviour` stops its coroutines, or that reactivating a `GameObject` resumes a stopped coroutine, contradicts Unity's lifecycle rules.
  Source: [Unity coroutines](https://codewiki.com/gamedev/unity-coroutines/)
- Do not treat `WaitForSeconds(1f)` as an exact one-second timer; doing so makes tests compare against idealized time.
  Source: [Unity coroutines](https://codewiki.com/gamedev/unity-coroutines/)
- Code starts with `StartCoroutine(MyRoutine())`, then calls `MyRoutine()` again and passes that new iterator to `StopCoroutine`.
  Source: [Unity coroutines](https://codewiki.com/gamedev/unity-coroutines/)
- Claiming code is faster just because it uses ECS, a job, or `[BurstCompile]` builds an architecture decision on an unmeasured assumption.
  Source: [Unity DOTS](https://codewiki.com/gamedev/unity-dots/)
- Adding or removing components during query iteration can invalidate the view being traversed, while toggling components every frame repeatedly moves entities between archetypes.
  Source: [Unity DOTS](https://codewiki.com/gamedev/unity-dots/)
- Do not assume this is safe: scheduling a job without passing `state.Dependency` or without storing the returned handle loses ordering against other component readers and writers.
  Source: [Unity DOTS](https://codewiki.com/gamedev/unity-dots/)
- A Burst job captures a `string`, managed array, `GameObject`, or ordinary `List`, so it can't enter the expected Burst compilation path.
  Source: [Unity DOTS](https://codewiki.com/gamedev/unity-dots/)
- Do not treat an ECB like an immediate `EntityManager` reads entities or components that don't exist until playback, and the wrong playback point; doing so can add a frame of latency.
  Source: [Unity DOTS](https://codewiki.com/gamedev/unity-dots/)
- Generated code mixes old tutorial APIs such as `Translation`, `ConvertToEntity`, or `Entities.ForEach` with Entities 1.4 APIs such as `LocalTransform`, Bakers, and `SystemAPI`.
  Source: [Unity DOTS](https://codewiki.com/gamedev/unity-dots/)
- Calling `GameObject.Find`, `FindFirstObjectByType`, or hierarchy searches repeatedly in `Update` turns object wiring into a global query every frame.
  Why: Renaming and activation state can also affect correctness.
  Source: [Unity fundamentals](https://codewiki.com/gamedev/unity-fundamentals/)
- Making every field `public` for Inspector visibility turns an editing requirement into permission for any code to mutate the state.
  Source: [Unity fundamentals](https://codewiki.com/gamedev/unity-fundamentals/)
- Do not assume `GetComponent()` always succeeds means one missing Prefab component produces a `NullReferenceException` somewhere less useful.
  Source: [Unity fundamentals](https://codewiki.com/gamedev/unity-fundamentals/)
- Do not assume this is safe: implementing "units per second" as `transform.position += velocity` without a time increment makes speed depend on frame rate.
  Why: Direct Transform writes can also fight the physics simulation on a Rigidbody object.
  Source: [Unity fundamentals](https://codewiki.com/gamedev/unity-fundamentals/)
- Do not treat `activeSelf` as the object's final scene state produces `true` even when an inactive parent suppresses it.
  Source: [Unity fundamentals](https://codewiki.com/gamedev/unity-fundamentals/)
- Do not treat a Prefab instance override as an asset default, or tuning an object in Play mode and immediately stopping, leaves the change at the wrong layer or loses it entirely.
  Source: [Unity fundamentals](https://codewiki.com/gamedev/unity-fundamentals/)
- Putting `currentHealth`, current level, or cooldown state in an asset makes every consumer share it.
  Why: A one-instance test can pass, with cross-talk appearing only after a second consumer exists.
  Source: [Unity ScriptableObject assets](https://codewiki.com/gamedev/unity-scriptableobjects/)
- Constructing a ScriptableObject with `new WeaponDefinition()` bypasses Unity's object creation path.
  Why: Generated code often treats it as an ordinary C# DTO and then produces invalid object behavior or an engine diagnostic.
  Source: [Unity ScriptableObject assets](https://codewiki.com/gamedev/unity-scriptableobjects/)
- Calling `UnityEditor.AssetDatabase` from Player runtime code introduces an editor-only API into the build.
  Why: A path that works in Editor Play mode does not prove that the Player can compile it or write an asset.
  Source: [Unity ScriptableObject assets](https://codewiki.com/gamedev/unity-scriptableobjects/)
- Do not assume that leaving Play mode reliably undoes every asset write; doing so makes tests depend on editor reload settings.
  Why: New Unity 6.6 projects do not reload the script domain by default, so caches and callbacks especially cannot rely on old lifecycle habits.
  Source: [Unity ScriptableObject assets](https://codewiki.com/gamedev/unity-scriptableobjects/)
- Changing a C# field initializer can leave existing `.asset` files with their old serialized value.
  Why: A code review that sees only the new default can wrongly conclude that all content has changed.
  Source: [Unity ScriptableObject assets](https://codewiki.com/gamedev/unity-scriptableobjects/)
- Repeating an old tutorial's claim that Unity cannot serialize dictionaries creates redundant parallel lists and synchronization code in a 6.6 project.
  Why: The opposite claim, that any nested collection now works, is also wrong.
  Source: [Unity ScriptableObject assets](https://codewiki.com/gamedev/unity-scriptableobjects/)
