unity-csharp

Version: 2.0 Stack: Unity, C#

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "unity-csharp" with this command: npx skills add alexanderstephenthompson/claude-hub/alexanderstephenthompson-claude-hub-unity-csharp

Unity C# Skill

Version: 2.0 Stack: Unity, C#

Patterns for writing clean, performant Unity C# code. Includes VR/mobile optimization.

Scope and Boundaries

This skill covers:

  • MonoBehaviour lifecycle and component architecture

  • Unity-specific C# patterns (caching, events, coroutines, null safety)

  • Performance optimization (draw calls, batching, LODs, pooling)

  • VR/mobile performance targets and profiling

  • ScriptableObject usage

Defers to other skills:

  • vrc-udon : VRChat-specific scripting (UdonSharp)

  • vrc-worlds : VRChat world setup and limits

  • vrc-avatars : VRChat avatar setup and limits

Use this skill when: Writing C# scripts for Unity, or optimizing Unity performance for VR/mobile.

Core Principles

  • Composition Over Inheritance — Small, focused components.

  • Avoid Update() When Possible — Event-driven or coroutines instead.

  • Cache References — GetComponent is expensive; cache in Awake.

  • ScriptableObjects for Data — Decouple data from behavior.

  • Null-Safe Access — Unity objects can be destroyed at any time.

  • Measure First — Profile before optimizing; gut feelings lie.

  • Batch Aggressively — Same material = potential batch. Draw calls matter most in VR.

Patterns

Reference Caching

public class PlayerController : MonoBehaviour { private Rigidbody _rb; private Animator _animator;

[SerializeField] private Transform _cameraTarget;

private void Awake()
{
    _rb = GetComponent<Rigidbody>();
    _animator = GetComponent<Animator>();
}

private void FixedUpdate()
{
    _rb.AddForce(Vector3.up);
}

}

Event System (ScriptableObject)

[CreateAssetMenu(menuName = "Events/Game Event")] public class GameEvent : ScriptableObject { private readonly List<GameEventListener> _listeners = new();

public void Raise()
{
    for (int i = _listeners.Count - 1; i >= 0; i--)
        _listeners[i].OnEventRaised();
}

public void RegisterListener(GameEventListener listener) =>
    _listeners.Add(listener);

public void UnregisterListener(GameEventListener listener) =>
    _listeners.Remove(listener);

}

public class GameEventListener : MonoBehaviour { [SerializeField] private GameEvent _event; [SerializeField] private UnityEvent _response;

private void OnEnable() => _event.RegisterListener(this);
private void OnDisable() => _event.UnregisterListener(this);
public void OnEventRaised() => _response.Invoke();

}

Null-Safe Pattern

// Unity overloads == for destroyed objects if (_target != null) { _target.DoSomething(); }

// Best: explicit destroyed check if (_target != null && !_target.Equals(null)) { _target.DoSomething(); }

Coroutine Pattern

private IEnumerator FadeOut(float duration) { float elapsed = 0f; Color startColor = _renderer.material.color;

while (elapsed &#x3C; duration)
{
    elapsed += Time.deltaTime;
    float t = elapsed / duration;
    _renderer.material.color = Color.Lerp(startColor, Color.clear, t);
    yield return null;
}

gameObject.SetActive(false);

}

Object Pooling

public class ObjectPool : MonoBehaviour { [SerializeField] private GameObject _prefab; [SerializeField] private int _initialSize = 10;

private Queue&#x3C;GameObject> _pool = new();

private void Awake()
{
    for (int i = 0; i &#x3C; _initialSize; i++)
    {
        var obj = Instantiate(_prefab);
        obj.SetActive(false);
        _pool.Enqueue(obj);
    }
}

public GameObject Get()
{
    if (_pool.Count == 0)
        return Instantiate(_prefab);

    var pooled = _pool.Dequeue();
    pooled.SetActive(true);
    return pooled;
}

public void Return(GameObject obj)
{
    obj.SetActive(false);
    _pool.Enqueue(obj);
}

}

Static Batching

gameObject.isStatic = true;

// Or specific flags GameObjectUtility.SetStaticEditorFlags(gameObject, StaticEditorFlags.BatchingStatic | StaticEditorFlags.OcclusionStatic);

VR Performance Targets

Metric Quest 2 Quest 3 PC VR

Draw Calls <100 <150 <200

Triangles <100K <150K <1M

Frame Time <14ms (72fps) <11ms (90fps) <11ms (90fps)

Texture Memory <200MB <500MB <1GB

LOD Configuration

LOD 0: 100% triangles (0-10m) LOD 1: 50% triangles (10-25m) LOD 2: 25% triangles (25-50m) Culled: 0 triangles (50m+)

Material Atlasing

Before: 20 objects x 20 materials = 20 draw calls (no batching) After: 20 objects x 1 atlas material = 1 draw call (batched)

Anti-Patterns

Anti-Pattern Problem Fix

GetComponent in Update Expensive every frame Cache in Awake

Find or FindObjectOfType

Slow, fragile Inject references or use events

Heavy Update loops Performance drain Use events, coroutines, or FixedUpdate

String comparisons for tags Typo-prone, slow Use CompareTag or constants

Public fields for everything No encapsulation Use [SerializeField] private

Unique material per object No batching possible Share materials, use atlases

No LODs Full detail at any distance Add LOD groups

Instantiate/Destroy in gameplay GC spikes, stutters Object pooling

Realtime lights everywhere Expensive shadows Bake lighting, limit realtime

No occlusion culling Render hidden objects Bake occlusion data

Checklist

Code Quality

  • References cached in Awake

  • No GetComponent in Update/FixedUpdate

  • No Find methods in runtime code

  • ScriptableObjects for shared data

  • Events for decoupled communication

  • Null checks for destroyable objects

Performance

  • Static objects marked static

  • Materials shared where possible

  • Texture atlases for small props

  • LOD groups on significant meshes

  • Occlusion culling baked

  • Object pooling for spawned objects

  • Lighting baked (not all realtime)

Profiling

  • Frame Debugger checked for draw calls

  • Profiler run for CPU spikes

  • Memory Profiler checked for leaks

  • Tested on target device (not just editor)

References

  • references/lifecycle.md — MonoBehaviour lifecycle and execution order

  • references/profiling.md — Unity Profiler usage and interpretation

Assets

  • assets/component-checklist.md — Unity component design checklist

  • assets/vr-performance-limits.md — VR platform performance limits and targets

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.