添加 claude code game studios 到项目
This commit is contained in:
334
docs/engine-reference/unity/current-best-practices.md
Normal file
334
docs/engine-reference/unity/current-best-practices.md
Normal file
@@ -0,0 +1,334 @@
|
||||
# Unity 6.3 LTS — Current Best Practices
|
||||
|
||||
**Last verified:** 2026-02-13
|
||||
|
||||
Modern Unity 6 patterns that may not be in the LLM's training data.
|
||||
These are production-ready recommendations as of Unity 6.3 LTS.
|
||||
|
||||
---
|
||||
|
||||
## Project Setup
|
||||
|
||||
### Use Unity 6.3 LTS for Production
|
||||
- **Tech Stream** (6.4+): Latest features, less stable
|
||||
- **LTS** (6.3): Production-ready, 2-year support (until Dec 2027)
|
||||
|
||||
### Choose the Right Render Pipeline
|
||||
- **URP (Universal)**: Mobile, cross-platform, good performance ✅ Recommended for most games
|
||||
- **HDRP (High Definition)**: High-end PC/console, photorealistic
|
||||
- **Built-in**: Deprecated, avoid for new projects
|
||||
|
||||
---
|
||||
|
||||
## Scripting
|
||||
|
||||
### Use C# 9+ Features (Unity 6 Supports C# 9)
|
||||
|
||||
```csharp
|
||||
// ✅ Record types for data
|
||||
public record PlayerData(string Name, int Level, float Health);
|
||||
|
||||
// ✅ Init-only properties
|
||||
public class Config {
|
||||
public string GameMode { get; init; }
|
||||
}
|
||||
|
||||
// ✅ Pattern matching
|
||||
var result = enemy switch {
|
||||
Boss boss => boss.Enrage(),
|
||||
Minion minion => minion.Flee(),
|
||||
_ => null
|
||||
};
|
||||
```
|
||||
|
||||
### Async/Await for Asset Loading
|
||||
|
||||
```csharp
|
||||
// ✅ Modern async pattern
|
||||
public async Task<GameObject> LoadEnemyAsync(string key) {
|
||||
var handle = Addressables.LoadAssetAsync<GameObject>(key);
|
||||
return await handle.Task;
|
||||
}
|
||||
```
|
||||
|
||||
### Use Source Generators for Serialization (Unity 6+)
|
||||
|
||||
```csharp
|
||||
// ✅ Source-generated serialization (faster, less reflection)
|
||||
[GenerateSerializer]
|
||||
public partial struct PlayerStats : IComponentData {
|
||||
public int Health;
|
||||
public int Mana;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DOTS/ECS (Production-Ready in Unity 6.3 LTS)
|
||||
|
||||
### Use ISystem (Not ComponentSystem)
|
||||
|
||||
```csharp
|
||||
// ✅ Modern unmanaged ISystem (Burst-compatible)
|
||||
public partial struct MovementSystem : ISystem {
|
||||
public void OnCreate(ref SystemState state) { }
|
||||
|
||||
public void OnUpdate(ref SystemState state) {
|
||||
foreach (var (transform, speed) in
|
||||
SystemAPI.Query<RefRW<LocalTransform>, RefRO<MoveSpeed>>()) {
|
||||
transform.ValueRW.Position += speed.ValueRO.Value * SystemAPI.Time.DeltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Use IJobEntity for Parallel Jobs
|
||||
|
||||
```csharp
|
||||
// ✅ IJobEntity (replaces IJobForEach)
|
||||
[BurstCompile]
|
||||
public partial struct DamageJob : IJobEntity {
|
||||
public float DeltaTime;
|
||||
|
||||
void Execute(ref Health health, in DamageOverTime dot) {
|
||||
health.Value -= dot.DamagePerSecond * DeltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule it
|
||||
var job = new DamageJob { DeltaTime = SystemAPI.Time.DeltaTime };
|
||||
job.ScheduleParallel();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Input
|
||||
|
||||
### Use Input System Package (Not Legacy Input)
|
||||
|
||||
```csharp
|
||||
// ✅ Input Actions (rebindable, cross-platform)
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class PlayerInput : MonoBehaviour {
|
||||
private PlayerControls controls;
|
||||
|
||||
void Awake() {
|
||||
controls = new PlayerControls();
|
||||
controls.Gameplay.Jump.performed += ctx => Jump();
|
||||
}
|
||||
|
||||
void OnEnable() => controls.Enable();
|
||||
void OnDisable() => controls.Disable();
|
||||
}
|
||||
```
|
||||
|
||||
Create Input Actions asset in editor, generate C# class via inspector.
|
||||
|
||||
---
|
||||
|
||||
## UI
|
||||
|
||||
### Use UI Toolkit for Runtime UI (Production-Ready in Unity 6)
|
||||
|
||||
```csharp
|
||||
// ✅ UI Toolkit (replaces UGUI for new projects)
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public class MainMenu : MonoBehaviour {
|
||||
void OnEnable() {
|
||||
var root = GetComponent<UIDocument>().rootVisualElement;
|
||||
|
||||
var playButton = root.Q<Button>("play-button");
|
||||
playButton.clicked += StartGame;
|
||||
|
||||
var scoreLabel = root.Q<Label>("score");
|
||||
scoreLabel.text = $"High Score: {PlayerPrefs.GetInt("HighScore")}";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**UXML** (UI structure) + **USS** (styling) = HTML/CSS-like workflow.
|
||||
|
||||
---
|
||||
|
||||
## Asset Management
|
||||
|
||||
### Use Addressables (Not Resources)
|
||||
|
||||
```csharp
|
||||
// ✅ Addressables (async, memory-efficient)
|
||||
using UnityEngine.AddressableAssets;
|
||||
|
||||
public async Task SpawnEnemyAsync(string enemyKey) {
|
||||
var handle = Addressables.InstantiateAsync(enemyKey);
|
||||
var enemy = await handle.Task;
|
||||
|
||||
// Cleanup: release when destroyed
|
||||
Addressables.ReleaseInstance(enemy);
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:** Async loading, remote content delivery, better memory control.
|
||||
|
||||
---
|
||||
|
||||
## Rendering
|
||||
|
||||
### Use RenderGraph API for Custom Passes (URP/HDRP)
|
||||
|
||||
```csharp
|
||||
// ✅ RenderGraph API (Unity 6+)
|
||||
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) {
|
||||
using (var builder = renderGraph.AddRasterRenderPass<PassData>("My Pass", out var passData)) {
|
||||
// Setup pass
|
||||
builder.SetRenderFunc((PassData data, RasterGraphContext context) => {
|
||||
// Execute commands
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Replaces:** Old `CommandBuffer.Execute()` pattern.
|
||||
|
||||
---
|
||||
|
||||
## Performance
|
||||
|
||||
### Use Burst Compiler + Jobs System
|
||||
|
||||
```csharp
|
||||
// ✅ Burst-compiled job (massive performance gain)
|
||||
[BurstCompile]
|
||||
struct ParticleUpdateJob : IJobParallelFor {
|
||||
public NativeArray<float3> Positions;
|
||||
public NativeArray<float3> Velocities;
|
||||
public float DeltaTime;
|
||||
|
||||
public void Execute(int index) {
|
||||
Positions[index] += Velocities[index] * DeltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule
|
||||
var job = new ParticleUpdateJob {
|
||||
Positions = positions,
|
||||
Velocities = velocities,
|
||||
DeltaTime = Time.deltaTime
|
||||
};
|
||||
job.Schedule(positions.Length, 64).Complete();
|
||||
```
|
||||
|
||||
**20-100x faster** than equivalent C# code.
|
||||
|
||||
---
|
||||
|
||||
### Use GPU Instancing for Repeated Objects
|
||||
|
||||
```csharp
|
||||
// ✅ GPU Instancing (thousands of objects, minimal draw calls)
|
||||
Graphics.RenderMeshInstanced(
|
||||
new RenderParams(material),
|
||||
mesh,
|
||||
0,
|
||||
matrices // NativeArray<Matrix4x4>
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Memory Management
|
||||
|
||||
### Use NativeContainers (Not Managed Arrays in Jobs)
|
||||
|
||||
```csharp
|
||||
// ✅ NativeArray (no GC, Burst-compatible)
|
||||
NativeArray<int> data = new NativeArray<int>(1000, Allocator.TempJob);
|
||||
// ... use in job
|
||||
data.Dispose(); // Manual cleanup required
|
||||
|
||||
// ✅ Or use using statement
|
||||
using var data = new NativeArray<int>(1000, Allocator.TempJob);
|
||||
// Auto-disposed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Multiplayer
|
||||
|
||||
### Use Netcode for GameObjects (Official)
|
||||
|
||||
```csharp
|
||||
// ✅ Unity's official netcode
|
||||
using Unity.Netcode;
|
||||
|
||||
public class Player : NetworkBehaviour {
|
||||
private NetworkVariable<int> health = new NetworkVariable<int>(100);
|
||||
|
||||
[ServerRpc]
|
||||
public void TakeDamageServerRpc(int damage) {
|
||||
health.Value -= damage;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Replaces:** UNet (deprecated), MLAPI (renamed to Netcode for GameObjects).
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
### Use Unity Test Framework (NUnit-based)
|
||||
|
||||
```csharp
|
||||
// ✅ Play Mode Test
|
||||
[UnityTest]
|
||||
public IEnumerator Player_TakesDamage_HealthDecreases() {
|
||||
var player = new GameObject().AddComponent<Player>();
|
||||
player.Health = 100;
|
||||
|
||||
player.TakeDamage(25);
|
||||
yield return null; // Wait one frame
|
||||
|
||||
Assert.AreEqual(75, player.Health);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Debugging
|
||||
|
||||
### Use Logging Best Practices
|
||||
|
||||
```csharp
|
||||
// ✅ Structured logging (Unity 6+)
|
||||
using UnityEngine;
|
||||
|
||||
Debug.Log($"Player {playerName} scored {score} points");
|
||||
|
||||
// ✅ Conditional compilation for debug code
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
Debug.DrawRay(transform.position, direction, Color.red);
|
||||
#endif
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary: Unity 6 Tech Stack
|
||||
|
||||
| Feature | Use This (2026) | Avoid This (Legacy) |
|
||||
|---------|------------------|----------------------|
|
||||
| **Input** | Input System package | `Input` class |
|
||||
| **UI** | UI Toolkit | UGUI (Canvas) |
|
||||
| **ECS** | ISystem + IJobEntity | ComponentSystem |
|
||||
| **Rendering** | URP + RenderGraph | Built-in pipeline |
|
||||
| **Assets** | Addressables | Resources |
|
||||
| **Jobs** | Burst + IJobParallelFor | Coroutines for heavy work |
|
||||
| **Multiplayer** | Netcode for GameObjects | UNet |
|
||||
|
||||
---
|
||||
|
||||
**Sources:**
|
||||
- https://docs.unity3d.com/6000.0/Documentation/Manual/BestPracticeGuides.html
|
||||
- https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/index.html
|
||||
- https://docs.unity3d.com/Packages/com.unity.inputsystem@1.11/manual/index.html
|
||||
Reference in New Issue
Block a user