| name | unity-game-dev |
| description | Unity game development expert: C# scripting patterns, component architecture, physics systems, character controllers, input handling, and multiplayer networking. Use for Unity projects of any genre. |
| license | MIT |
| metadata | {"author":"generated","version":"0.2.0","generated":"2026-03-17","instrumented":"2026-03-21","sources":["Unity Documentation (general patterns)","Game Programming Patterns (Robert Nystrom)"]} |
| allowed-tools | Read Grep Glob Write Edit |
| context | fork |
| domain | {"file_patterns":["*.cs"],"keywords":["MonoBehaviour","NetworkBehaviour","GameObject","Component","SerializeField","ScriptableObject"],"watch_for":[{"pattern":"GetComponent<*> in Awake|Start","category":"component-caching","type":"exemplar"},{"pattern":"GetComponent<*> in Update|FixedUpdate|LateUpdate","category":"component-caching","type":"anti-pattern"},{"pattern":"ObjectPool|Pool<","category":"pooling","type":"exemplar"},{"pattern":"Instantiate\\(.*\\) in Update|FixedUpdate","category":"pooling","type":"anti-pattern"},{"pattern":"ScriptableObject.*CreateAssetMenu","category":"data-architecture","type":"exemplar"},{"pattern":"\\[RequireComponent","category":"component-dependencies","type":"exemplar"},{"pattern":"Find\\(|FindObjectOfType","category":"object-references","type":"anti-pattern"},{"pattern":"NetworkVariable|ServerRpc|ClientRpc","category":"networking","type":"exemplar"},{"pattern":"private.*=>.*GetComponent","category":"component-caching","type":"exemplar"}]} |
| principles_locked | true |
Unity Game Development
Expert guidance for Unity projects: C# scripting, component architecture, physics, input handling, character controllers, and multiplayer networking.
When to Use
- Building Unity game projects (any genre)
- Writing C# scripts for MonoBehaviours
- Designing character controllers or physics systems
- Implementing multiplayer/networking
- Optimizing game performance
- Structuring game code architecture
When NOT to Use
- Non-Unity engines (Unreal, Godot, custom)
- Pure web/backend development
- ML training or data science
Principles
- No Hot Path Allocations: Avoid
new, Instantiate, GetComponent, Find in Update/FixedUpdate/LateUpdate
- Cache Expensive Operations: GetComponent, Find, Resources.Load should happen in Awake/Start, not per-frame
- Single Responsibility: Each MonoBehaviour does one thing. Compose, don't inherit.
- Server Authority: In multiplayer, server owns game state. Clients send inputs, server validates.
- Composition Over Inheritance: Use component composition, not deep class hierarchies.
- Physics in FixedUpdate: Rigidbody operations in FixedUpdate only. Input in Update.
- Data-Driven Design: Use ScriptableObjects for shared configuration data.
Techniques
Component Architecture
Use ScriptableObjects for data:
[CreateAssetMenu(fileName = "WeaponData", menuName = "Game/Weapon")]
public class WeaponData : ScriptableObject
{
public string weaponName;
public float damage;
public float attackSpeed;
public GameObject prefab;
}
Keep MonoBehaviours focused (single responsibility):
public class Health : MonoBehaviour
{
[SerializeField] private float maxHealth = 100f;
private float currentHealth;
public event Action<float> OnDamaged;
public event Action OnDied;
public void TakeDamage(float amount)
{
currentHealth -= amount;
OnDamaged?.Invoke(currentHealth / maxHealth);
if (currentHealth <= 0) OnDied?.Invoke();
}
}
Use composition over inheritance:
Component Caching
Cache GetComponent calls in Awake:
[RequireComponent(typeof(Rigidbody))]
public class HorseController : MonoBehaviour
{
private Rigidbody rb;
void Awake() => rb = GetComponent<Rigidbody>();
void FixedUpdate()
{
rb.MovePosition(rb.position + direction * Time.fixedDeltaTime);
}
}
Detection patterns for learning:
- ✅ GOOD:
GetComponent<T>() in Awake/Start with field assignment
- ❌ BAD:
GetComponent<T>() inside Update/FixedUpdate/LateUpdate
Object Lifecycle
Use pooling for frequently instantiated objects:
var bullet = bulletPool.Get();
bulletPool.Release(bullet);
Detection patterns for learning:
- ✅ GOOD:
Pool.Get() / Pool.Release() pattern
- ❌ BAD:
Instantiate() in Update or frequently-called methods
Character Controllers
For physics-based movement (rigidbody):
[RequireComponent(typeof(Rigidbody))]
public class HorseController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 10f;
[SerializeField] private float turnSpeed = 100f;
private Rigidbody rb;
private Vector2 inputDirection;
void Awake() => rb = GetComponent<Rigidbody>();
void Update()
{
inputDirection = new Vector2(
Input.GetAxis("Horizontal"),
Input.GetAxis("Vertical")
);
}
void FixedUpdate()
{
Vector3 move = transform.forward * inputDirection.y * moveSpeed;
rb.MovePosition(rb.position + move * Time.fixedDeltaTime);
}
}
For precise/arcade movement (CharacterController):
[RequireComponent(typeof(CharacterController))]
public class KnightController : MonoBehaviour
{
private CharacterController controller;
void Start() => controller = GetComponent<CharacterController>();
void Update()
{
Vector3 movement = CalculateMovement();
controller.Move(movement * Time.deltaTime);
}
}
Input System (New Input System)
Input Action asset + component:
public class PlayerInput : MonoBehaviour
{
private PlayerInputActions inputActions;
void Awake()
{
inputActions = new PlayerInputActions();
}
void OnEnable() => inputActions.Player.Enable();
void OnDisable() => inputActions.Player.Disable();
public Vector2 MoveInput => inputActions.Player.Move.ReadValue<Vector2>();
public bool AttackPressed => inputActions.Player.Attack.WasPressedThisFrame();
}
Multiplayer Networking
With Netcode for GameObjects:
public class NetworkedHealth : NetworkBehaviour
{
private NetworkVariable<float> health = new(100f);
[ServerRpc]
public void TakeDamageServerRpc(float amount)
{
health.Value -= amount;
if (health.Value <= 0)
DespawnClientRpc();
}
[ClientRpc]
private void DespawnClientRpc()
{
}
}
Key networking principles:
- Server authoritative: Server owns game state, clients send inputs
- Predict locally, reconcile from server
- Only sync what changes (NetworkVariable, not every frame)
- Use NetworkTransform for movement sync
Combat Systems
Hitbox/Hurtbox approach:
public class Hitbox : MonoBehaviour
{
[SerializeField] private float damage;
[SerializeField] private LayerMask targetLayers;
void OnTriggerEnter(Collider other)
{
if ((targetLayers & (1 << other.gameObject.layer)) != 0)
{
var health = other.GetComponent<Health>();
health?.TakeDamage(damage);
}
}
}
Anti-Patterns
| Anti-Pattern | Violates Principle | Detection |
|---|
GetComponent<T>() in Update | #2 (Cache) | GetComponent in Update|FixedUpdate |
Find() or FindObjectOfType() | #1 (Hot Path), #2 (Cache) | Find( or FindObjectOfType( |
Instantiate() in hot path | #1 (Hot Path) | Instantiate( in Update |
| God object MonoBehaviour | #3 (Single Responsibility) | Class with 500+ lines |
| Client modifying game state | #4 (Server Authority) | Missing [ServerRpc] |
| Physics in Update | #6 (FixedUpdate) | Rigidbody in void Update |
Quality Criteria
Project Learnings
This section is updated automatically as the agent works on your project.
Learnings are validated against Principles before being added.
Sources
- Unity Documentation (MonoBehaviour lifecycle, Netcode for GameObjects)
- Game Programming Patterns by Robert Nystrom
- Standard Unity architecture patterns
Instrumented for continuous learning on 2026-03-21.