Agent Skills: Unity C# Scripting Patterns

|

UncategorizedID: josiahsiegel/claude-plugin-marketplace/unity-csharp-scripting

Install this agent skill to your local

pnpm dlx add-skill https://github.com/JosiahSiegel/claude-plugin-marketplace/tree/HEAD/plugins/unity-master/skills/unity-csharp-scripting

Skill Files

Browse the full folder contents for unity-csharp-scripting.

Download Skill

Loading file tree…

plugins/unity-master/skills/unity-csharp-scripting/SKILL.md

Skill Metadata

Name
unity-csharp-scripting
Description
|

Unity C# Scripting Patterns

Overview

Core C# scripting reference for Unity development. Covers MonoBehaviour lifecycle, physics and collision APIs, animation scripting, audio, navigation, common design patterns, serialization, and ECS/DOTS coding patterns.

MonoBehaviour Lifecycle

Execution Order

Awake() -> OnEnable() -> Start() -> FixedUpdate() -> Update() -> LateUpdate() -> OnDisable() -> OnDestroy()

| Method | When Called | Use For | |--------|-----------|---------| | Awake() | Once, when object instantiates (before Start) | Self-initialization, caching references | | OnEnable() | Each time object becomes active | Subscribe to events, reset state | | Start() | Once, before first Update (after all Awake) | Cross-object initialization | | FixedUpdate() | Fixed timestep (default 0.02s) | Physics, Rigidbody movement | | Update() | Every frame | Input, non-physics logic | | LateUpdate() | After all Update calls | Camera follow, post-movement adjustments | | OnDisable() | When object deactivates | Unsubscribe events, save state | | OnDestroy() | When object is destroyed | Final cleanup, resource release |

Key Rules

  • Awake runs even on disabled components (but not disabled GameObjects)
  • Never rely on Awake/Start order between scripts -- use [DefaultExecutionOrder(N)] or Script Execution Order settings
  • Use OnValidate() for editor-time validation of serialized fields

Coroutines and Async

Coroutines

IEnumerator SpawnWaves(int count, float delay)
{
    for (int i = 0; i < count; i++)
    {
        SpawnEnemy();
        yield return new WaitForSeconds(delay);
    }
}
// Start: Coroutine handle = StartCoroutine(SpawnWaves(5, 1f));
// Stop: StopCoroutine(handle); or StopAllCoroutines();

| Yield Instruction | Behavior | |-------------------|----------| | yield return null | Wait one frame | | yield return new WaitForSeconds(t) | Wait t seconds (affected by timeScale) | | yield return new WaitForSecondsRealtime(t) | Unscaled time | | yield return new WaitForFixedUpdate() | Wait for next FixedUpdate | | yield return new WaitForEndOfFrame() | After rendering | | yield return new WaitUntil(() => condition) | Wait until predicate is true | | yield return StartCoroutine(other) | Wait for nested coroutine |

Async/Await (Unity 6+ / UniTask)

For Unity 2023+/Unity 6, Awaitable is built-in. For older versions, use UniTask.

async Awaitable LoadLevelAsync(string sceneName)
{
    await Awaitable.WaitForSecondsAsync(1f);
    var op = SceneManager.LoadSceneAsync(sceneName);
    while (!op.isDone)
    {
        progressBar.value = op.progress;
        await Awaitable.NextFrameAsync();
    }
}

Events and Delegates

Event Pattern (Recommended)

// Publisher
public class Health : MonoBehaviour
{
    public event System.Action<float> OnDamaged;  // event keyword prevents external invocation
    public event System.Action OnDeath;

    public void TakeDamage(float amount)
    {
        currentHealth -= amount;
        OnDamaged?.Invoke(amount);
        if (currentHealth <= 0) OnDeath?.Invoke();
    }
}

// Subscriber
void OnEnable() => health.OnDamaged += HandleDamage;
void OnDisable() => health.OnDamaged -= HandleDamage;
void HandleDamage(float amount) => /* react */;

ScriptableObject Event Channels

Decouple systems without direct references. Create GameEvent as a ScriptableObject asset, invoke from publishers, and listen from subscribers via GameEventListener MonoBehaviours. See references/design-patterns.md for full implementation.

Physics API Quick Reference

Rigidbody Movement (3D)

| Task | Method | Where | |------|--------|-------| | Continuous force | rb.AddForce(dir * force) | FixedUpdate | | Instant impulse | rb.AddForce(dir * force, ForceMode.Impulse) | FixedUpdate | | Direct velocity | rb.linearVelocity = dir * speed | FixedUpdate | | Kinematic move | rb.MovePosition(target) | FixedUpdate | | Rotation | rb.MoveRotation(targetRot) | FixedUpdate |

Note: In Unity 6, Rigidbody.velocity is renamed to Rigidbody.linearVelocity.

Raycasting

if (Physics.Raycast(origin, direction, out RaycastHit hit, maxDistance, layerMask))
{
    Debug.Log($"Hit {hit.collider.name} at {hit.point}");
}
// Use Physics.RaycastAll or Physics.RaycastNonAlloc for multiple hits
// 2D: Physics2D.Raycast, Physics2D.OverlapCircle, etc.

Collision vs Trigger

| Callback | Requires | Use For | |----------|----------|---------| | OnCollisionEnter/Stay/Exit | Both have colliders, at least one Rigidbody, isTrigger=false | Physical impacts | | OnTriggerEnter/Stay/Exit | One collider has isTrigger=true, at least one Rigidbody | Zones, pickups, detection |

Always use CompareTag("Enemy") instead of other.tag == "Enemy" (avoids GC allocation).

Animation Scripting

[RequireComponent(typeof(Animator))]
public class CharacterAnimation : MonoBehaviour
{
    static readonly int SpeedHash = Animator.StringToHash("Speed");
    static readonly int JumpTrigger = Animator.StringToHash("Jump");
    Animator _anim;

    void Awake() => _anim = GetComponent<Animator>();
    void Update()
    {
        _anim.SetFloat(SpeedHash, moveSpeed);
        if (jumped) _anim.SetTrigger(JumpTrigger);
    }
}

Cache Animator.StringToHash results as static readonly fields to avoid per-frame hashing. Use Animation Events for gameplay-timed callbacks (footsteps, hit frames). For IK, implement OnAnimatorIK(int layerIndex) with SetIKPosition/Rotation/Weight.

Audio Quick Reference

[RequireComponent(typeof(AudioSource))]
public class SFXPlayer : MonoBehaviour
{
    [SerializeField] AudioClip[] clips;
    AudioSource _source;
    void Awake() => _source = GetComponent<AudioSource>();
    public void PlayRandom() => _source.PlayOneShot(clips[Random.Range(0, clips.Length)]);
}

Use AudioSource.PlayOneShot() for overlapping SFX. Use AudioMixer with exposed parameters for volume control. Use snapshots for state transitions (combat vs. exploration).

Serialization

| Type | Serialized | Notes | |------|-----------|-------| | public fields | Yes | Visible in Inspector | | [SerializeField] private | Yes | Preferred -- maintains encapsulation | | [HideInInspector] public | Yes, hidden | Serialized but not shown | | [NonSerialized] public | No | Opt-out of serialization | | Properties | No | Never serialized by Unity | | Dictionaries | No | Use serialized list + rebuild, or Odin/SerializedDictionary | | Interfaces | No | Use abstract ScriptableObject or SerializeReference |

Use [SerializeReference] for polymorphic serialization of interfaces and abstract types.

Common Design Patterns

| Pattern | When to Use | Approach | |---------|------------|----------| | Singleton | Global managers (Audio, GameState) | ScriptableObject-based or lazy MonoBehaviour | | Observer | Decoupled communication | C# events or SO event channels | | Command | Input/undo systems | Command interface + history stack | | State Machine | AI, player states | Enum + switch, or class-based states | | Object Pool | Bullets, particles, enemies | Queue<T> with pre-instantiation | | Service Locator | Testable global access | Static registry with interface keys |

For detailed implementations and code examples, see references/design-patterns.md.

ECS/DOTS Quick Reference

| Concept | Role | |---------|------| | Entity | Lightweight ID (no MonoBehaviour) | | IComponentData | Pure data struct on entities | | SystemBase / ISystem | Logic operating on component queries | | EntityQuery | Filter entities by component sets | | Jobs (IJobEntity) | Multithreaded systems | | Burst Compiler | SIMD-optimized native code |

For ECS architecture patterns and migration guidance, see references/design-patterns.md.

Additional Resources

Reference Files

  • references/design-patterns.md -- Full implementations of singleton, observer, command, state machine, object pool, service locator, and ECS patterns
  • references/physics-animation-audio.md -- Detailed physics setup (2D and 3D), advanced animation (blend trees, IK, root motion, Animation Rigging), and audio architecture