plugins/unity-master/skills/unity-csharp-scripting/SKILL.md
C# scripting in Unity for gameplay, behavior, and engine integration. PROACTIVELY activate for: (1) writing Unity C# scripts, (2) MonoBehaviour lifecycle (Awake/OnEnable/Start/Update/FixedUpdate/LateUpdate), (3) coroutines and async/await in Unity, (4) delegates, events, Action/Func patterns, (5) ScriptableObject creation and serialization, (6) GetComponent / TryGetComponent and component caching, (7) physics scripting (Rigidbody, raycast, collision/trigger callbacks), (8) animation scripting (Animator parameters, state machines, IK), (9) NavMesh and NavMeshAgent scripting, (10) input handling (Input System package), (11) custom serialization and SerializeField. Provides: lifecycle reference, coroutine vs async patterns, ScriptableObject templates, Rigidbody/collision recipes, NavMesh examples, and Input System setup.
npx skillsauth add JosiahSiegel/claude-plugin-marketplace unity-csharp-scriptingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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.
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 |
[DefaultExecutionOrder(N)] or Script Execution Order settingsOnValidate() for editor-time validation of serialized fieldsIEnumerator 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 |
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();
}
}
// 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 */;
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.
| 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.
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.
| 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).
[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.
[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).
| 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.
| 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.
| 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.
references/design-patterns.md -- Full implementations of singleton, observer, command, state machine, object pool, service locator, and ECS patternsreferences/physics-animation-audio.md -- Detailed physics setup (2D and 3D), advanced animation (blend trees, IK, root motion, Animation Rigging), and audio architecturedevelopment
Use for Clerk sessions, tokens, webhooks, orgs, and security. PROACTIVELY activate for session tokens, JWT templates, getToken(), custom claims, pending sessions, multi-session UX, organizations, roles, permissions, system vs custom permissions, features/plans, MFA/passkeys/password policy/bot protection, Clerk webhooks, Svix signatures, verifyWebhook(), user/org sync, retries/replays, environment variables, custom domains, secret rotation, logs, and auth security reviews. Provides token semantics, webhook idempotency, authorization defaults, and hardening checklist.
tools
Use for Clerk in Next.js. PROACTIVELY activate for @clerk/nextjs setup, App Router auth()/currentUser(), clerkMiddleware(), proxy.ts/middleware.ts, createRouteMatcher(), protected pages/layouts/Route Handlers/Server Actions/API routes/tRPC, auth.protect() role/permission/token checks, ClerkProvider placement, server-only clerkClient, Link prefetch, redirects, 401/404 auth failures, custom domains, __clerk proxy paths, and deployment gotchas. Provides file patterns, server/client boundary rules, matcher templates, and production checks.
development
Use for Clerk frontend auth flows. PROACTIVELY activate for React, JavaScript, Vue, Nuxt, Astro, Expo, React Router, TanStack React Start, or SPA setup; ClerkProvider and publishable-key wiring; SignIn/SignUp/UserButton/UserProfile/OrganizationSwitcher; custom useUser/useAuth/useClerk/useSignIn/useSignUp/useSession/useOrganization flows; multi-session UX; cross-origin getToken() fetches; loading states, redirects, routing, CORS/cookies, or hydration bugs. Provides SDK selection, UI patterns, token-fetch templates, and frontend gotchas.
development
Use for Clerk dev/prod readiness, deployment, and multi-language implementation planning. PROACTIVELY activate for environment variables, pk_test/sk_test vs pk_live/sk_live, local dev, preview/staging/prod instances, domains/DNS, redirects, OAuth credentials, custom domains/proxy, authorizedParties, CSP, CORS/cookies, webhooks/tunnels, Vercel/Netlify/Cloudflare/API gateways, monitoring/troubleshooting, and backends in Node/Express/Fastify, Python/FastAPI/Django/Flask, Go, Ruby/Rails, Java/Spring, .NET, PHP/Laravel. Provides checklists, rollout plans, and language-portable patterns.