omgkit 2.13.0 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -10
- package/package.json +2 -2
- package/plugin/agents/api-designer.md +5 -0
- package/plugin/agents/architect.md +8 -0
- package/plugin/agents/brainstormer.md +4 -0
- package/plugin/agents/cicd-manager.md +6 -0
- package/plugin/agents/code-reviewer.md +6 -0
- package/plugin/agents/copywriter.md +2 -0
- package/plugin/agents/data-engineer.md +255 -0
- package/plugin/agents/database-admin.md +10 -0
- package/plugin/agents/debugger.md +10 -0
- package/plugin/agents/devsecops.md +314 -0
- package/plugin/agents/docs-manager.md +4 -0
- package/plugin/agents/domain-decomposer.md +181 -0
- package/plugin/agents/embedded-systems.md +397 -0
- package/plugin/agents/fullstack-developer.md +12 -0
- package/plugin/agents/game-systems-designer.md +375 -0
- package/plugin/agents/git-manager.md +10 -0
- package/plugin/agents/journal-writer.md +2 -0
- package/plugin/agents/ml-engineer.md +284 -0
- package/plugin/agents/observability-engineer.md +353 -0
- package/plugin/agents/oracle.md +9 -0
- package/plugin/agents/performance-engineer.md +290 -0
- package/plugin/agents/pipeline-architect.md +6 -0
- package/plugin/agents/planner.md +12 -0
- package/plugin/agents/platform-engineer.md +325 -0
- package/plugin/agents/project-manager.md +3 -0
- package/plugin/agents/researcher.md +5 -0
- package/plugin/agents/scientific-computing.md +426 -0
- package/plugin/agents/scout.md +3 -0
- package/plugin/agents/security-auditor.md +7 -0
- package/plugin/agents/sprint-master.md +17 -0
- package/plugin/agents/tester.md +10 -0
- package/plugin/agents/ui-ux-designer.md +12 -0
- package/plugin/agents/vulnerability-scanner.md +6 -0
- package/plugin/commands/data/pipeline.md +47 -0
- package/plugin/commands/data/quality.md +49 -0
- package/plugin/commands/domain/analyze.md +34 -0
- package/plugin/commands/domain/map.md +41 -0
- package/plugin/commands/game/balance.md +56 -0
- package/plugin/commands/game/optimize.md +62 -0
- package/plugin/commands/iot/provision.md +58 -0
- package/plugin/commands/ml/evaluate.md +47 -0
- package/plugin/commands/ml/train.md +48 -0
- package/plugin/commands/perf/benchmark.md +54 -0
- package/plugin/commands/perf/profile.md +49 -0
- package/plugin/commands/platform/blueprint.md +56 -0
- package/plugin/commands/security/audit.md +54 -0
- package/plugin/commands/security/scan.md +55 -0
- package/plugin/commands/sre/dashboard.md +53 -0
- package/plugin/registry.yaml +711 -0
- package/plugin/skills/ai-ml/experiment-tracking/SKILL.md +338 -0
- package/plugin/skills/ai-ml/feature-stores/SKILL.md +340 -0
- package/plugin/skills/ai-ml/llm-ops/SKILL.md +454 -0
- package/plugin/skills/ai-ml/ml-pipelines/SKILL.md +390 -0
- package/plugin/skills/ai-ml/model-monitoring/SKILL.md +398 -0
- package/plugin/skills/ai-ml/model-serving/SKILL.md +386 -0
- package/plugin/skills/event-driven/cqrs-patterns/SKILL.md +348 -0
- package/plugin/skills/event-driven/event-sourcing/SKILL.md +334 -0
- package/plugin/skills/event-driven/kafka-deep/SKILL.md +252 -0
- package/plugin/skills/event-driven/saga-orchestration/SKILL.md +335 -0
- package/plugin/skills/event-driven/schema-registry/SKILL.md +328 -0
- package/plugin/skills/event-driven/stream-processing/SKILL.md +313 -0
- package/plugin/skills/game/game-audio/SKILL.md +446 -0
- package/plugin/skills/game/game-networking/SKILL.md +490 -0
- package/plugin/skills/game/godot-patterns/SKILL.md +413 -0
- package/plugin/skills/game/shader-programming/SKILL.md +492 -0
- package/plugin/skills/game/unity-patterns/SKILL.md +488 -0
- package/plugin/skills/iot/device-provisioning/SKILL.md +405 -0
- package/plugin/skills/iot/edge-computing/SKILL.md +369 -0
- package/plugin/skills/iot/industrial-protocols/SKILL.md +438 -0
- package/plugin/skills/iot/mqtt-deep/SKILL.md +418 -0
- package/plugin/skills/iot/ota-updates/SKILL.md +426 -0
- package/plugin/skills/microservices/api-gateway-patterns/SKILL.md +201 -0
- package/plugin/skills/microservices/circuit-breaker-patterns/SKILL.md +246 -0
- package/plugin/skills/microservices/contract-testing/SKILL.md +284 -0
- package/plugin/skills/microservices/distributed-tracing/SKILL.md +246 -0
- package/plugin/skills/microservices/service-discovery/SKILL.md +304 -0
- package/plugin/skills/microservices/service-mesh/SKILL.md +181 -0
- package/plugin/skills/mobile-advanced/mobile-ci-cd/SKILL.md +407 -0
- package/plugin/skills/mobile-advanced/mobile-security/SKILL.md +403 -0
- package/plugin/skills/mobile-advanced/offline-first/SKILL.md +473 -0
- package/plugin/skills/mobile-advanced/push-notifications/SKILL.md +494 -0
- package/plugin/skills/mobile-advanced/react-native-deep/SKILL.md +374 -0
- package/plugin/skills/simulation/numerical-methods/SKILL.md +434 -0
- package/plugin/skills/simulation/parallel-computing/SKILL.md +382 -0
- package/plugin/skills/simulation/physics-engines/SKILL.md +377 -0
- package/plugin/skills/simulation/validation-verification/SKILL.md +479 -0
- package/plugin/skills/simulation/visualization-scientific/SKILL.md +365 -0
- package/plugin/workflows/ai-engineering/agent-development.md +3 -3
- package/plugin/workflows/ai-engineering/fine-tuning.md +3 -3
- package/plugin/workflows/ai-engineering/model-evaluation.md +3 -3
- package/plugin/workflows/ai-engineering/prompt-engineering.md +2 -2
- package/plugin/workflows/ai-engineering/rag-development.md +4 -4
- package/plugin/workflows/ai-ml/data-pipeline.md +188 -0
- package/plugin/workflows/ai-ml/experiment-cycle.md +203 -0
- package/plugin/workflows/ai-ml/feature-engineering.md +208 -0
- package/plugin/workflows/ai-ml/model-deployment.md +199 -0
- package/plugin/workflows/ai-ml/monitoring-setup.md +227 -0
- package/plugin/workflows/api/api-design.md +1 -1
- package/plugin/workflows/api/api-testing.md +2 -2
- package/plugin/workflows/content/technical-docs.md +1 -1
- package/plugin/workflows/database/migration.md +1 -1
- package/plugin/workflows/database/optimization.md +1 -1
- package/plugin/workflows/database/schema-design.md +3 -3
- package/plugin/workflows/development/bug-fix.md +3 -3
- package/plugin/workflows/development/code-review.md +2 -1
- package/plugin/workflows/development/feature.md +3 -3
- package/plugin/workflows/development/refactor.md +2 -2
- package/plugin/workflows/event-driven/consumer-groups.md +190 -0
- package/plugin/workflows/event-driven/event-storming.md +172 -0
- package/plugin/workflows/event-driven/replay-testing.md +186 -0
- package/plugin/workflows/event-driven/saga-implementation.md +206 -0
- package/plugin/workflows/event-driven/schema-evolution.md +173 -0
- package/plugin/workflows/fullstack/authentication.md +4 -4
- package/plugin/workflows/fullstack/full-feature.md +4 -4
- package/plugin/workflows/game-dev/content-pipeline.md +218 -0
- package/plugin/workflows/game-dev/platform-submission.md +263 -0
- package/plugin/workflows/game-dev/playtesting.md +237 -0
- package/plugin/workflows/game-dev/prototype-to-production.md +205 -0
- package/plugin/workflows/microservices/contract-first.md +151 -0
- package/plugin/workflows/microservices/distributed-tracing.md +166 -0
- package/plugin/workflows/microservices/domain-decomposition.md +123 -0
- package/plugin/workflows/microservices/integration-testing.md +149 -0
- package/plugin/workflows/microservices/service-mesh-setup.md +153 -0
- package/plugin/workflows/microservices/service-scaffolding.md +151 -0
- package/plugin/workflows/omega/1000x-innovation.md +2 -2
- package/plugin/workflows/omega/100x-architecture.md +2 -2
- package/plugin/workflows/omega/10x-improvement.md +2 -2
- package/plugin/workflows/quality/performance-optimization.md +2 -2
- package/plugin/workflows/research/best-practices.md +1 -1
- package/plugin/workflows/research/technology-research.md +1 -1
- package/plugin/workflows/security/penetration-testing.md +3 -3
- package/plugin/workflows/security/security-audit.md +3 -3
- package/plugin/workflows/sprint/sprint-execution.md +2 -2
- package/plugin/workflows/sprint/sprint-retrospective.md +1 -1
- package/plugin/workflows/sprint/sprint-setup.md +1 -1
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
# Unity Patterns
|
|
2
|
+
|
|
3
|
+
Unity game architecture patterns including ECS, ScriptableObjects, object pooling, and performance optimization.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Unity development patterns provide scalable, maintainable game architectures that optimize performance and enable team collaboration.
|
|
8
|
+
|
|
9
|
+
## Core Concepts
|
|
10
|
+
|
|
11
|
+
### Architecture Approaches
|
|
12
|
+
- **MonoBehaviour**: Traditional Unity component
|
|
13
|
+
- **ScriptableObjects**: Data containers, assets
|
|
14
|
+
- **ECS (DOTS)**: Data-oriented, high performance
|
|
15
|
+
- **Hybrid**: Mix of approaches
|
|
16
|
+
|
|
17
|
+
### Design Patterns in Unity
|
|
18
|
+
- Singleton (Service Locator)
|
|
19
|
+
- Object Pool
|
|
20
|
+
- State Machine
|
|
21
|
+
- Observer (Events)
|
|
22
|
+
- Command Pattern
|
|
23
|
+
|
|
24
|
+
## ScriptableObjects Architecture
|
|
25
|
+
|
|
26
|
+
### Data Definition
|
|
27
|
+
```csharp
|
|
28
|
+
// Weapon data container
|
|
29
|
+
[CreateAssetMenu(fileName = "NewWeapon", menuName = "Game/Weapons/Weapon Data")]
|
|
30
|
+
public class WeaponData : ScriptableObject
|
|
31
|
+
{
|
|
32
|
+
[Header("Basic Info")]
|
|
33
|
+
public string weaponName;
|
|
34
|
+
public Sprite icon;
|
|
35
|
+
public GameObject prefab;
|
|
36
|
+
|
|
37
|
+
[Header("Stats")]
|
|
38
|
+
public float damage;
|
|
39
|
+
public float attackSpeed;
|
|
40
|
+
public float range;
|
|
41
|
+
|
|
42
|
+
[Header("Audio")]
|
|
43
|
+
public AudioClip attackSound;
|
|
44
|
+
public AudioClip hitSound;
|
|
45
|
+
|
|
46
|
+
public float DPS => damage * attackSpeed;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Character stats
|
|
50
|
+
[CreateAssetMenu(fileName = "NewCharacter", menuName = "Game/Characters/Character Data")]
|
|
51
|
+
public class CharacterData : ScriptableObject
|
|
52
|
+
{
|
|
53
|
+
public string characterName;
|
|
54
|
+
public int maxHealth;
|
|
55
|
+
public float moveSpeed;
|
|
56
|
+
public WeaponData defaultWeapon;
|
|
57
|
+
|
|
58
|
+
[SerializeField] private AnimatorOverrideController animatorOverride;
|
|
59
|
+
|
|
60
|
+
public void ApplyTo(Character character)
|
|
61
|
+
{
|
|
62
|
+
character.MaxHealth = maxHealth;
|
|
63
|
+
character.MoveSpeed = moveSpeed;
|
|
64
|
+
character.EquipWeapon(defaultWeapon);
|
|
65
|
+
if (animatorOverride != null)
|
|
66
|
+
character.Animator.runtimeAnimatorController = animatorOverride;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Event System with ScriptableObjects
|
|
72
|
+
```csharp
|
|
73
|
+
// Game event (no parameters)
|
|
74
|
+
[CreateAssetMenu(menuName = "Events/Game Event")]
|
|
75
|
+
public class GameEvent : ScriptableObject
|
|
76
|
+
{
|
|
77
|
+
private readonly List<GameEventListener> listeners = new();
|
|
78
|
+
|
|
79
|
+
public void Raise()
|
|
80
|
+
{
|
|
81
|
+
for (int i = listeners.Count - 1; i >= 0; i--)
|
|
82
|
+
listeners[i].OnEventRaised();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public void RegisterListener(GameEventListener listener) => listeners.Add(listener);
|
|
86
|
+
public void UnregisterListener(GameEventListener listener) => listeners.Remove(listener);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Listener component
|
|
90
|
+
public class GameEventListener : MonoBehaviour
|
|
91
|
+
{
|
|
92
|
+
public GameEvent gameEvent;
|
|
93
|
+
public UnityEvent response;
|
|
94
|
+
|
|
95
|
+
private void OnEnable() => gameEvent.RegisterListener(this);
|
|
96
|
+
private void OnDisable() => gameEvent.UnregisterListener(this);
|
|
97
|
+
public void OnEventRaised() => response.Invoke();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Generic event with parameter
|
|
101
|
+
[CreateAssetMenu(menuName = "Events/Int Event")]
|
|
102
|
+
public class IntEvent : ScriptableObject
|
|
103
|
+
{
|
|
104
|
+
private readonly List<IntEventListener> listeners = new();
|
|
105
|
+
|
|
106
|
+
public void Raise(int value)
|
|
107
|
+
{
|
|
108
|
+
foreach (var listener in listeners)
|
|
109
|
+
listener.OnEventRaised(value);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public void RegisterListener(IntEventListener listener) => listeners.Add(listener);
|
|
113
|
+
public void UnregisterListener(IntEventListener listener) => listeners.Remove(listener);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Object Pooling
|
|
118
|
+
|
|
119
|
+
### Generic Pool System
|
|
120
|
+
```csharp
|
|
121
|
+
public class ObjectPool<T> where T : Component
|
|
122
|
+
{
|
|
123
|
+
private readonly T prefab;
|
|
124
|
+
private readonly Transform parent;
|
|
125
|
+
private readonly Queue<T> pool = new();
|
|
126
|
+
private readonly HashSet<T> active = new();
|
|
127
|
+
private readonly int maxSize;
|
|
128
|
+
|
|
129
|
+
public ObjectPool(T prefab, Transform parent, int initialSize, int maxSize = 100)
|
|
130
|
+
{
|
|
131
|
+
this.prefab = prefab;
|
|
132
|
+
this.parent = parent;
|
|
133
|
+
this.maxSize = maxSize;
|
|
134
|
+
|
|
135
|
+
for (int i = 0; i < initialSize; i++)
|
|
136
|
+
CreateInstance();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private T CreateInstance()
|
|
140
|
+
{
|
|
141
|
+
var instance = Object.Instantiate(prefab, parent);
|
|
142
|
+
instance.gameObject.SetActive(false);
|
|
143
|
+
pool.Enqueue(instance);
|
|
144
|
+
return instance;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public T Get()
|
|
148
|
+
{
|
|
149
|
+
T instance;
|
|
150
|
+
|
|
151
|
+
if (pool.Count > 0)
|
|
152
|
+
{
|
|
153
|
+
instance = pool.Dequeue();
|
|
154
|
+
}
|
|
155
|
+
else if (active.Count < maxSize)
|
|
156
|
+
{
|
|
157
|
+
instance = CreateInstance();
|
|
158
|
+
pool.Dequeue();
|
|
159
|
+
}
|
|
160
|
+
else
|
|
161
|
+
{
|
|
162
|
+
Debug.LogWarning($"Pool exhausted for {prefab.name}");
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
instance.gameObject.SetActive(true);
|
|
167
|
+
active.Add(instance);
|
|
168
|
+
return instance;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public void Return(T instance)
|
|
172
|
+
{
|
|
173
|
+
if (!active.Contains(instance)) return;
|
|
174
|
+
|
|
175
|
+
instance.gameObject.SetActive(false);
|
|
176
|
+
active.Remove(instance);
|
|
177
|
+
pool.Enqueue(instance);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public void ReturnAll()
|
|
181
|
+
{
|
|
182
|
+
foreach (var instance in active.ToList())
|
|
183
|
+
Return(instance);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Poolable interface
|
|
188
|
+
public interface IPoolable
|
|
189
|
+
{
|
|
190
|
+
void OnSpawn();
|
|
191
|
+
void OnDespawn();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Usage example
|
|
195
|
+
public class BulletPool : MonoBehaviour
|
|
196
|
+
{
|
|
197
|
+
[SerializeField] private Bullet bulletPrefab;
|
|
198
|
+
[SerializeField] private int poolSize = 50;
|
|
199
|
+
|
|
200
|
+
private ObjectPool<Bullet> pool;
|
|
201
|
+
|
|
202
|
+
private void Awake()
|
|
203
|
+
{
|
|
204
|
+
pool = new ObjectPool<Bullet>(bulletPrefab, transform, poolSize);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
public Bullet SpawnBullet(Vector3 position, Quaternion rotation)
|
|
208
|
+
{
|
|
209
|
+
var bullet = pool.Get();
|
|
210
|
+
if (bullet == null) return null;
|
|
211
|
+
|
|
212
|
+
bullet.transform.SetPositionAndRotation(position, rotation);
|
|
213
|
+
bullet.Initialize(this);
|
|
214
|
+
return bullet;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
public void ReturnBullet(Bullet bullet) => pool.Return(bullet);
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## State Machine
|
|
222
|
+
|
|
223
|
+
### Hierarchical State Machine
|
|
224
|
+
```csharp
|
|
225
|
+
public interface IState
|
|
226
|
+
{
|
|
227
|
+
void Enter();
|
|
228
|
+
void Exit();
|
|
229
|
+
void Update();
|
|
230
|
+
void FixedUpdate();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
public abstract class State : IState
|
|
234
|
+
{
|
|
235
|
+
protected StateMachine stateMachine;
|
|
236
|
+
protected readonly float startTime;
|
|
237
|
+
|
|
238
|
+
protected State(StateMachine stateMachine)
|
|
239
|
+
{
|
|
240
|
+
this.stateMachine = stateMachine;
|
|
241
|
+
startTime = Time.time;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
public virtual void Enter() { }
|
|
245
|
+
public virtual void Exit() { }
|
|
246
|
+
public virtual void Update() { }
|
|
247
|
+
public virtual void FixedUpdate() { }
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
public class StateMachine
|
|
251
|
+
{
|
|
252
|
+
public IState CurrentState { get; private set; }
|
|
253
|
+
private readonly Dictionary<Type, IState> states = new();
|
|
254
|
+
|
|
255
|
+
public void AddState(IState state)
|
|
256
|
+
{
|
|
257
|
+
states[state.GetType()] = state;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
public void ChangeState<T>() where T : IState
|
|
261
|
+
{
|
|
262
|
+
CurrentState?.Exit();
|
|
263
|
+
CurrentState = states[typeof(T)];
|
|
264
|
+
CurrentState.Enter();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
public void Update() => CurrentState?.Update();
|
|
268
|
+
public void FixedUpdate() => CurrentState?.FixedUpdate();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Character states
|
|
272
|
+
public class IdleState : State
|
|
273
|
+
{
|
|
274
|
+
private readonly CharacterController character;
|
|
275
|
+
|
|
276
|
+
public IdleState(StateMachine sm, CharacterController character) : base(sm)
|
|
277
|
+
{
|
|
278
|
+
this.character = character;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
public override void Enter()
|
|
282
|
+
{
|
|
283
|
+
character.Animator.Play("Idle");
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
public override void Update()
|
|
287
|
+
{
|
|
288
|
+
if (character.Input.Movement.magnitude > 0.1f)
|
|
289
|
+
stateMachine.ChangeState<MoveState>();
|
|
290
|
+
|
|
291
|
+
if (character.Input.Attack)
|
|
292
|
+
stateMachine.ChangeState<AttackState>();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## ECS (DOTS) Basics
|
|
298
|
+
|
|
299
|
+
### Component Definition
|
|
300
|
+
```csharp
|
|
301
|
+
using Unity.Entities;
|
|
302
|
+
using Unity.Mathematics;
|
|
303
|
+
|
|
304
|
+
// Component data
|
|
305
|
+
public struct Position : IComponentData
|
|
306
|
+
{
|
|
307
|
+
public float3 Value;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
public struct Velocity : IComponentData
|
|
311
|
+
{
|
|
312
|
+
public float3 Value;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
public struct Health : IComponentData
|
|
316
|
+
{
|
|
317
|
+
public float Current;
|
|
318
|
+
public float Max;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Buffer element
|
|
322
|
+
[InternalBufferCapacity(8)]
|
|
323
|
+
public struct DamageBuffer : IBufferElementData
|
|
324
|
+
{
|
|
325
|
+
public float Amount;
|
|
326
|
+
public Entity Source;
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### System Implementation
|
|
331
|
+
```csharp
|
|
332
|
+
using Unity.Burst;
|
|
333
|
+
using Unity.Entities;
|
|
334
|
+
using Unity.Jobs;
|
|
335
|
+
using Unity.Transforms;
|
|
336
|
+
|
|
337
|
+
[BurstCompile]
|
|
338
|
+
public partial struct MovementSystem : ISystem
|
|
339
|
+
{
|
|
340
|
+
[BurstCompile]
|
|
341
|
+
public void OnUpdate(ref SystemState state)
|
|
342
|
+
{
|
|
343
|
+
float deltaTime = SystemAPI.Time.DeltaTime;
|
|
344
|
+
|
|
345
|
+
new MoveJob { DeltaTime = deltaTime }.ScheduleParallel();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
[BurstCompile]
|
|
349
|
+
partial struct MoveJob : IJobEntity
|
|
350
|
+
{
|
|
351
|
+
public float DeltaTime;
|
|
352
|
+
|
|
353
|
+
void Execute(ref LocalTransform transform, in Velocity velocity)
|
|
354
|
+
{
|
|
355
|
+
transform.Position += velocity.Value * DeltaTime;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
[BurstCompile]
|
|
361
|
+
public partial struct DamageSystem : ISystem
|
|
362
|
+
{
|
|
363
|
+
[BurstCompile]
|
|
364
|
+
public void OnUpdate(ref SystemState state)
|
|
365
|
+
{
|
|
366
|
+
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
|
367
|
+
|
|
368
|
+
foreach (var (health, damageBuffer, entity) in
|
|
369
|
+
SystemAPI.Query<RefRW<Health>, DynamicBuffer<DamageBuffer>>()
|
|
370
|
+
.WithEntityAccess())
|
|
371
|
+
{
|
|
372
|
+
foreach (var damage in damageBuffer)
|
|
373
|
+
{
|
|
374
|
+
health.ValueRW.Current -= damage.Amount;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
damageBuffer.Clear();
|
|
378
|
+
|
|
379
|
+
if (health.ValueRO.Current <= 0)
|
|
380
|
+
{
|
|
381
|
+
ecb.DestroyEntity(entity);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
ecb.Playback(state.EntityManager);
|
|
386
|
+
ecb.Dispose();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
## Performance Optimization
|
|
392
|
+
|
|
393
|
+
### Update Optimization
|
|
394
|
+
```csharp
|
|
395
|
+
public class OptimizedUpdater : MonoBehaviour
|
|
396
|
+
{
|
|
397
|
+
private static readonly List<IUpdatable> updatables = new();
|
|
398
|
+
private static readonly List<IFixedUpdatable> fixedUpdatables = new();
|
|
399
|
+
|
|
400
|
+
public static void Register(IUpdatable updatable) => updatables.Add(updatable);
|
|
401
|
+
public static void Unregister(IUpdatable updatable) => updatables.Remove(updatable);
|
|
402
|
+
|
|
403
|
+
private void Update()
|
|
404
|
+
{
|
|
405
|
+
float deltaTime = Time.deltaTime;
|
|
406
|
+
for (int i = 0; i < updatables.Count; i++)
|
|
407
|
+
updatables[i].OnUpdate(deltaTime);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
private void FixedUpdate()
|
|
411
|
+
{
|
|
412
|
+
float fixedDeltaTime = Time.fixedDeltaTime;
|
|
413
|
+
for (int i = 0; i < fixedUpdatables.Count; i++)
|
|
414
|
+
fixedUpdatables[i].OnFixedUpdate(fixedDeltaTime);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
public interface IUpdatable
|
|
419
|
+
{
|
|
420
|
+
void OnUpdate(float deltaTime);
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Memory Optimization
|
|
425
|
+
```csharp
|
|
426
|
+
// Avoid allocations in Update
|
|
427
|
+
public class NoAllocExample : MonoBehaviour
|
|
428
|
+
{
|
|
429
|
+
// Cache references
|
|
430
|
+
private Transform cachedTransform;
|
|
431
|
+
private Rigidbody cachedRigidbody;
|
|
432
|
+
|
|
433
|
+
// Pre-allocate arrays
|
|
434
|
+
private readonly Collider[] hitResults = new Collider[32];
|
|
435
|
+
private readonly RaycastHit[] rayResults = new RaycastHit[16];
|
|
436
|
+
|
|
437
|
+
// Use StringBuilder for strings
|
|
438
|
+
private readonly StringBuilder stringBuilder = new(256);
|
|
439
|
+
|
|
440
|
+
private void Awake()
|
|
441
|
+
{
|
|
442
|
+
cachedTransform = transform;
|
|
443
|
+
cachedRigidbody = GetComponent<Rigidbody>();
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
private void Update()
|
|
447
|
+
{
|
|
448
|
+
// Non-allocating physics
|
|
449
|
+
int hitCount = Physics.OverlapSphereNonAlloc(
|
|
450
|
+
cachedTransform.position, 5f, hitResults);
|
|
451
|
+
|
|
452
|
+
for (int i = 0; i < hitCount; i++)
|
|
453
|
+
{
|
|
454
|
+
ProcessHit(hitResults[i]);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
## Best Practices
|
|
461
|
+
|
|
462
|
+
1. **Use ScriptableObjects**: Data-driven design
|
|
463
|
+
2. **Pool Everything**: Reuse instantiated objects
|
|
464
|
+
3. **Cache Components**: GetComponent is expensive
|
|
465
|
+
4. **Avoid Update**: Use events when possible
|
|
466
|
+
5. **Profile Regularly**: Use Unity Profiler
|
|
467
|
+
|
|
468
|
+
## Anti-Patterns
|
|
469
|
+
|
|
470
|
+
- Singleton overuse
|
|
471
|
+
- Find/GetComponent in Update
|
|
472
|
+
- String comparisons for tags
|
|
473
|
+
- Allocations in hot paths
|
|
474
|
+
- Deep inheritance hierarchies
|
|
475
|
+
|
|
476
|
+
## When to Use
|
|
477
|
+
|
|
478
|
+
- Any Unity game project
|
|
479
|
+
- Team collaboration needed
|
|
480
|
+
- Performance-critical games
|
|
481
|
+
- Data-driven game design
|
|
482
|
+
- Scalable architecture
|
|
483
|
+
|
|
484
|
+
## When NOT to Use
|
|
485
|
+
|
|
486
|
+
- Very simple prototypes
|
|
487
|
+
- Game jams (may be overkill)
|
|
488
|
+
- Learning Unity basics
|