unity-performance
from cryptorabea/claude_unity_dev_plugin
No description
npx skills add https://github.com/cryptorabea/claude_unity_dev_plugin --skill unity-performanceSKILL.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
...