@su-record/vibe 2.4.55 โ 2.4.57
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/CLAUDE.md +7 -18
- package/agents/compounder.md +1 -1
- package/agents/implementer.md +2 -1
- package/agents/simplifier.md +2 -1
- package/commands/vibe.run.md +26 -27
- package/commands/vibe.spec.md +84 -40
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +0 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/postinstall.js +32 -1
- package/dist/cli/postinstall.js.map +1 -1
- package/dist/cli/setup.d.ts +18 -4
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +87 -27
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/types.d.ts +6 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/languages/csharp-unity.md +516 -0
- package/languages/gdscript-godot.md +470 -0
- package/languages/ruby-rails.md +489 -0
- package/languages/typescript-angular.md +433 -0
- package/languages/typescript-astro.md +416 -0
- package/languages/typescript-electron.md +407 -0
- package/languages/typescript-nestjs.md +524 -0
- package/languages/typescript-svelte.md +407 -0
- package/languages/typescript-tauri.md +366 -0
- package/package.json +1 -1
- package/skills/vibe-capabilities.md +1 -1
- package/vibe/constitution.md +130 -97
- package/vibe/rules/core/communication-guide.md +50 -56
- package/vibe/rules/core/development-philosophy.md +35 -36
- package/vibe/rules/core/quick-start.md +66 -85
- package/vibe/rules/quality/bdd-contract-testing.md +94 -89
- package/vibe/rules/quality/checklist.md +132 -132
- package/vibe/rules/quality/testing-strategy.md +132 -129
- package/vibe/rules/standards/anti-patterns.md +74 -74
- package/vibe/rules/standards/code-structure.md +44 -44
- package/vibe/rules/standards/complexity-metrics.md +63 -62
- package/vibe/rules/standards/naming-conventions.md +72 -72
- package/vibe/templates/constitution-template.md +153 -95
- package/vibe/templates/contract-backend-template.md +41 -32
- package/vibe/templates/contract-frontend-template.md +35 -30
- package/vibe/templates/feature-template.md +33 -33
- package/vibe/templates/spec-template.md +118 -96
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
# ๐ฎ C# + Unity ํ์ง ๊ท์น
|
|
2
|
+
|
|
3
|
+
## ํต์ฌ ์์น (core์์ ์์)
|
|
4
|
+
|
|
5
|
+
```markdown
|
|
6
|
+
โ
๋จ์ผ ์ฑ
์ (SRP)
|
|
7
|
+
โ
์ค๋ณต ์ ๊ฑฐ (DRY)
|
|
8
|
+
โ
์ฌ์ฌ์ฉ์ฑ
|
|
9
|
+
โ
๋ฎ์ ๋ณต์ก๋
|
|
10
|
+
โ
ํจ์ โค 30์ค
|
|
11
|
+
โ
์ค์ฒฉ โค 3๋จ๊ณ
|
|
12
|
+
โ
Cyclomatic complexity โค 10
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Unity ์ํคํ
์ฒ ์ดํด
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
19
|
+
โ MonoBehaviour Lifecycle โ
|
|
20
|
+
โ Awake โ OnEnable โ Start โ Update โ ... โ
|
|
21
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
22
|
+
โ ScriptableObject (๋ฐ์ดํฐ ์์
) โ
|
|
23
|
+
โ - ์ค์ , ์ด๋ฒคํธ, ๊ณต์ ๋ฐ์ดํฐ โ
|
|
24
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
25
|
+
โ Pure C# Classes (๋น-MonoBehaviour) โ
|
|
26
|
+
โ - ๊ฒ์ ๋ก์ง, ์ ํธ๋ฆฌํฐ โ
|
|
27
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## C#/Unity ํนํ ๊ท์น
|
|
31
|
+
|
|
32
|
+
### 1. MonoBehaviour ์ต์ํ
|
|
33
|
+
|
|
34
|
+
```csharp
|
|
35
|
+
// โ ๋ชจ๋ ๋ก์ง์ MonoBehaviour์
|
|
36
|
+
public class PlayerController : MonoBehaviour
|
|
37
|
+
{
|
|
38
|
+
public float health;
|
|
39
|
+
public float speed;
|
|
40
|
+
public int gold;
|
|
41
|
+
|
|
42
|
+
void Update()
|
|
43
|
+
{
|
|
44
|
+
// ์ด๋, ์ ํฌ, ์ธ๋ฒคํ ๋ฆฌ, UI ์
๋ฐ์ดํธ ๋ชจ๋ ์ฌ๊ธฐ์...
|
|
45
|
+
// ์๋ฐฑ ์ค์ ์ฝ๋
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// โ
๊ด์ฌ์ฌ ๋ถ๋ฆฌ
|
|
50
|
+
public class PlayerController : MonoBehaviour
|
|
51
|
+
{
|
|
52
|
+
[SerializeField] private PlayerData _data;
|
|
53
|
+
|
|
54
|
+
private PlayerMovement _movement;
|
|
55
|
+
private PlayerCombat _combat;
|
|
56
|
+
|
|
57
|
+
private void Awake()
|
|
58
|
+
{
|
|
59
|
+
_movement = new PlayerMovement(_data, transform);
|
|
60
|
+
_combat = new PlayerCombat(_data);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private void Update()
|
|
64
|
+
{
|
|
65
|
+
_movement.Update(Time.deltaTime);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Pure C# ํด๋์ค
|
|
70
|
+
public class PlayerMovement
|
|
71
|
+
{
|
|
72
|
+
private readonly PlayerData _data;
|
|
73
|
+
private readonly Transform _transform;
|
|
74
|
+
|
|
75
|
+
public PlayerMovement(PlayerData data, Transform transform)
|
|
76
|
+
{
|
|
77
|
+
_data = data;
|
|
78
|
+
_transform = transform;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public void Update(float deltaTime)
|
|
82
|
+
{
|
|
83
|
+
// ์ด๋ ๋ก์ง๋ง
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 2. ScriptableObject ํ์ฉ
|
|
89
|
+
|
|
90
|
+
```csharp
|
|
91
|
+
// โ
๋ฐ์ดํฐ ์์
|
|
92
|
+
[CreateAssetMenu(fileName = "PlayerData", menuName = "Game/PlayerData")]
|
|
93
|
+
public class PlayerData : ScriptableObject
|
|
94
|
+
{
|
|
95
|
+
[Header("Stats")]
|
|
96
|
+
public float maxHealth = 100f;
|
|
97
|
+
public float moveSpeed = 5f;
|
|
98
|
+
|
|
99
|
+
[Header("Combat")]
|
|
100
|
+
public float attackDamage = 10f;
|
|
101
|
+
public float attackRange = 2f;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// โ
์ด๋ฒคํธ ์ฑ๋
|
|
105
|
+
[CreateAssetMenu(fileName = "GameEvent", menuName = "Events/GameEvent")]
|
|
106
|
+
public class GameEvent : ScriptableObject
|
|
107
|
+
{
|
|
108
|
+
private readonly List<IGameEventListener> _listeners = new();
|
|
109
|
+
|
|
110
|
+
public void Raise()
|
|
111
|
+
{
|
|
112
|
+
for (int i = _listeners.Count - 1; i >= 0; i--)
|
|
113
|
+
{
|
|
114
|
+
_listeners[i].OnEventRaised();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public void RegisterListener(IGameEventListener listener) => _listeners.Add(listener);
|
|
119
|
+
public void UnregisterListener(IGameEventListener listener) => _listeners.Remove(listener);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public interface IGameEventListener
|
|
123
|
+
{
|
|
124
|
+
void OnEventRaised();
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 3. ์ค๋ธ์ ํธ ํ๋ง
|
|
129
|
+
|
|
130
|
+
```csharp
|
|
131
|
+
// โ
์ ๋ค๋ฆญ ์ค๋ธ์ ํธ ํ
|
|
132
|
+
public class ObjectPool<T> where T : Component
|
|
133
|
+
{
|
|
134
|
+
private readonly T _prefab;
|
|
135
|
+
private readonly Transform _parent;
|
|
136
|
+
private readonly Queue<T> _pool = new();
|
|
137
|
+
|
|
138
|
+
public ObjectPool(T prefab, Transform parent, int initialSize = 10)
|
|
139
|
+
{
|
|
140
|
+
_prefab = prefab;
|
|
141
|
+
_parent = parent;
|
|
142
|
+
|
|
143
|
+
for (int i = 0; i < initialSize; i++)
|
|
144
|
+
{
|
|
145
|
+
CreateInstance();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public T Get()
|
|
150
|
+
{
|
|
151
|
+
T instance = _pool.Count > 0 ? _pool.Dequeue() : CreateInstance();
|
|
152
|
+
instance.gameObject.SetActive(true);
|
|
153
|
+
return instance;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public void Return(T instance)
|
|
157
|
+
{
|
|
158
|
+
instance.gameObject.SetActive(false);
|
|
159
|
+
_pool.Enqueue(instance);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private T CreateInstance()
|
|
163
|
+
{
|
|
164
|
+
T instance = Object.Instantiate(_prefab, _parent);
|
|
165
|
+
instance.gameObject.SetActive(false);
|
|
166
|
+
return instance;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ์ฌ์ฉ ์์
|
|
171
|
+
public class BulletManager : MonoBehaviour
|
|
172
|
+
{
|
|
173
|
+
[SerializeField] private Bullet _bulletPrefab;
|
|
174
|
+
|
|
175
|
+
private ObjectPool<Bullet> _bulletPool;
|
|
176
|
+
|
|
177
|
+
private void Awake()
|
|
178
|
+
{
|
|
179
|
+
_bulletPool = new ObjectPool<Bullet>(_bulletPrefab, transform, 50);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public Bullet SpawnBullet(Vector3 position, Vector3 direction)
|
|
183
|
+
{
|
|
184
|
+
Bullet bullet = _bulletPool.Get();
|
|
185
|
+
bullet.Initialize(position, direction, () => _bulletPool.Return(bullet));
|
|
186
|
+
return bullet;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 4. ์ฑ๊ธํค ํจํด (์ฃผ์ํด์ ์ฌ์ฉ)
|
|
192
|
+
|
|
193
|
+
```csharp
|
|
194
|
+
// โ
์์ ํ ์ฑ๊ธํค
|
|
195
|
+
public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
|
|
196
|
+
{
|
|
197
|
+
private static T _instance;
|
|
198
|
+
private static readonly object _lock = new();
|
|
199
|
+
private static bool _applicationIsQuitting;
|
|
200
|
+
|
|
201
|
+
public static T Instance
|
|
202
|
+
{
|
|
203
|
+
get
|
|
204
|
+
{
|
|
205
|
+
if (_applicationIsQuitting)
|
|
206
|
+
{
|
|
207
|
+
Debug.LogWarning($"[Singleton] Instance of {typeof(T)} already destroyed.");
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
lock (_lock)
|
|
212
|
+
{
|
|
213
|
+
if (_instance == null)
|
|
214
|
+
{
|
|
215
|
+
_instance = FindObjectOfType<T>();
|
|
216
|
+
|
|
217
|
+
if (_instance == null)
|
|
218
|
+
{
|
|
219
|
+
var singleton = new GameObject($"[Singleton] {typeof(T)}");
|
|
220
|
+
_instance = singleton.AddComponent<T>();
|
|
221
|
+
DontDestroyOnLoad(singleton);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return _instance;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
protected virtual void OnApplicationQuit()
|
|
230
|
+
{
|
|
231
|
+
_applicationIsQuitting = true;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// ์ฌ์ฉ
|
|
236
|
+
public class GameManager : Singleton<GameManager>
|
|
237
|
+
{
|
|
238
|
+
public GameState CurrentState { get; private set; }
|
|
239
|
+
|
|
240
|
+
public void ChangeState(GameState newState)
|
|
241
|
+
{
|
|
242
|
+
CurrentState = newState;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### 5. ์ฝ๋ฃจํด vs async/await
|
|
248
|
+
|
|
249
|
+
```csharp
|
|
250
|
+
// โ
์ฝ๋ฃจํด (Unity ์๋ช
์ฃผ๊ธฐ์ ํตํฉ)
|
|
251
|
+
public class EnemySpawner : MonoBehaviour
|
|
252
|
+
{
|
|
253
|
+
[SerializeField] private float _spawnInterval = 2f;
|
|
254
|
+
|
|
255
|
+
private Coroutine _spawnCoroutine;
|
|
256
|
+
|
|
257
|
+
public void StartSpawning()
|
|
258
|
+
{
|
|
259
|
+
_spawnCoroutine = StartCoroutine(SpawnLoop());
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
public void StopSpawning()
|
|
263
|
+
{
|
|
264
|
+
if (_spawnCoroutine != null)
|
|
265
|
+
{
|
|
266
|
+
StopCoroutine(_spawnCoroutine);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private IEnumerator SpawnLoop()
|
|
271
|
+
{
|
|
272
|
+
while (true)
|
|
273
|
+
{
|
|
274
|
+
SpawnEnemy();
|
|
275
|
+
yield return new WaitForSeconds(_spawnInterval);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// โ
async/await (I/O ์์
)
|
|
281
|
+
public class SaveManager : MonoBehaviour
|
|
282
|
+
{
|
|
283
|
+
public async Task SaveGameAsync(GameSaveData data)
|
|
284
|
+
{
|
|
285
|
+
string json = JsonUtility.ToJson(data);
|
|
286
|
+
string path = Path.Combine(Application.persistentDataPath, "save.json");
|
|
287
|
+
|
|
288
|
+
await File.WriteAllTextAsync(path, json);
|
|
289
|
+
Debug.Log("Game saved!");
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
public async Task<GameSaveData> LoadGameAsync()
|
|
293
|
+
{
|
|
294
|
+
string path = Path.Combine(Application.persistentDataPath, "save.json");
|
|
295
|
+
|
|
296
|
+
if (!File.Exists(path))
|
|
297
|
+
return null;
|
|
298
|
+
|
|
299
|
+
string json = await File.ReadAllTextAsync(path);
|
|
300
|
+
return JsonUtility.FromJson<GameSaveData>(json);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### 6. ์ด๋ฒคํธ ์์คํ
|
|
306
|
+
|
|
307
|
+
```csharp
|
|
308
|
+
// โ
C# ์ด๋ฒคํธ
|
|
309
|
+
public class Health : MonoBehaviour
|
|
310
|
+
{
|
|
311
|
+
public event Action<float> OnHealthChanged;
|
|
312
|
+
public event Action OnDeath;
|
|
313
|
+
|
|
314
|
+
[SerializeField] private float _maxHealth = 100f;
|
|
315
|
+
private float _currentHealth;
|
|
316
|
+
|
|
317
|
+
public float CurrentHealth => _currentHealth;
|
|
318
|
+
public float MaxHealth => _maxHealth;
|
|
319
|
+
|
|
320
|
+
private void Awake()
|
|
321
|
+
{
|
|
322
|
+
_currentHealth = _maxHealth;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
public void TakeDamage(float damage)
|
|
326
|
+
{
|
|
327
|
+
_currentHealth = Mathf.Max(0, _currentHealth - damage);
|
|
328
|
+
OnHealthChanged?.Invoke(_currentHealth / _maxHealth);
|
|
329
|
+
|
|
330
|
+
if (_currentHealth <= 0)
|
|
331
|
+
{
|
|
332
|
+
OnDeath?.Invoke();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ๊ตฌ๋
|
|
338
|
+
public class HealthUI : MonoBehaviour
|
|
339
|
+
{
|
|
340
|
+
[SerializeField] private Health _health;
|
|
341
|
+
[SerializeField] private Slider _healthBar;
|
|
342
|
+
|
|
343
|
+
private void OnEnable()
|
|
344
|
+
{
|
|
345
|
+
_health.OnHealthChanged += UpdateHealthBar;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
private void OnDisable()
|
|
349
|
+
{
|
|
350
|
+
_health.OnHealthChanged -= UpdateHealthBar;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private void UpdateHealthBar(float normalizedHealth)
|
|
354
|
+
{
|
|
355
|
+
_healthBar.value = normalizedHealth;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### 7. ์ธ์คํํฐ ์ต์ ํ
|
|
361
|
+
|
|
362
|
+
```csharp
|
|
363
|
+
// โ
SerializeField + private
|
|
364
|
+
public class Enemy : MonoBehaviour
|
|
365
|
+
{
|
|
366
|
+
[Header("Settings")]
|
|
367
|
+
[SerializeField] private float _moveSpeed = 3f;
|
|
368
|
+
[SerializeField] private float _attackRange = 1.5f;
|
|
369
|
+
|
|
370
|
+
[Header("References")]
|
|
371
|
+
[SerializeField] private Transform _target;
|
|
372
|
+
[SerializeField] private Animator _animator;
|
|
373
|
+
|
|
374
|
+
[Header("Debug")]
|
|
375
|
+
[SerializeField, ReadOnly] private float _distanceToTarget;
|
|
376
|
+
|
|
377
|
+
// public ํ๋กํผํฐ๋ก ์ฝ๊ธฐ ์ ์ฉ ์ ๊ทผ
|
|
378
|
+
public float MoveSpeed => _moveSpeed;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// โ
RequireComponent
|
|
382
|
+
[RequireComponent(typeof(Rigidbody))]
|
|
383
|
+
[RequireComponent(typeof(Collider))]
|
|
384
|
+
public class PhysicsObject : MonoBehaviour
|
|
385
|
+
{
|
|
386
|
+
private Rigidbody _rb;
|
|
387
|
+
|
|
388
|
+
private void Awake()
|
|
389
|
+
{
|
|
390
|
+
_rb = GetComponent<Rigidbody>();
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### 8. ์ฑ๋ฅ ์ต์ ํ
|
|
396
|
+
|
|
397
|
+
```csharp
|
|
398
|
+
// โ
GetComponent ์บ์ฑ
|
|
399
|
+
public class OptimizedBehaviour : MonoBehaviour
|
|
400
|
+
{
|
|
401
|
+
// โ Update์์ GetComponent ํธ์ถ
|
|
402
|
+
void Update()
|
|
403
|
+
{
|
|
404
|
+
GetComponent<Rigidbody>().AddForce(Vector3.up);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// โ
์บ์ฑ
|
|
408
|
+
private Rigidbody _rb;
|
|
409
|
+
|
|
410
|
+
void Awake()
|
|
411
|
+
{
|
|
412
|
+
_rb = GetComponent<Rigidbody>();
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
void Update()
|
|
416
|
+
{
|
|
417
|
+
_rb.AddForce(Vector3.up);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// โ
string ๋น๊ต ์ต์ ํ
|
|
422
|
+
public class TagChecker : MonoBehaviour
|
|
423
|
+
{
|
|
424
|
+
// โ ๋ฌธ์์ด ๋น๊ต
|
|
425
|
+
void OnTriggerEnter(Collider other)
|
|
426
|
+
{
|
|
427
|
+
if (other.tag == "Player") { }
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// โ
CompareTag ์ฌ์ฉ
|
|
431
|
+
void OnTriggerEnter(Collider other)
|
|
432
|
+
{
|
|
433
|
+
if (other.CompareTag("Player")) { }
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// โ
ํ ๋น ์ต์ํ
|
|
438
|
+
public class NoAllocExample : MonoBehaviour
|
|
439
|
+
{
|
|
440
|
+
// ๋ฏธ๋ฆฌ ํ ๋น
|
|
441
|
+
private readonly Collider[] _hitBuffer = new Collider[10];
|
|
442
|
+
private readonly RaycastHit[] _rayBuffer = new RaycastHit[5];
|
|
443
|
+
|
|
444
|
+
void CheckOverlap(Vector3 position, float radius)
|
|
445
|
+
{
|
|
446
|
+
// NonAlloc ๋ฒ์ ์ฌ์ฉ
|
|
447
|
+
int count = Physics.OverlapSphereNonAlloc(position, radius, _hitBuffer);
|
|
448
|
+
|
|
449
|
+
for (int i = 0; i < count; i++)
|
|
450
|
+
{
|
|
451
|
+
// _hitBuffer[i] ์ฒ๋ฆฌ
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## ํด๋ ๊ตฌ์กฐ ๊ถ์ฅ
|
|
458
|
+
|
|
459
|
+
```
|
|
460
|
+
Assets/
|
|
461
|
+
โโโ _Project/ # ํ๋ก์ ํธ ์์
|
|
462
|
+
โ โโโ Scripts/
|
|
463
|
+
โ โ โโโ Core/ # ํต์ฌ ์์คํ
|
|
464
|
+
โ โ โโโ Player/
|
|
465
|
+
โ โ โโโ Enemy/
|
|
466
|
+
โ โ โโโ UI/
|
|
467
|
+
โ โ โโโ Utils/
|
|
468
|
+
โ โโโ Prefabs/
|
|
469
|
+
โ โโโ ScriptableObjects/
|
|
470
|
+
โ โ โโโ Data/
|
|
471
|
+
โ โ โโโ Events/
|
|
472
|
+
โ โโโ Materials/
|
|
473
|
+
โ โโโ Textures/
|
|
474
|
+
โ โโโ Audio/
|
|
475
|
+
โโโ Scenes/
|
|
476
|
+
โโโ Resources/ # ๋ฐํ์ ๋ก๋ (์ฃผ์ํด์ ์ฌ์ฉ)
|
|
477
|
+
โโโ Plugins/
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
## ๋ค์ด๋ฐ ์ปจ๋ฒค์
|
|
481
|
+
|
|
482
|
+
```csharp
|
|
483
|
+
// ํด๋์ค: PascalCase
|
|
484
|
+
public class PlayerController { }
|
|
485
|
+
|
|
486
|
+
// ์ธํฐํ์ด์ค: I ์ ๋์ฌ
|
|
487
|
+
public interface IDamageable { }
|
|
488
|
+
|
|
489
|
+
// private ํ๋: _ ์ ๋์ฌ + camelCase
|
|
490
|
+
private float _moveSpeed;
|
|
491
|
+
|
|
492
|
+
// SerializeField: _ ์ ๋์ฌ ์ ์ง
|
|
493
|
+
[SerializeField] private float _health;
|
|
494
|
+
|
|
495
|
+
// ์์: UPPER_SNAKE_CASE ๋๋ PascalCase
|
|
496
|
+
private const float MAX_HEALTH = 100f;
|
|
497
|
+
private const float MaxHealth = 100f;
|
|
498
|
+
|
|
499
|
+
// ํ๋กํผํฐ: PascalCase
|
|
500
|
+
public float Health => _health;
|
|
501
|
+
|
|
502
|
+
// ๋ฉ์๋: PascalCase
|
|
503
|
+
public void TakeDamage(float damage) { }
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
## ์ฒดํฌ๋ฆฌ์คํธ
|
|
507
|
+
|
|
508
|
+
- [ ] MonoBehaviour ๋ก์ง ์ต์ํ
|
|
509
|
+
- [ ] GetComponent ๊ฒฐ๊ณผ ์บ์ฑ
|
|
510
|
+
- [ ] ์ด๋ฒคํธ ๊ตฌ๋
ํด์ (OnDisable)
|
|
511
|
+
- [ ] ์ค๋ธ์ ํธ ํ๋ง ์ ์ฉ
|
|
512
|
+
- [ ] SerializeField + private ์ฌ์ฉ
|
|
513
|
+
- [ ] CompareTag ์ฌ์ฉ
|
|
514
|
+
- [ ] NonAlloc API ์ฌ์ฉ
|
|
515
|
+
- [ ] Update ์ต์ํ (ํ์์๋ง)
|
|
516
|
+
- [ ] ScriptableObject๋ก ๋ฐ์ดํฐ ๋ถ๋ฆฌ
|