添加 claude code game studios 到项目

This commit is contained in:
panw
2026-05-15 14:52:29 +08:00
parent dff559462d
commit a16fe4bff7
415 changed files with 78609 additions and 0 deletions

View File

@@ -0,0 +1,289 @@
# Unity 6.3 — Animation Module Reference
**Last verified:** 2026-02-13
**Knowledge Gap:** Unity 6 animation improvements, Timeline enhancements
---
## Overview
Unity 6.3 animation systems:
- **Animator Controller (Mecanim)**: State machine-based (RECOMMENDED)
- **Timeline**: Cinematic sequences, cutscenes
- **Animation Rigging**: Procedural runtime animation
- **Legacy Animation**: Deprecated, avoid
---
## Key Changes from 2022 LTS
### Animation Rigging Package (Production-Ready in Unity 6)
```csharp
// Install: Package Manager > Animation Rigging
// Runtime IK, aim constraints, procedural animation
```
### Timeline Improvements
- Better performance
- More track types
- Improved signal system
---
## Animator Controller (Mecanim)
### Basic Setup
```csharp
// Create: Assets > Create > Animator Controller
// Add to GameObject: Add Component > Animator
// Assign Controller: Animator > Controller = YourAnimatorController
```
### State Transitions
```csharp
Animator animator = GetComponent<Animator>();
// ✅ Trigger transition
animator.SetTrigger("Jump");
// ✅ Bool parameter
animator.SetBool("IsRunning", true);
// ✅ Float parameter (blend trees)
animator.SetFloat("Speed", currentSpeed);
// ✅ Integer parameter
animator.SetInteger("WeaponType", 2);
```
### Animation Layers
- **Base Layer**: Default animations (locomotion)
- **Override Layers**: Replace base layer (e.g., weapon swap)
- **Additive Layers**: Add on top of base (e.g., breathing, aim offset)
```csharp
// Set layer weight (0-1)
animator.SetLayerWeight(1, 0.5f); // 50% blend
```
---
## Blend Trees
### 1D Blend Tree (Speed blending)
```csharp
// Idle (Speed = 0) → Walk (Speed = 0.5) → Run (Speed = 1.0)
animator.SetFloat("Speed", moveSpeed);
```
### 2D Blend Tree (Directional movement)
```csharp
// X-axis: Strafe (-1 to 1)
// Y-axis: Forward/Back (-1 to 1)
animator.SetFloat("MoveX", input.x);
animator.SetFloat("MoveY", input.y);
```
---
## Animation Events
### Trigger Events from Animation Clips
```csharp
// Add in Animation window: Right-click timeline > Add Animation Event
// Must have matching method on GameObject:
public void OnFootstep() {
// Play footstep sound
AudioSource.PlayClipAtPoint(footstepClip, transform.position);
}
public void OnAttackHit() {
// Deal damage
DealDamageInFrontOfPlayer();
}
```
---
## Root Motion
### Character Movement via Animation
```csharp
Animator animator = GetComponent<Animator>();
animator.applyRootMotion = true; // Move character based on animation
void OnAnimatorMove() {
// Custom root motion handling
transform.position += animator.deltaPosition;
transform.rotation *= animator.deltaRotation;
}
```
---
## Animation Rigging (Unity 6+)
### IK (Inverse Kinematics)
```csharp
// Install: Package Manager > Animation Rigging
// Add: Rig Builder component + Rig GameObject
// Two Bone IK (Arm/Leg)
// - Add Two Bone IK Constraint
// - Assign Tip (hand/foot), Mid (elbow/knee), Root (shoulder/hip)
// - Set Target (where hand/foot should reach)
// Runtime control:
TwoBoneIKConstraint ikConstraint = rig.GetComponentInChildren<TwoBoneIKConstraint>();
ikConstraint.data.target = targetTransform;
ikConstraint.weight = 1f; // 0-1 blend
```
### Aim Constraint (Look At)
```csharp
// Character looks at target
MultiAimConstraint aimConstraint = rig.GetComponentInChildren<MultiAimConstraint>();
aimConstraint.data.sourceObjects[0] = new WeightedTransform(targetTransform, 1f);
```
---
## Timeline (Cutscenes)
### Basic Timeline Setup
```csharp
// Create: Assets > Create > Timeline
// Add to GameObject: Add Component > Playable Director
// Assign Timeline: Playable Director > Playable = YourTimeline
// Play from script:
PlayableDirector director = GetComponent<PlayableDirector>();
director.Play();
```
### Timeline Tracks
- **Activation Track**: Enable/disable GameObjects
- **Animation Track**: Play animations on Animator
- **Audio Track**: Synchronized audio playback
- **Cinemachine Track**: Camera movement
- **Signal Track**: Trigger events at specific times
### Signal System (Events)
```csharp
// Create Signal Asset: Assets > Create > Signals > Signal
// Add Signal Emitter to Timeline track
// Add Signal Receiver component to GameObject
public class CutsceneEvents : MonoBehaviour {
public void OnDialogueStart() {
// Triggered by signal
}
}
```
---
## Animation Playback Control
### Play Animation Directly (No State Machine)
```csharp
// ✅ CrossFade (smooth transition)
animator.CrossFade("Attack", 0.2f); // 0.2s transition
// ✅ Play (instant)
animator.Play("Idle");
// ❌ Avoid: Legacy Animation component
Animation anim = GetComponent<Animation>(); // DEPRECATED
```
---
## Animation Curves
### Custom Property Animation
```csharp
// In Animation window: Add Property > Custom Component > Your Script > Your Float
public class WeaponTrail : MonoBehaviour {
public float trailIntensity; // Animated by clip
void Update() {
// Intensity controlled by animation curve
trailRenderer.startWidth = trailIntensity;
}
}
```
---
## Performance Optimization
### Culling
- `Animator > Culling Mode`:
- **Always Animate**: Always update (expensive)
- **Cull Update Transforms**: Stop updating bones when off-screen (RECOMMENDED)
- **Cull Completely**: Stop all animation when off-screen
### LOD (Level of Detail)
- Simpler animations for distant characters
- Reduce skeleton bone count for LOD meshes
---
## Common Patterns
### Check if Animation Finished
```csharp
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
if (stateInfo.IsName("Attack") && stateInfo.normalizedTime >= 1.0f) {
// Attack animation finished
}
```
### Override Animation Speed
```csharp
animator.speed = 1.5f; // 150% speed
```
### Get Current Animation Name
```csharp
AnimatorClipInfo[] clipInfo = animator.GetCurrentAnimatorClipInfo(0);
string currentClip = clipInfo[0].clip.name;
```
---
## Debugging
### Animator Window
- `Window > Animation > Animator`
- Visualize state machine, see active state
### Animation Window
- `Window > Animation > Animation`
- Edit animation clips, add events
---
## Sources
- https://docs.unity3d.com/6000.0/Documentation/Manual/AnimationOverview.html
- https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/index.html
- https://docs.unity3d.com/Packages/com.unity.timeline@1.8/manual/index.html

View File

@@ -0,0 +1,284 @@
# Unity 6.3 — Audio Module Reference
**Last verified:** 2026-02-13
**Knowledge Gap:** Unity 6 audio mixer improvements
---
## Overview
Unity 6.3 audio systems:
- **AudioSource**: Play sounds on GameObjects
- **Audio Mixer**: Mix, effect processing, dynamic mixing
- **Spatial Audio**: 3D positioned sound
---
## Basic Audio Playback
### AudioSource Component
```csharp
AudioSource audioSource = GetComponent<AudioSource>();
// ✅ Play
audioSource.Play();
// ✅ Play with delay
audioSource.PlayDelayed(0.5f); // 0.5 seconds
// ✅ Play one-shot (doesn't interrupt current sound)
audioSource.PlayOneShot(clip);
// ✅ Stop
audioSource.Stop();
// ✅ Pause/Resume
audioSource.Pause();
audioSource.UnPause();
```
### Play Sound at Position (Static Method)
```csharp
// ✅ Quick 3D sound playback (auto-destroys when done)
AudioSource.PlayClipAtPoint(clip, transform.position);
// ✅ With volume
AudioSource.PlayClipAtPoint(clip, transform.position, 0.7f);
```
---
## 3D Spatial Audio
### AudioSource 3D Settings
```csharp
AudioSource source = GetComponent<AudioSource>();
// Spatial Blend: 0 = 2D, 1 = 3D
source.spatialBlend = 1.0f; // Fully 3D
// Doppler effect (pitch shift based on velocity)
source.dopplerLevel = 1.0f;
// Distance attenuation
source.minDistance = 1f; // Full volume within this distance
source.maxDistance = 50f; // Inaudible beyond this distance
source.rolloffMode = AudioRolloffMode.Logarithmic; // Natural falloff
```
### Volume Rolloff Curves
- **Logarithmic**: Natural, realistic (RECOMMENDED)
- **Linear**: Steady decrease
- **Custom**: Define your own curve
---
## Audio Mixer (Advanced Mixing)
### Setup Audio Mixer
1. `Assets > Create > Audio Mixer`
2. Open mixer: `Window > Audio > Audio Mixer`
3. Create groups: Master > SFX, Music, Dialogue
### Assign AudioSource to Mixer Group
```csharp
using UnityEngine.Audio;
public AudioMixerGroup sfxGroup;
void Start() {
AudioSource source = GetComponent<AudioSource>();
source.outputAudioMixerGroup = sfxGroup; // Route to SFX group
}
```
### Control Mixer from Code
```csharp
using UnityEngine.Audio;
public AudioMixer audioMixer;
// ✅ Set volume (exposed parameter)
audioMixer.SetFloat("MusicVolume", -10f); // dB (-80 to 0)
// ✅ Get volume
audioMixer.GetFloat("MusicVolume", out float volume);
// Convert linear (0-1) to dB
float volumeDB = Mathf.Log10(volumeLinear) * 20f;
audioMixer.SetFloat("MusicVolume", volumeDB);
```
### Expose Mixer Parameters
In Audio Mixer window:
1. Right-click parameter (e.g., Volume)
2. "Expose 'Volume' to script"
3. Rename in "Exposed Parameters" tab (e.g., "MusicVolume")
---
## Audio Effects
### Add Effects to Mixer Groups
In Audio Mixer:
- Click group (e.g., SFX)
- Click "Add Effect"
- Choose: Reverb, Echo, Low Pass, High Pass, Distortion, etc.
### Duck Music During Dialogue (Sidechain)
```csharp
// Setup in Audio Mixer:
// 1. Create "Duck Volume" snapshot
// 2. Lower music volume in that snapshot
// 3. Transition to snapshot when dialogue plays
public AudioMixerSnapshot normalSnapshot;
public AudioMixerSnapshot duckedSnapshot;
public void PlayDialogue(AudioClip clip) {
duckedSnapshot.TransitionTo(0.5f); // 0.5s transition
audioSource.PlayOneShot(clip);
Invoke(nameof(RestoreMusic), clip.length);
}
void RestoreMusic() {
normalSnapshot.TransitionTo(1.0f); // 1s transition back
}
```
---
## Audio Performance
### Optimize Audio Loading
```csharp
// Audio Import Settings (Inspector):
// - Load Type:
// - Decompress On Load: Small clips (SFX), loads fully into memory
// - Compressed In Memory: Medium clips, decompressed at runtime (RECOMMENDED)
// - Streaming: Large clips (music), streamed from disk
// Compression Format:
// - PCM: Uncompressed, highest quality, largest size
// - ADPCM: 3.5x compression, good for SFX (RECOMMENDED for SFX)
// - Vorbis/MP3: High compression, good for music (RECOMMENDED for music)
```
### Preload Audio
```csharp
// Preload audio clip before playing (avoid stutter)
audioSource.clip.LoadAudioData();
// Check if loaded
if (audioSource.clip.loadState == AudioDataLoadState.Loaded) {
audioSource.Play();
}
```
---
## Music Systems
### Crossfade Between Tracks
```csharp
public IEnumerator CrossfadeMusic(AudioSource from, AudioSource to, float duration) {
float elapsed = 0f;
to.Play();
while (elapsed < duration) {
elapsed += Time.deltaTime;
float t = elapsed / duration;
from.volume = Mathf.Lerp(1f, 0f, t);
to.volume = Mathf.Lerp(0f, 1f, t);
yield return null;
}
from.Stop();
}
```
### Seamless Music Looping
```csharp
// Audio Import Settings:
// - Check "Loop" for seamless music loops
audioSource.loop = true;
```
---
## Common Patterns
### Random Pitch Variation (Avoid Repetition)
```csharp
void PlaySoundWithVariation(AudioClip clip) {
AudioSource source = GetComponent<AudioSource>();
source.pitch = Random.Range(0.9f, 1.1f); // ±10% pitch variation
source.PlayOneShot(clip);
}
```
### Footstep Sounds (Random from Array)
```csharp
public AudioClip[] footstepClips;
void PlayFootstep() {
AudioClip clip = footstepClips[Random.Range(0, footstepClips.Length)];
AudioSource.PlayClipAtPoint(clip, transform.position, 0.5f);
}
```
### Check if Sound is Playing
```csharp
if (audioSource.isPlaying) {
// Sound is currently playing
}
```
---
## Audio Listener
### Single Listener Rule
- Only ONE `AudioListener` should be active at a time
- Usually attached to Main Camera
```csharp
// Disable extra listeners
AudioListener listener = GetComponent<AudioListener>();
listener.enabled = false;
```
---
## Debugging
### Audio Window
- `Window > Audio > Audio Mixer`
- Visualize levels, test snapshots
### Audio Settings
- `Edit > Project Settings > Audio`
- Global volume, DSP buffer size, speaker mode
---
## Sources
- https://docs.unity3d.com/6000.0/Documentation/Manual/Audio.html
- https://docs.unity3d.com/6000.0/Documentation/Manual/AudioMixer.html

View File

@@ -0,0 +1,356 @@
# Unity 6.3 — Input Module Reference
**Last verified:** 2026-02-13
**Knowledge Gap:** Unity 6 uses new Input System (legacy Input deprecated)
---
## Overview
Unity 6 input systems:
- **Input System Package** (RECOMMENDED): Cross-platform, rebindable, modern
- **Legacy Input Manager**: Deprecated, avoid for new projects
---
## Key Changes from 2022 LTS
### Legacy Input Deprecated in Unity 6
```csharp
// ❌ DEPRECATED: Input class
if (Input.GetKeyDown(KeyCode.Space)) { }
// ✅ NEW: Input System package
using UnityEngine.InputSystem;
if (Keyboard.current.spaceKey.wasPressedThisFrame) { }
```
**Migration Required:** Install `com.unity.inputsystem` package.
---
## Input System Package Setup
### Installation
1. `Window > Package Manager`
2. Search "Input System"
3. Install package
4. Restart Unity when prompted
### Enable New Input System
`Edit > Project Settings > Player > Active Input Handling`:
- **Input System Package (New)** ✅ Recommended
- **Both** (for migration period)
---
## Input Actions (Recommended Pattern)
### Create Input Actions Asset
1. `Assets > Create > Input Actions`
2. Name it (e.g., "PlayerControls")
3. Open asset, define actions:
```
Action Maps:
Gameplay
Actions:
- Move (Value, Vector2)
- Jump (Button)
- Fire (Button)
- Look (Value, Vector2)
```
4. **Generate C# Class**: Check "Generate C# Class" in Inspector
5. Click "Apply"
### Use Generated Input Class
```csharp
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour {
private PlayerControls controls;
void Awake() {
controls = new PlayerControls();
// Subscribe to actions
controls.Gameplay.Jump.performed += ctx => Jump();
controls.Gameplay.Fire.performed += ctx => Fire();
}
void OnEnable() => controls.Enable();
void OnDisable() => controls.Disable();
void Update() {
// Read continuous input
Vector2 move = controls.Gameplay.Move.ReadValue<Vector2>();
transform.Translate(new Vector3(move.x, 0, move.y) * Time.deltaTime);
Vector2 look = controls.Gameplay.Look.ReadValue<Vector2>();
// Apply camera rotation
}
void Jump() {
Debug.Log("Jump!");
}
void Fire() {
Debug.Log("Fire!");
}
}
```
---
## Direct Device Access (Quick & Dirty)
### Keyboard
```csharp
using UnityEngine.InputSystem;
void Update() {
// Current state
if (Keyboard.current.spaceKey.isPressed) { }
// Just pressed this frame
if (Keyboard.current.spaceKey.wasPressedThisFrame) { }
// Just released this frame
if (Keyboard.current.spaceKey.wasReleasedThisFrame) { }
}
```
### Mouse
```csharp
using UnityEngine.InputSystem;
void Update() {
// Mouse position
Vector2 mousePos = Mouse.current.position.ReadValue();
// Mouse delta (movement)
Vector2 mouseDelta = Mouse.current.delta.ReadValue();
// Mouse buttons
if (Mouse.current.leftButton.wasPressedThisFrame) { }
if (Mouse.current.rightButton.isPressed) { }
// Scroll wheel
Vector2 scroll = Mouse.current.scroll.ReadValue();
}
```
### Gamepad
```csharp
using UnityEngine.InputSystem;
void Update() {
Gamepad gamepad = Gamepad.current;
if (gamepad == null) return; // No gamepad connected
// Buttons
if (gamepad.buttonSouth.wasPressedThisFrame) { } // A/Cross
if (gamepad.buttonWest.wasPressedThisFrame) { } // X/Square
// Sticks
Vector2 leftStick = gamepad.leftStick.ReadValue();
Vector2 rightStick = gamepad.rightStick.ReadValue();
// Triggers
float leftTrigger = gamepad.leftTrigger.ReadValue();
float rightTrigger = gamepad.rightTrigger.ReadValue();
// D-Pad
Vector2 dpad = gamepad.dpad.ReadValue();
}
```
### Touch (Mobile)
```csharp
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.EnhancedTouch;
void OnEnable() {
EnhancedTouchSupport.Enable();
}
void Update() {
foreach (var touch in UnityEngine.InputSystem.EnhancedTouch.Touch.activeTouches) {
Debug.Log($"Touch at {touch.screenPosition}");
}
}
```
---
## Input Action Callbacks
### Action Callbacks (Event-Driven)
```csharp
// started: Input began (e.g., trigger pressed slightly)
controls.Gameplay.Fire.started += ctx => Debug.Log("Fire started");
// performed: Input action triggered (e.g., button fully pressed)
controls.Gameplay.Fire.performed += ctx => Debug.Log("Fire performed");
// canceled: Input released or interrupted
controls.Gameplay.Fire.canceled += ctx => Debug.Log("Fire canceled");
```
### Context Data
```csharp
controls.Gameplay.Move.performed += ctx => {
Vector2 value = ctx.ReadValue<Vector2>();
float duration = ctx.duration; // How long input held
InputControl control = ctx.control; // Which device/control triggered it
};
```
---
## Control Schemes & Device Switching
### Define Control Schemes in Input Actions Asset
```
Control Schemes:
- Keyboard&Mouse (Keyboard, Mouse)
- Gamepad (Gamepad)
- Touch (Touchscreen)
```
### Auto-Switch on Device Change
```csharp
controls.Gameplay.Move.performed += ctx => {
if (ctx.control.device is Keyboard) {
Debug.Log("Using keyboard");
} else if (ctx.control.device is Gamepad) {
Debug.Log("Using gamepad");
}
};
```
---
## Rebinding (Runtime Key Mapping)
### Interactive Rebind
```csharp
using UnityEngine.InputSystem;
public void RebindJumpKey() {
var rebindOperation = controls.Gameplay.Jump.PerformInteractiveRebinding()
.WithControlsExcluding("Mouse") // Exclude mouse bindings
.OnComplete(operation => {
Debug.Log("Rebind complete");
operation.Dispose();
})
.Start();
}
```
### Save/Load Bindings
```csharp
// Save
string rebinds = controls.SaveBindingOverridesAsJson();
PlayerPrefs.SetString("InputBindings", rebinds);
// Load
string rebinds = PlayerPrefs.GetString("InputBindings");
controls.LoadBindingOverridesFromJson(rebinds);
```
---
## Action Types
### Button (Press/Release)
- Single press/release
- Example: Jump, Fire
### Value (Continuous)
- Continuous value (float, Vector2)
- Example: Move, Look, Aim
### Pass-Through (Immediate)
- No processing, immediate value
- Example: Mouse position
---
## Processors (Input Modifiers)
### Scale
```csharp
// In Input Actions asset: Action > Properties > Processors > Add > Scale
// Multiply input by value (e.g., invert Y-axis)
```
### Invert
```csharp
// In Input Actions asset: Action > Properties > Processors > Add > Invert
// Flip input sign
```
### Dead Zone
```csharp
// In Input Actions asset: Action > Properties > Processors > Add > Stick Deadzone
// Ignore small stick movements
```
---
## PlayerInput Component (Simplified Setup)
### Automatic Input Setup
```csharp
// Add Component: Player Input
// Assign Input Actions asset
// Behavior: Send Messages / Invoke Unity Events / Invoke C# Events
// Send Messages example:
public class Player : MonoBehaviour {
public void OnMove(InputValue value) {
Vector2 move = value.Get<Vector2>();
// Handle movement
}
public void OnJump(InputValue value) {
if (value.isPressed) {
Jump();
}
}
}
```
---
## Debugging
### Input Debugger
- `Window > Analysis > Input Debugger`
- See active devices, input values, action states
---
## Sources
- https://docs.unity3d.com/Packages/com.unity.inputsystem@1.11/manual/index.html
- https://docs.unity3d.com/Packages/com.unity.inputsystem@1.11/manual/QuickStartGuide.html

View File

@@ -0,0 +1,330 @@
# Unity 6.3 — Navigation Module Reference
**Last verified:** 2026-02-13
**Knowledge Gap:** Unity 6 NavMesh improvements
---
## Overview
Unity 6 navigation systems:
- **NavMesh**: Built-in pathfinding for AI agents
- **NavMeshComponents**: Package for runtime NavMesh building
---
## NavMesh Basics
### Bake Navigation Mesh
1. Mark walkable surfaces:
- Select GameObject (floor/terrain)
- Inspector > Navigation > Object tab
- Check "Navigation Static"
2. Bake NavMesh:
- `Window > AI > Navigation`
- Bake tab
- Click "Bake"
3. Configure settings:
- **Agent Radius**: How wide the agent is (0.5m default)
- **Agent Height**: How tall the agent is (2m default)
- **Max Slope**: Maximum walkable slope (45° default)
- **Step Height**: Maximum climbable step (0.4m default)
---
## NavMeshAgent (AI Movement)
### Basic Agent Setup
```csharp
using UnityEngine;
using UnityEngine.AI;
public class Enemy : MonoBehaviour {
private NavMeshAgent agent;
public Transform target;
void Start() {
agent = GetComponent<NavMeshAgent>();
}
void Update() {
// ✅ Move to target
agent.SetDestination(target.position);
}
}
```
---
### NavMeshAgent Properties
```csharp
NavMeshAgent agent = GetComponent<NavMeshAgent>();
// Speed
agent.speed = 3.5f;
// Acceleration
agent.acceleration = 8f;
// Stopping distance
agent.stoppingDistance = 2f; // Stop 2m before destination
// Auto-braking (slow down at destination)
agent.autoBraking = true;
// Rotation speed
agent.angularSpeed = 120f; // Degrees per second
// Obstacle avoidance
agent.obstacleAvoidanceType = ObstacleAvoidanceType.HighQualityObstacleAvoidance;
```
---
### Check Path Status
```csharp
void Update() {
agent.SetDestination(target.position);
// Check if agent has a path
if (agent.hasPath) {
// Check if path is complete
if (agent.pathStatus == NavMeshPathStatus.PathComplete) {
Debug.Log("Valid path");
} else if (agent.pathStatus == NavMeshPathStatus.PathPartial) {
Debug.Log("Partial path (destination unreachable)");
} else {
Debug.Log("Invalid path");
}
}
// Check if agent reached destination
if (!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance) {
Debug.Log("Reached destination");
}
}
```
---
### Calculate Path (Don't Move Yet)
```csharp
NavMeshPath path = new NavMeshPath();
agent.CalculatePath(targetPosition, path);
if (path.status == NavMeshPathStatus.PathComplete) {
// Valid path exists
agent.SetPath(path); // Apply the path
}
```
---
## NavMesh Areas (Walkable Costs)
### Define Areas
`Window > AI > Navigation > Areas tab`
- **Walkable**: Cost 1 (default)
- **Not Walkable**: Unwalkable
- **Jump**: Cost 2 (prefer other routes)
- **Custom**: Define your own
### Assign Area Costs
```csharp
// Prefer shorter paths over low-cost paths
agent.areaMask = NavMesh.AllAreas; // Walk on all areas
// Only walk on "Walkable" area (avoid "Jump")
agent.areaMask = 1 << NavMesh.GetAreaFromName("Walkable");
```
---
## NavMesh Obstacles (Dynamic Obstacles)
### NavMeshObstacle Component
```csharp
// Add: GameObject > Add Component > NavMesh Obstacle
// Carve: Create hole in NavMesh (agents avoid)
// Don't Carve: Agent pushes through (local avoidance)
```
### Dynamic Carving (Moving Obstacles)
```csharp
NavMeshObstacle obstacle = GetComponent<NavMeshObstacle>();
obstacle.carving = true; // Create dynamic hole in NavMesh
```
---
## Off-Mesh Links (Jumps, Teleports)
### Create Off-Mesh Link
1. `GameObject > Create Empty` (at jump start)
2. Add `Off Mesh Link` component
3. Set Start/End transforms
4. Configure:
- **Bi-Directional**: Can traverse both ways
- **Cost Override**: Path cost for this link
### Detect Off-Mesh Link Traversal
```csharp
void Update() {
// Check if agent is on an off-mesh link
if (agent.isOnOffMeshLink) {
// Manually traverse (e.g., play jump animation)
StartCoroutine(TraverseOffMeshLink());
}
}
IEnumerator TraverseOffMeshLink() {
OffMeshLinkData data = agent.currentOffMeshLinkData;
Vector3 startPos = agent.transform.position;
Vector3 endPos = data.endPos;
float duration = 0.5f;
float elapsed = 0f;
while (elapsed < duration) {
agent.transform.position = Vector3.Lerp(startPos, endPos, elapsed / duration);
elapsed += Time.deltaTime;
yield return null;
}
agent.CompleteOffMeshLink(); // Resume normal pathfinding
}
```
---
## NavMeshComponents Package (Runtime Baking)
### Installation
1. `Window > Package Manager`
2. Add from Git URL: `com.unity.ai.navigation`
### Runtime NavMesh Baking
```csharp
using Unity.AI.Navigation;
public class NavMeshBuilder : MonoBehaviour {
public NavMeshSurface surface;
void Start() {
// Bake NavMesh at runtime
surface.BuildNavMesh();
}
void UpdateNavMesh() {
// Update NavMesh after terrain changes
surface.UpdateNavMesh(surface.navMeshData);
}
}
```
---
## Common Patterns
### Patrol Between Waypoints
```csharp
public Transform[] waypoints;
private int currentWaypoint = 0;
void Update() {
if (!agent.pathPending && agent.remainingDistance < 0.5f) {
// Reached waypoint, move to next
currentWaypoint = (currentWaypoint + 1) % waypoints.Length;
agent.SetDestination(waypoints[currentWaypoint].position);
}
}
```
### Chase Player
```csharp
public Transform player;
public float chaseRange = 10f;
void Update() {
float distance = Vector3.Distance(transform.position, player.position);
if (distance <= chaseRange) {
agent.SetDestination(player.position);
} else {
agent.ResetPath(); // Stop moving
}
}
```
### Flee from Player
```csharp
public Transform player;
public float fleeRange = 5f;
void Update() {
float distance = Vector3.Distance(transform.position, player.position);
if (distance <= fleeRange) {
// Run away from player
Vector3 fleeDirection = transform.position - player.position;
Vector3 fleeTarget = transform.position + fleeDirection.normalized * 10f;
agent.SetDestination(fleeTarget);
}
}
```
---
## Debugging
### NavMesh Visualization
- `Window > AI > Navigation > Bake tab`
- Check "Show NavMesh" to visualize walkable areas
### Agent Path Gizmos
```csharp
void OnDrawGizmos() {
if (agent != null && agent.hasPath) {
Gizmos.color = Color.green;
Vector3[] corners = agent.path.corners;
for (int i = 0; i < corners.Length - 1; i++) {
Gizmos.DrawLine(corners[i], corners[i + 1]);
}
}
}
```
---
## Performance Tips
- **Limit Obstacle Avoidance Quality**: Use `LowQualityObstacleAvoidance` for distant agents
- **Update Frequency**: Don't call `SetDestination()` every frame if target hasn't moved
- **Area Masks**: Limit walkable areas to reduce pathfinding search space
- **NavMesh Tiles**: Use tiled NavMesh for large worlds (NavMeshComponents package)
---
## Sources
- https://docs.unity3d.com/6000.0/Documentation/Manual/Navigation.html
- https://docs.unity3d.com/Packages/com.unity.ai.navigation@2.0/manual/index.html

View File

@@ -0,0 +1,351 @@
# Unity 6.3 — Networking Module Reference
**Last verified:** 2026-02-13
**Knowledge Gap:** Unity 6 uses Netcode for GameObjects (UNet deprecated)
---
## Overview
Unity 6 networking options:
- **Netcode for GameObjects** (RECOMMENDED): Official Unity multiplayer framework
- **Mirror**: Community-driven (UNet successor)
- **Photon**: Third-party service (PUN2)
- **Custom**: Low-level sockets
**UNet (Legacy)**: Deprecated, do not use.
---
## Netcode for GameObjects
### Installation
1. `Window > Package Manager`
2. Search "Netcode for GameObjects"
3. Install `com.unity.netcode.gameobjects`
---
## Basic Setup
### NetworkManager
```csharp
// Add to scene: GameObject > Add Component > NetworkManager
// Or create custom NetworkManager:
using Unity.Netcode;
public class CustomNetworkManager : MonoBehaviour {
void Start() {
NetworkManager.Singleton.StartHost(); // Server + client
// OR
NetworkManager.Singleton.StartServer(); // Dedicated server
// OR
NetworkManager.Singleton.StartClient(); // Client only
}
}
```
---
## NetworkObject (Networked GameObjects)
### Mark GameObject as Networked
1. Add `NetworkObject` component to GameObject
2. Must be in root of prefab (not nested)
3. Register prefab in `NetworkManager > NetworkPrefabs List`
### Spawn Network Objects
```csharp
using Unity.Netcode;
public class GameManager : NetworkBehaviour {
public GameObject playerPrefab;
[ServerRpc(RequireOwnership = false)]
public void SpawnPlayerServerRpc(ulong clientId) {
GameObject player = Instantiate(playerPrefab);
player.GetComponent<NetworkObject>().SpawnAsPlayerObject(clientId);
}
}
```
---
## NetworkBehaviour (Networked Scripts)
### NetworkBehaviour Base Class
```csharp
using Unity.Netcode;
public class Player : NetworkBehaviour {
// Called when spawned on network
public override void OnNetworkSpawn() {
if (IsOwner) {
// Only run on owner's client
GetComponent<Camera>().enabled = true;
}
}
void Update() {
if (!IsOwner) return; // Only owner can control
// Handle input
if (Input.GetKey(KeyCode.W)) {
MoveServerRpc(Vector3.forward);
}
}
[ServerRpc]
void MoveServerRpc(Vector3 direction) {
// Runs on server
transform.position += direction * Time.deltaTime;
}
}
```
---
## Network Variables (Synchronized State)
### NetworkVariable<T>
```csharp
using Unity.Netcode;
public class Player : NetworkBehaviour {
// ✅ Auto-synced across clients
private NetworkVariable<int> health = new NetworkVariable<int>(100);
public override void OnNetworkSpawn() {
// Subscribe to value changes
health.OnValueChanged += OnHealthChanged;
}
void OnHealthChanged(int oldValue, int newValue) {
Debug.Log($"Health changed: {oldValue} -> {newValue}");
UpdateHealthUI(newValue);
}
[ServerRpc]
public void TakeDamageServerRpc(int damage) {
// Only server can modify NetworkVariable
health.Value -= damage;
}
}
```
### NetworkVariable Permissions
```csharp
// Server can write, clients read-only (default)
private NetworkVariable<int> score = new NetworkVariable<int>();
// Owner can write
private NetworkVariable<int> ammo = new NetworkVariable<int>(
default,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Owner
);
```
---
## RPCs (Remote Procedure Calls)
### ServerRpc (Client → Server)
```csharp
// Client calls, server executes
[ServerRpc]
void FireWeaponServerRpc() {
// Runs on server
Debug.Log("Server: Weapon fired");
}
// Call from client:
if (IsOwner && Input.GetKeyDown(KeyCode.Space)) {
FireWeaponServerRpc();
}
```
### ClientRpc (Server → All Clients)
```csharp
// Server calls, all clients execute
[ClientRpc]
void PlayExplosionClientRpc(Vector3 position) {
// Runs on all clients
Instantiate(explosionPrefab, position, Quaternion.identity);
}
// Call from server:
[ServerRpc]
void ExplodeServerRpc(Vector3 position) {
// Server logic
DealDamageToNearbyPlayers(position);
// Notify all clients
PlayExplosionClientRpc(position);
}
```
### RPC Parameters
```csharp
// ✅ Supported: Primitives, structs, strings, arrays
[ServerRpc]
void SetNameServerRpc(string playerName) { }
[ClientRpc]
void UpdateScoresClientRpc(int[] scores) { }
// ❌ Not supported: MonoBehaviour, GameObject (use NetworkObjectReference)
```
---
## Network Ownership
### Check Ownership
```csharp
if (IsOwner) {
// This client owns this NetworkObject
}
if (IsServer) {
// Running on server
}
if (IsClient) {
// Running on client
}
if (IsLocalPlayer) {
// This is the local player object
}
```
### Transfer Ownership
```csharp
// Server transfers ownership
NetworkObject netObj = GetComponent<NetworkObject>();
netObj.ChangeOwnership(newOwnerClientId);
```
---
## NetworkObjectReference (Pass GameObjects in RPCs)
```csharp
using Unity.Netcode;
[ServerRpc]
void AttackTargetServerRpc(NetworkObjectReference targetRef) {
if (targetRef.TryGet(out NetworkObject target)) {
// Got the target object
target.GetComponent<Health>().TakeDamage(10);
}
}
// Call:
NetworkObject targetNetObj = target.GetComponent<NetworkObject>();
AttackTargetServerRpc(targetNetObj);
```
---
## Client-Server Architecture
### Server-Authoritative Pattern (RECOMMENDED)
```csharp
public class Player : NetworkBehaviour {
private NetworkVariable<Vector3> position = new NetworkVariable<Vector3>();
void Update() {
if (IsOwner) {
// Client: Send input to server
Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
MoveServerRpc(input);
}
// All clients: Sync to networked position
transform.position = position.Value;
}
[ServerRpc]
void MoveServerRpc(Vector3 input) {
// Server: Validate and apply movement
position.Value += input * Time.deltaTime * moveSpeed;
}
}
```
---
## Network Transport
### Unity Transport (Default)
```csharp
// Configured in NetworkManager:
// - Transport: Unity Transport
// - Address: 127.0.0.1 (localhost) or server IP
// - Port: 7777 (default)
```
### Connection Events
```csharp
void Start() {
NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnected;
}
void OnClientConnected(ulong clientId) {
Debug.Log($"Client {clientId} connected");
}
void OnClientDisconnected(ulong clientId) {
Debug.Log($"Client {clientId} disconnected");
}
```
---
## Performance Tips
### Reduce Network Traffic
- Use `NetworkVariable` for state that changes infrequently
- Batch multiple changes before syncing
- Use delta compression for large data
### Prediction & Reconciliation
- Run movement locally for responsiveness
- Reconcile with server authoritative state
- Use interpolation for smooth movement
---
## Debugging
### Network Profiler
- `Window > Analysis > Network Profiler`
- Monitor bandwidth, RPC calls, variable updates
### Network Simulator (Test Latency/Packet Loss)
- `NetworkManager > Network Simulator`
- Add artificial lag and packet loss for testing
---
## Sources
- https://docs-multiplayer.unity3d.com/netcode/current/about/
- https://docs-multiplayer.unity3d.com/netcode/current/learn/bossroom/

View File

@@ -0,0 +1,268 @@
# Unity 6.3 — Physics Module Reference
**Last verified:** 2026-02-13
**Knowledge Gap:** Unity 6 physics improvements, solver changes
---
## Overview
Unity 6.3 uses **PhysX 5.1** (improved from PhysX 4.x in 2022 LTS):
- Better solver stability
- Improved performance
- Enhanced collision detection
---
## Key Changes from 2022 LTS
### Default Solver Iterations Increased
Unity 6 increased default solver iterations for better stability:
```csharp
// Default changed from 6 to 8 iterations
Physics.defaultSolverIterations = 8; // Check if relying on old behavior
```
### Enhanced Collision Detection
```csharp
// ✅ Unity 6: Improved Continuous Collision Detection (CCD)
rigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
// Better handling of fast-moving objects
```
---
## Core Physics Components
### Rigidbody
```csharp
// ✅ Best practice: Use AddForce, not direct velocity writes
Rigidbody rb = GetComponent<Rigidbody>();
rb.AddForce(Vector3.forward * 10f, ForceMode.Impulse);
// ❌ Avoid: Direct velocity assignment (can cause instability)
rb.velocity = new Vector3(0, 10, 0); // Only use when necessary
```
### Colliders
```csharp
// Primitive colliders: Box, Sphere, Capsule (cheapest)
// Mesh colliders: Expensive, use only for static geometry
// ✅ Compound colliders (multiple primitives) > single mesh collider
```
---
## Raycasting
### Efficient Raycasting (Avoid Allocations)
```csharp
// ✅ Non-allocating raycast
if (Physics.Raycast(origin, direction, out RaycastHit hit, maxDistance)) {
Debug.Log($"Hit: {hit.collider.name}");
}
// ✅ Multiple hits (non-allocating)
RaycastHit[] results = new RaycastHit[10];
int hitCount = Physics.RaycastNonAlloc(origin, direction, results, maxDistance);
for (int i = 0; i < hitCount; i++) {
Debug.Log($"Hit {i}: {results[i].collider.name}");
}
// ❌ Avoid: RaycastAll (allocates array every call)
RaycastHit[] hits = Physics.RaycastAll(origin, direction); // GC allocation!
```
### LayerMask for Selective Raycasting
```csharp
// ✅ Use LayerMask to filter collisions
int layerMask = 1 << LayerMask.NameToLayer("Enemy");
Physics.Raycast(origin, direction, out RaycastHit hit, maxDistance, layerMask);
```
---
## Physics Queries
### OverlapSphere (Check for nearby objects)
```csharp
// ✅ Non-allocating version
Collider[] results = new Collider[10];
int count = Physics.OverlapSphereNonAlloc(center, radius, results);
for (int i = 0; i < count; i++) {
// Process results[i]
}
```
### SphereCast (Thick raycast)
```csharp
// Useful for character controllers
if (Physics.SphereCast(origin, radius, direction, out RaycastHit hit, maxDistance)) {
// Hit something with a sphere-shaped ray
}
```
---
## Collision Events
### OnCollisionEnter / Stay / Exit
```csharp
void OnCollisionEnter(Collision collision) {
// Triggered when collision starts
Debug.Log($"Collided with {collision.gameObject.name}");
// Access contact points
foreach (ContactPoint contact in collision.contacts) {
Debug.DrawRay(contact.point, contact.normal, Color.red, 2f);
}
}
```
### OnTriggerEnter / Stay / Exit
```csharp
void OnTriggerEnter(Collider other) {
// Trigger collider (Is Trigger = true)
if (other.CompareTag("Pickup")) {
Destroy(other.gameObject);
}
}
```
---
## Character Controllers
### CharacterController Component
```csharp
CharacterController controller = GetComponent<CharacterController>();
// ✅ Move with collision detection
Vector3 move = transform.forward * speed * Time.deltaTime;
controller.Move(move);
// Apply gravity manually
if (!controller.isGrounded) {
velocity.y += Physics.gravity.y * Time.deltaTime;
}
controller.Move(velocity * Time.deltaTime);
```
---
## Physics Materials
### Friction & Bounciness
```csharp
// Create: Assets > Create > Physic Material
// Assign to collider: Collider > Material
// PhysicMaterial settings:
// - Dynamic Friction: 0.6 (sliding friction)
// - Static Friction: 0.6 (starting friction)
// - Bounciness: 0.0 - 1.0
// - Friction Combine: Average, Minimum, Maximum, Multiply
// - Bounce Combine: Average, Minimum, Maximum, Multiply
```
---
## Joints
### Fixed Joint (Attach two rigidbodies)
```csharp
FixedJoint joint = gameObject.AddComponent<FixedJoint>();
joint.connectedBody = otherRigidbody;
```
### Hinge Joint (Door, wheel)
```csharp
HingeJoint hinge = gameObject.AddComponent<HingeJoint>();
hinge.axis = Vector3.up; // Rotation axis
hinge.useLimits = true;
hinge.limits = new JointLimits { min = -90, max = 90 };
```
---
## Performance Optimization
### Physics Layer Collision Matrix
`Edit > Project Settings > Physics > Layer Collision Matrix`
- Disable unnecessary collision checks between layers
- Massive performance gain
### Fixed Timestep
`Edit > Project Settings > Time > Fixed Timestep`
- Default: 0.02 (50 FPS physics)
- Lower = more accurate, higher CPU cost
- Match game's target framerate if possible
### Simplified Collision Geometry
- Use primitive colliders (box, sphere, capsule) over mesh colliders
- Bake mesh colliders at build time, not runtime
---
## Common Patterns
### Ground Check (Character Controller)
```csharp
bool IsGrounded() {
float rayLength = 0.1f;
return Physics.Raycast(transform.position, Vector3.down, rayLength);
}
```
### Apply Explosion Force
```csharp
void ApplyExplosion(Vector3 explosionPos, float radius, float force) {
Collider[] colliders = Physics.OverlapSphere(explosionPos, radius);
foreach (Collider hit in colliders) {
Rigidbody rb = hit.GetComponent<Rigidbody>();
if (rb != null) {
rb.AddExplosionForce(force, explosionPos, radius);
}
}
}
```
---
## Debugging
### Physics Debugger (Unity 6+)
- `Window > Analysis > Physics Debugger`
- Visualize colliders, contacts, queries
### Gizmos
```csharp
void OnDrawGizmos() {
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, detectionRadius);
}
```
---
## Sources
- https://docs.unity3d.com/6000.0/Documentation/Manual/PhysicsOverview.html
- https://docs.unity3d.com/ScriptReference/Physics.html

View File

@@ -0,0 +1,238 @@
# Unity 6.3 — Rendering Module Reference
**Last verified:** 2026-02-13
**Knowledge Gap:** LLM trained on Unity 2022 LTS; Unity 6 has major rendering changes
---
## Overview
Unity 6.3 LTS uses **Scriptable Render Pipelines (SRP)** as the modern rendering architecture:
- **URP (Universal Render Pipeline)**: Cross-platform, mobile-friendly (RECOMMENDED)
- **HDRP (High Definition Render Pipeline)**: High-end PC/console, photorealistic
- **Built-in Pipeline**: Deprecated, avoid for new projects
---
## Key Changes from 2022 LTS
### RenderGraph API (Unity 6+)
Custom render passes now use RenderGraph instead of CommandBuffer:
```csharp
// ✅ Unity 6+ (RenderGraph)
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) {
using var builder = renderGraph.AddRasterRenderPass<PassData>("MyPass", out var passData);
builder.SetRenderFunc((PassData data, RasterGraphContext ctx) => {
// Rendering commands
});
}
// ❌ Old (CommandBuffer - still works but deprecated)
public override void Execute(ScriptableRenderContext context, ref RenderingData data) { }
```
### GPU Resident Drawer (Unity 6+)
Automatic batching for massive draw call reduction:
```csharp
// Enable in URP Asset settings:
// Rendering > GPU Resident Drawer = Enabled
// Automatically batches thousands of objects with minimal CPU overhead
```
---
## URP Quick Reference
### Creating a URP Asset
1. `Assets > Create > Rendering > URP Asset (with Universal Renderer)`
2. Assign to `Project Settings > Graphics > Scriptable Render Pipeline Settings`
### URP Renderer Features
Add custom render passes:
```csharp
using UnityEngine.Rendering.Universal;
public class OutlineRendererFeature : ScriptableRendererFeature {
OutlineRenderPass pass;
public override void Create() {
pass = new OutlineRenderPass();
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData data) {
renderer.EnqueuePass(pass);
}
}
```
---
## Materials & Shaders
### Shader Graph (Visual Shader Editor)
Unity 6 Shader Graph is production-ready for all shader types:
```csharp
// Create: Assets > Create > Shader Graph > URP > Lit Shader Graph
// No code needed, visual node-based editing
```
### HLSL Custom Shaders (URP)
```hlsl
// URP Lit shader template
Shader "Custom/URPLit" {
Properties {
_BaseColor ("Base Color", Color) = (1,1,1,1)
}
SubShader {
Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" }
Pass {
Name "ForwardLit"
Tags { "LightMode"="UniversalForward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes {
float4 positionOS : POSITION;
};
struct Varyings {
float4 positionCS : SV_POSITION;
};
Varyings vert(Attributes input) {
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
return output;
}
half4 frag(Varyings input) : SV_Target {
return half4(1, 0, 0, 1); // Red
}
ENDHLSL
}
}
}
```
---
## Lighting
### Baked Lighting (Unity 6 Progressive Lightmapper)
```csharp
// Mark objects as static: Inspector > Static > Contribute GI
// Bake: Window > Rendering > Lighting > Generate Lighting
```
### Real-Time Lights (URP)
```csharp
// Main Light (Directional): Auto-handled by URP
// Additional Lights: Limited by "Additional Lights" setting in URP Asset
// Check light count in shader:
int lightCount = GetAdditionalLightsCount();
```
---
## Post-Processing
### Volume System (Unity 6+)
```csharp
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
// Add Volume component to GameObject
// Add Volume Profile asset
// Configure effects: Bloom, Color Grading, Depth of Field, etc.
// Script access:
Volume volume = GetComponent<Volume>();
if (volume.profile.TryGet<Bloom>(out var bloom)) {
bloom.intensity.value = 2.5f;
}
```
---
## Performance
### SRP Batcher (Auto-batching)
```csharp
// Enable: URP Asset > Advanced > SRP Batcher = Enabled
// Batches draws with same shader variant (minimal CPU overhead)
```
### GPU Instancing
```csharp
// Material: Enable "Enable GPU Instancing" checkbox
// Batches identical meshes (same material + mesh)
Graphics.RenderMeshInstanced(
new RenderParams(material),
mesh,
0,
matrices // NativeArray<Matrix4x4>
);
```
### Occlusion Culling
```csharp
// Window > Rendering > Occlusion Culling
// Bake occlusion data for static geometry
```
---
## Common Patterns
### Custom Camera Rendering
```csharp
// Get URP camera data
var cameraData = frameData.Get<UniversalCameraData>();
var camera = cameraData.camera;
// Access render targets
var colorTarget = cameraData.renderer.cameraColorTargetHandle;
```
### Screen-Space Effects
```csharp
// Create ScriptableRendererFeature
// Inject pass at specific point: AfterRenderingOpaques, AfterRenderingTransparents, etc.
```
---
## Debugging
### Frame Debugger
- `Window > Analysis > Frame Debugger`
- Step through draw calls, inspect state
### Rendering Debugger (Unity 6+)
- `Window > Analysis > Rendering Debugger`
- Live view of URP settings, overdraw, lighting
---
## Sources
- https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@17.0/manual/index.html
- https://docs.unity3d.com/6000.0/Documentation/Manual/render-pipelines.html

View File

@@ -0,0 +1,377 @@
# Unity 6.3 — UI Module Reference
**Last verified:** 2026-02-13
**Knowledge Gap:** Unity 6 UI Toolkit is production-ready for runtime UI
---
## Overview
Unity 6 UI systems:
- **UI Toolkit** (RECOMMENDED): Modern, performant, HTML/CSS-like (production-ready in Unity 6)
- **UGUI (Canvas)**: Legacy system, still supported but not recommended for new projects
- **IMGUI**: Editor-only, deprecated for runtime UI
---
## UI Toolkit (Modern UI)
### Setup UI Document
1. Create UXML (UI structure):
- `Assets > Create > UI Toolkit > UI Document`
2. Create USS (styling):
- `Assets > Create > UI Toolkit > StyleSheet`
3. Add to scene:
- `GameObject > UI Toolkit > UI Document`
- Assign UXML to `UIDocument > Source Asset`
---
### UXML (UI Structure)
```xml
<!-- MainMenu.uxml -->
<ui:UXML xmlns:ui="UnityEngine.UIElements">
<ui:VisualElement class="container">
<ui:Label text="Main Menu" class="title" />
<ui:Button name="play-button" text="Play" />
<ui:Button name="settings-button" text="Settings" />
<ui:Button name="quit-button" text="Quit" />
</ui:VisualElement>
</ui:UXML>
```
---
### USS (Styling)
```css
/* MainMenu.uss */
.container {
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background-color: rgb(30, 30, 30);
}
.title {
font-size: 48px;
color: white;
margin-bottom: 20px;
}
Button {
width: 200px;
height: 50px;
margin: 10px;
font-size: 24px;
}
Button:hover {
background-color: rgb(100, 150, 200);
}
```
---
### C# Scripting (UI Toolkit)
```csharp
using UnityEngine;
using UnityEngine.UIElements;
public class MainMenu : MonoBehaviour {
void OnEnable() {
var root = GetComponent<UIDocument>().rootVisualElement;
// Query elements by name
var playButton = root.Q<Button>("play-button");
var settingsButton = root.Q<Button>("settings-button");
var quitButton = root.Q<Button>("quit-button");
// Register callbacks
playButton.clicked += OnPlayClicked;
settingsButton.clicked += OnSettingsClicked;
quitButton.clicked += Application.Quit;
}
void OnPlayClicked() {
Debug.Log("Play clicked");
// Load game scene
}
void OnSettingsClicked() {
Debug.Log("Settings clicked");
// Open settings menu
}
}
```
---
### Common UI Elements
```csharp
// Label (text display)
var label = root.Q<Label>("score-label");
label.text = "Score: 100";
// Button
var button = root.Q<Button>("submit-button");
button.clicked += OnSubmit;
// TextField (text input)
var textField = root.Q<TextField>("name-input");
string playerName = textField.value;
// Toggle (checkbox)
var toggle = root.Q<Toggle>("music-toggle");
bool isMusicEnabled = toggle.value;
// Slider
var slider = root.Q<Slider>("volume-slider");
float volume = slider.value; // 0-1
// DropdownField (dropdown menu)
var dropdown = root.Q<DropdownField>("difficulty-dropdown");
dropdown.choices = new List<string> { "Easy", "Normal", "Hard" };
dropdown.value = "Normal";
```
---
### Dynamic UI Creation (No UXML)
```csharp
void CreateUI() {
var root = GetComponent<UIDocument>().rootVisualElement;
// Create elements
var container = new VisualElement();
container.AddToClassList("container");
var label = new Label("Hello, UI Toolkit!");
var button = new Button(() => Debug.Log("Clicked")) { text = "Click Me" };
container.Add(label);
container.Add(button);
root.Add(container);
}
```
---
### USS Flexbox Layout
```css
/* Horizontal layout */
.horizontal {
flex-direction: row;
}
/* Vertical layout (default) */
.vertical {
flex-direction: column;
}
/* Center children */
.centered {
align-items: center;
justify-content: center;
}
/* Spacing */
.spaced {
justify-content: space-between;
}
```
---
## UGUI (Legacy Canvas UI)
### Basic Setup (Still Works in Unity 6)
```csharp
// GameObject > UI > Canvas (creates Canvas, EventSystem)
// UI Elements:
// - Text (use TextMeshPro instead)
// - Button
// - Image
// - Slider
// - Toggle
// - InputField
```
---
### UGUI Scripting
```csharp
using UnityEngine;
using UnityEngine.UI;
using TMPro; // TextMeshPro
public class LegacyUI : MonoBehaviour {
public TextMeshProUGUI scoreText;
public Button playButton;
public Slider volumeSlider;
void Start() {
// Update text
scoreText.text = "Score: 100";
// Button click
playButton.onClick.AddListener(OnPlayClicked);
// Slider value changed
volumeSlider.onValueChanged.AddListener(OnVolumeChanged);
}
void OnPlayClicked() {
Debug.Log("Play clicked");
}
void OnVolumeChanged(float value) {
AudioListener.volume = value;
}
}
```
---
### TextMeshPro (Better Text Rendering)
```csharp
// Install: Window > TextMeshPro > Import TMP Essential Resources
// Use TMP_Text instead of Unity's Text component
using TMPro;
public TextMeshProUGUI tmpText;
tmpText.text = "High Quality Text";
tmpText.fontSize = 24;
tmpText.color = Color.white;
```
---
## Canvas Settings (UGUI)
### Render Modes
```csharp
// Screen Space - Overlay: UI rendered on top of everything (no camera needed)
// Screen Space - Camera: UI rendered by specific camera (allows effects)
// World Space: UI in 3D world (e.g., floating health bars)
```
### Canvas Scaler (Responsive UI)
```csharp
// UI Scale Mode:
// - Constant Pixel Size: UI elements have fixed pixel size
// - Scale With Screen Size: UI scales based on reference resolution (RECOMMENDED)
// - Constant Physical Size: UI elements have fixed physical size (cm)
// Example: Scale With Screen Size
// Reference Resolution: 1920x1080
// Screen Match Mode: Match Width Or Height (0.5 = balanced)
```
---
## Layout Groups (UGUI)
### Horizontal Layout Group
```csharp
// Auto-arranges children horizontally
// Add: GameObject > Add Component > Horizontal Layout Group
```
### Vertical Layout Group
```csharp
// Auto-arranges children vertically
```
### Grid Layout Group
```csharp
// Arranges children in a grid
```
---
## Performance (UI Toolkit vs UGUI)
### UI Toolkit Advantages
- ✅ Faster rendering (retained mode)
- ✅ Better for complex UIs with many elements
- ✅ Easier styling (CSS-like)
- ✅ Better for dynamic UIs
### UGUI Advantages
- ✅ More mature, widely documented
- ✅ Better integration with Unity Editor
- ✅ Easier for beginners
---
## Common Patterns
### Health Bar (UI Toolkit)
```csharp
var healthBar = root.Q<VisualElement>("health-bar");
healthBar.style.width = new StyleLength(new Length(healthPercent, LengthUnit.Percent));
```
### Health Bar (UGUI)
```csharp
public Image healthBarImage;
void UpdateHealth(float percent) {
healthBarImage.fillAmount = percent; // 0-1
}
```
---
### Fade In/Out (UI Toolkit)
```csharp
IEnumerator FadeIn(VisualElement element, float duration) {
float elapsed = 0f;
while (elapsed < duration) {
elapsed += Time.deltaTime;
element.style.opacity = Mathf.Lerp(0f, 1f, elapsed / duration);
yield return null;
}
}
```
---
## Debugging
### UI Toolkit Debugger
- `Window > UI Toolkit > Debugger`
- Inspect element hierarchy, styles, layout
### UGUI Event System Debugger
- Select EventSystem in Hierarchy
- Inspector shows active input module, raycast info
---
## Sources
- https://docs.unity3d.com/6000.0/Documentation/Manual/UIElements.html
- https://docs.unity3d.com/Packages/com.unity.ui@2.0/manual/index.html
- https://docs.unity3d.com/Packages/com.unity.ugui@2.0/manual/index.html