unity-csharp-scripting Checked
Installation
Copy the prompt below and send it to your AI assistant (e.g. Claude Code) — it will follow the instructions and install automatically.
Install the "unity-csharp-scripting" skill by following the instructions at https://skill123.me/install/unity-csharp-scripting.
Run in your terminal — downloads and installs to ~/.claude/skills/.
curl -fsSL https://skill123.me/install/unity-csharp-scripting.sh | bash
Download the zip and extract it into your skills directory (e.g. ~/.claude/skills/), then restart your session.
⬇ Download v1.0.0 · 5 KBNot live-tested yet — this skill is rated on static analysis only.
About this skill
Write Unity 6.3 LTS C# gameplay scripts: the MonoBehaviour lifecycle (Awake/OnEnable/Start/Update/FixedUpdate/LateUpdate), GameObject and component access, coroutines, and Inspector serialization. Use when creating or editing .cs scripts in a Unity project, or when the user mentions MonoBehaviour, Start/Update, GetComponent, SerializeField, coroutines, or "Unity script".
Unity C# Scripting (MonoBehaviour)
Write correct, idiomatic gameplay scripts in Unity 6. Get the lifecycle, component
access, serialization, and coroutines right so behaviour is deterministic and the
Inspector stays useful. Targets **Unity 6.3 LTS (6000.3)**, C# / .NET Standard 2.1.
Documentation
Write Unity 6.3 LTS C# gameplay scripts: the MonoBehaviour lifecycle (Awake/OnEnable/Start/Update/FixedUpdate/LateUpdate), GameObject and component access, coroutines, and Inspector serialization. Use when creating or editing .cs scripts in a Unity project, or when the user mentions MonoBehaviour, Start/Update, GetComponent, SerializeField, coroutines, or "Unity script".
Unity C# Scripting (MonoBehaviour)
Write correct, idiomatic gameplay scripts in Unity 6. Get the lifecycle, component
access, serialization, and coroutines right so behaviour is deterministic and the
Inspector stays useful. Targets **Unity 6.3 LTS (6000.3)**, C# / .NET Standard 2.1.
When to use
- Use when authoring or fixing a
MonoBehaviour: choosing the right lifecycle callback,
reading/caching components, exposing fields to the Inspector, or running timed logic
with coroutines.
- Use when the project has
*.csfiles, anAssembly-CSharpor*.asmdef, and a
ProjectSettings/ folder.
**When *not* to use:** moving rigidbodies / collision response → unity-physics; reading
player input → unity-input-system; shared data assets / config → unity-scriptableobjects;
Animator parameters → unity-animation. This skill owns the *script lifecycle and C#
plumbing*, not those subsystems.
Core workflow
1. **Pick the callback by purpose, not habit.** Awake (cache references, runs once on
load), OnEnable (subscribe to events), Start (init that depends on other objects'
Awake), Update (per-frame logic/input polling), FixedUpdate (physics), LateUpdate
(camera follow after movement), OnDisable/OnDestroy (unsubscribe/cleanup).
2. **Cache component lookups in Awake** — never call GetComponent every frame.
3. **Expose tunables with [SerializeField] private**, not public fields, so other code
can't mutate them but designers can edit them in the Inspector.
4. **Scale per-frame values by Time.deltaTime** in Update (and Time.fixedDeltaTime
semantics are automatic in FixedUpdate).
5. **Use coroutines for time-sequenced logic** (delays, tweens, "do X then wait then Y");
start them with StartCoroutine and stop them deterministically.
6. **Verify in Play mode**: check the Console for null-reference exceptions, confirm values
in the Inspector update as expected, and watch the Profiler if Update is hot.
Patterns
### 1. Lifecycle + cached components (the canonical skeleton)
using UnityEngine;
[RequireComponent(typeof(Rigidbody))] // auto-adds the dependency, prevents null refs
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 6f; // editable in Inspector, private in code
private Rigidbody _rb; // cached, not fetched per frame
private void Awake() => _rb = GetComponent<Rigidbody>(); // cache once on load
View full documentation
private void Update()
{
// Per-frame, non-physics work. Scale by deltaTime so it is frame-rate independent.
transform.Rotate(0f, 90f * Time.deltaTime, 0f);
}
private void FixedUpdate()
{
// Physics work belongs here (fixed timestep). See the unity-physics skill.
_rb.MovePosition(_rb.position + transform.forward * moveSpeed * Time.fixedDeltaTime);
}
}
### 2. Safe component access with `TryGetComponent`
// Avoids allocating a null and is clearer than GetComponent + null check.
if (other.TryGetComponent<Health>(out var health))
health.Apply(-10);
### 3. Serialization that shows up correctly in the Inspector
[SerializeField, Range(0f, 1f)] private float volume = 0.8f; // slider
[SerializeField] private string playerName = "Hero"; // private but serialized
[System.Serializable] // REQUIRED for a plain class to serialize/show
public class Stats { public int hp = 100; public int mana = 50; }
[SerializeField] private Stats stats = new(); // nested struct-like data in the Inspector
### 4. Coroutines for time-sequenced logic
private void Start() => StartCoroutine(FlashThenHide());
private System.Collections.IEnumerator FlashThenHide()
{
yield return new WaitForSeconds(0.5f); // wait half a second of game time
GetComponent<Renderer>().enabled = false;
yield return null; // resume next frame
}
## Pitfalls
- **`GetComponent` in `Update`** — it searches every frame and tanks performance. Cache the
reference in `Awake`/`Start`.
- **Physics in `Update`** — moving a `Rigidbody` with forces or `MovePosition` outside
`FixedUpdate` causes jitter and timestep-dependent behaviour. Read input in `Update`,
apply physics in `FixedUpdate`.
- **Relying on `Start` order across objects** — `Start` runs after *all* `Awake`s, but order
among `Start`s is undefined. Do cross-object wiring in `Start`, self-setup in `Awake`.
- **`public` fields just to show them in the Inspector** — that also lets any script mutate
them. Use `[SerializeField] private` instead.
- **`gameObject.tag == "Enemy"`** allocates a string and is slower; use
`gameObject.CompareTag("Enemy")`.
- **Coroutines stop when the GameObject is disabled** — a disabled object's coroutines are
killed; re-`StartCoroutine` in `OnEnable` if it must survive toggling.
- **`Update` never runs before `Start`, but the *first* `Update` can run on the same
frame as `Start`** — guard against not-yet-initialised fields if you split setup oddly.
## References
- For the full event-execution-order table and advanced coroutine patterns (custom
`CustomYieldInstruction`, stopping by handle, `WaitUntil`/`WaitWhile`), read
`references/lifecycle-and-coroutines.md`.
- Primary docs: Unity Manual "Event function execution order"
(`https://docs.unity3d.com/Manual/execution-order.html`) and `ScriptReference/MonoBehaviour`.
## Related skills
- `unity-physics` — `Rigidbody`, collisions, and `FixedUpdate` motion.
- `unity-input-system` — reading player input into these scripts.
- `unity-scriptableobjects` — sharing data/config between scripts without singletons.
Score breakdown
Assessment methodology
Version history
Imported from gamedev-skills/awesome-gamedev-agent-skills@main
