Unity C# Agent Rules
Project Context
You are developing a game with Unity (2022 LTS or later) using C#. The project follows component-based architecture, uses ScriptableObjects for data, and targets one or more platforms including PC, mobile, consoles, or WebGL.
Code Style
- Follow Microsoft C# naming conventions: `PascalCase` for public members and types, `_camelCase` for private fields, `camelCase` for local variables.
- Use `[SerializeField]` on private fields instead of making them public for Inspector exposure.
- Add `[Tooltip("Describe what this field controls")]` on all serialized fields for designer documentation.
- Organize `using` directives: Unity namespaces first, then System, then third-party.
- Avoid `GameObject.Find()`, `FindObjectOfType<T>()`, and string-based method calls — use direct references or events.
- Write XML doc comments on all public methods, properties, and classes.
Project Structure
- Organize `Assets/` by feature: `Features/Player/`, `Features/Inventory/`, `Features/Combat/`.
- Store ScriptableObject definitions in `Scripts/Data/` and ScriptableObject instances in `Assets/Data/`.
- Place editor scripts and custom inspectors in `Editor/` subdirectories — Unity excludes these from builds automatically.
- Use Assembly Definition files (`.asmdef`) per feature folder to reduce recompilation scope and enforce module boundaries.
- Keep third-party assets in a `Plugins/` or `ThirdParty/` folder, isolated from project code.
MonoBehaviour Lifecycle
- Use `Awake()` for self-initialization: cache components, set up internal state.
- Use `Start()` for cross-component references that must resolve after all `Awake()` calls complete.
- Perform physics interactions in `FixedUpdate()`; handle input and visual updates in `Update()`.
- Use `LateUpdate()` for camera follow logic and anything that must run after all `Update()` calls.
- Use `OnDisable()` and `OnDestroy()` to unsubscribe from events, stop coroutines, and release resources.
- Remove empty lifecycle methods (`Update`, `Start`, `FixedUpdate`) — Unity calls them even when empty.
Component Architecture
- Prefer composition: many small, single-purpose components on one GameObject over deep inheritance.
- Use ScriptableObjects for configuration data, shared constants, and event channels (event bus pattern).
- Keep MonoBehaviours thin — delegate business logic to plain C# classes that can be unit-tested without Unity.
- Use interfaces (`IDamageable`, `IInteractable`, `IPickupable`) to decouple systems from concrete types.
- Avoid deep `MonoBehaviour` inheritance hierarchies — prefer `interface` composition instead.
Physics & Input
- Use the new Input System package (`UnityEngine.InputSystem`) — avoid the legacy `Input` class.
- Define input actions in an Input Actions asset and generate C# wrapper classes.
- Use `Rigidbody` and `Rigidbody2D` physics instead of directly moving `transform.position` on physics objects.
- Use layer masks in all `Physics.Raycast` and overlap queries — never cast against all layers.
- Use `Physics.RaycastNonAlloc` and `Physics.OverlapSphereNonAlloc` to avoid per-frame GC allocations.
- Configure the collision matrix in Physics Settings to minimize unnecessary collision pair checks.
Performance
- Profile on target hardware with the Unity Profiler — editor performance does not represent device performance.
- Implement object pooling for frequently spawned/destroyed objects: bullets, particles, hit effects.
- Avoid allocations in `Update()`: no `new`, LINQ queries, string concatenation, or boxing in hot paths.
- Cache all `GetComponent<T>()` calls in `Awake()` — never call it in `Update()`.
- Use LOD Groups for complex 3D assets and configure occlusion culling for large scenes.
- Use the Burst Compiler and Jobs System for CPU-intensive computation that can run off the main thread.
- Minimize Canvas rebuilds: separate frequently updated UI elements onto their own Canvas component.
ScriptableObject Patterns
- Use ScriptableObjects for game configuration: enemy stats, weapon data, level progression tables.
- Use ScriptableObject event channels for decoupled communication: `GameEvent`, `GameEventListener`.
- Create ScriptableObject-based state machines for simple AI without MonoBehaviour overhead.
- Mark configuration ScriptableObjects `[CreateAssetMenu]` for easy creation from the Project window.
Testing
- Write Edit Mode tests for pure C# logic that does not require the MonoBehaviour lifecycle.
- Write Play Mode tests for integration testing of GameObjects, physics simulation, and coroutines.
- Use Unity Test Framework with NUnit; assert with `Assert.AreEqual`, `Assert.IsNotNull`, `Assert.That`.
- Run tests in batch mode in CI: `unity -batchmode -runTests -testPlatform editmode -logFile test.log`.
Build & Deployment
- Use scripted builds via `BuildPipeline.BuildPlayer` or Unity Build Automation for reproducible builds.
- Use preprocessor directives (`#if UNITY_EDITOR`, `#if UNITY_IOS`) sparingly — abstract platform differences behind interfaces.
- Strip unused engine code with Managed Stripping Level set to `Medium` or `High` for release builds.
- Test on actual target devices before each milestone — emulators and the editor hide real performance issues.