unity-performance

from cryptorabea/claude_unity_dev_plugin

No description

0 stars0 forksUpdated Dec 30, 2025
npx skills add https://github.com/cryptorabea/claude_unity_dev_plugin --skill unity-performance

SKILL.md

Unity Performance Optimization

Essential performance optimization techniques for Unity games, covering memory management, CPU optimization, rendering, and profiling strategies.

Overview

Performance is critical for Unity games across all platforms. Poor performance manifests as low framerates, stuttering, long load times, and crashes. This skill covers proven optimization techniques that apply to all Unity projects.

Core optimization areas:

  • CPU optimization (Update loops, caching, pooling)
  • Memory management (GC reduction, allocation patterns)
  • Rendering optimization (batching, culling, LOD)
  • Profiling and measurement (identifying bottlenecks)

Reference Caching

The most common Unity performance mistake is repeated expensive lookups. Cache all references to avoid redundant operations.

GetComponent Caching

Never call GetComponent repeatedly - cache results in Awake:

// ❌ BAD - GetComponent every frame
private void Update()
{
    GetComponent<Rigidbody>().velocity = Vector3.forward;  // SLOW!
}

// ✅ GOOD - Cache once
private Rigidbody rb;

private void Awake()
{
    rb = GetComponent<Rigidbody>();
}

private void Update()
{
    rb.velocity = Vector3.forward;  // FAST
}

Performance impact: GetComponent is 10-100x slower than cached reference.

Transform Caching

Cache transform access, especially for frequently accessed GameObjects:

// ❌ BAD - Property access overhead
private void Update()
{
    transform.position += Vector3.forward * Time.deltaTime;
    transform.rotation = Quaternion.identity;
}

// ✅ GOOD - Cache transform reference
private Transform myTransform;

private void Awake()
{
    myTransform = transform;
}

private void Update()
{
    myTransform.position += Vector3.forward * Time.deltaTime;
    myTransform.rotation = Quaternion.identity;
}

Why: transform property has overhead. Cached reference eliminates repeated lookups.

Find Method Caching

Never use Find methods in Update - cache results:

// ❌ BAD - Find every frame (EXTREMELY SLOW)
private void Update()
{
    GameObject player = GameObject.Find("Player");
    Transform target = GameObject.FindWithTag("Enemy").transform;
}

// ✅ GOOD - Cache in Start
private GameObject player;
private Transform target;

private void Start()
{
    player = GameObject.Find("Player");
    target = GameObject.FindWithTag("Enemy")?.transform;
}

private void Update()
{
    // Use cached references
}

Performance impact: Find methods scan entire scene hierarchy. 100-1000x slower than cached references.

Material Caching

Access renderer.material creates new Material instance - cache to avoid leaks:

// ❌ BAD - Creates new Material every frame (MEMORY LEAK)
private void Update()
{
    GetComponent<Renderer>().material.color = Color.red;  // Creates new Material!
}

// ✅ GOOD - Cache material reference
private Material material;

private void Awake()
{
    material = GetComponent<Renderer>().material;
}

private void Update()
{
    material.color = Color.red;  // Modifies cached Material
}

private void OnDestroy()
{
    // Clean up instantiated material
    if (material != null)
        Destroy(material);
}

Critical: Accessing .material creates new instance. Use .sharedMaterial for read-only access to avoid instantiation.

Object Pooling

Instantiate and Destroy are expensive. Reuse objects instead of creating/destroying repeatedly.

Basic Pool Implementation

public class ObjectPool : MonoBehaviour
{
    [SerializeField] private GameObject prefab;
    [SerializeField] private int initialSize = 10;

    private Queue<GameObject> pool = new Queue<GameObject>();

    private void Awake()
    {
        // Pre-instantiate objects
        for (int i = 0; i < initialSize; i++)
        {
            GameObject obj = Instantiate(prefab);
            obj.SetActive(false);
            pool.Enqueue(obj);
        }
    }

    public GameObject Get()
    {
        if (pool.Count > 0)
        {
            GameObject obj = pool.Dequeue();
            obj.SetActive(true);
            return obj;
        }

        // Pool exhausted - create new
        return Instantiate(prefab);
    }

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

Use for:

  • Bullets, projectiles
  • Particle effects
  • UI elements (tooltips, damage numbers)
  • Enemies in wave-based games
  • Audio sources

Performance gain: 10-50x faster than Instantiate/Destroy, eliminates GC spikes.

Pool Pattern Usage

public class BulletSpawner : MonoBehaviour
{
    [SerializeField] private ObjectPool bulletPool;
    [SerializeField] private Transform firePoint;

    private void Fire()
    {
        // Get from pool
        GameObject bullet = bulletPool.Get();
        bullet.transform.position = firePoint.position;
        bullet.transform.rotation = firePoint.rotation;

        // Return after 3 

...
Read full content

Repository Stats

Stars0
Forks0