# Colosseum - Unity Game Project ## Project Overview Multiplayer arena game built with **Unity 6000.3.10f1** and **Unity Netcode for GameObjects**. - **Language**: C# 9.0 - **Target Framework**: .NET Standard 2.1 - **Root Namespace**: `Colosseum` - **Assembly Definition**: `Colosseum.Game` (Assets/Scripts/Colosseum.Game.asmdef) ## Game Design Documentation Design docs are maintained in Obsidian Vault: `\\Truenas\smb\Obsidian Vault\Colosseum` - Always use the shared Obsidian Vault at `\\Truenas\smb\Obsidian Vault\Colosseum` for project documentation updates. - Do not write Colosseum design notes to `C:\Users\dal4s\OneDrive\문서\Obsidian Vault\Colosseum`; that path is not the active vault for this project. - When editing user-authored Obsidian notes, preserve the user's original text structure as much as possible. - If Codex adds interpretation, clarification, proposals, or implementation notes to a user-authored note, put them in a clearly labeled separate section such as `Codex 보완 메모` or `Codex 제안` so the added content is visibly distinguishable from the user's original writing. - Avoid silently rewriting or blending Codex-authored guidance into the user's original bullet lists unless the user explicitly asks for a rewrite. - Cross-session design agreements that should be checked before related work are summarized in `\\Truenas\smb\Obsidian Vault\Colosseum\개발\세션 공통 합의.md`. ### Game Concept - **Genre**: Online multiplayer co-op action RPG (3rd person) - **Theme**: Gladiator survival boss raid in Colosseum - **Roles**: Multi-role system - players can hybridize (e.g., Tank 0.5 + DPS 0.5) instead of fixed Tank/DPS/Healer ### Stats System | Stat | Abbr | Description | Derived Formula | |------|------|-------------|-----------------| | Strength | STR | Weapon damage | Physical Damage = STR × 2 | | Dexterity | DEX | Ranged aim/damage, melee speed | Ranged Damage = DEX × 2 | | Intelligence | INT | Magic damage | Magic Damage = INT × 2 | | Vitality | VIT | Max health | Max HP = VIT × 10 | | Wisdom | WIS | Healing power | Heal Power = WIS × 1.5 | | Spirit | SPI | Max mana | Max MP = SPI × 5 | ### Damage Calculation ``` Final Damage = baseDamage + (statDamage × statScaling) ``` | DamageType | Base Stat | Description | |------------|-----------|-------------| | Physical | STR | Melee weapon damage | | Magical | INT | Spell damage | | Ranged | DEX | Bow/ranged damage | | True | None | Fixed damage, no stat scaling | ### Stat Modifier System Modifiers are applied in order: 1. **Flat**: Add fixed value 2. **PercentAdd**: Sum percentages, then multiply 3. **PercentMult**: Multiply individually ``` Final = (Base + FlatSum) × (1 + PercentAddSum) × PercentMult1 × PercentMult2... ``` ### Skill System - **Active Skills**: 6 slots (L-click, R-click, 1, 2, 3, 4) - **Passive Skills**: Tree-based progression from center - **Effects**: Triggered via animation events (`OnEffect(index)`) - **Animation**: Start clip + optional end clip ## Build/Run Commands This is a Unity project. Use Unity Editor for building and testing. ```bash # Open in Unity Editor (requires Unity Hub) # Build via: File > Build Settings > Build # Run tests in Unity Editor # Window > General > Test Runner > EditMode / PlayMode ``` ### Build from Command Line (Windows) ```bash # Build Windows standalone (adjust paths as needed) "C:\Program Files\Unity\Hub\Editor\6000.3.10f1\Editor\Unity.exe" -batchmode -projectPath . -buildWindows64Player ./Builds/Windows/Colosseum.exe -quit ``` ## Project Structure ``` Assets/ Scripts/ Abnormalities/ # Buff/debuff system Editor/ # Unity editor extensions Network/ # Network management Player/ # Player controllers Skills/ # Skill system Effects/ # Skill effects (damage, heal, etc.) Stats/ # Character statistics UI/ # User interface ``` ## Code Style Guidelines ### Namespaces Follow `Colosseum.{Subnamespace}` pattern: ```csharp namespace Colosseum.Player { } namespace Colosseum.Skills { } namespace Colosseum.Skills.Effects { } namespace Colosseum.Stats { } namespace Colosseum.Network { } namespace Colosseum.Abnormalities { } ``` ### Using Statements Order Organize imports in this order, separated by blank lines: 1. System namespaces 2. UnityEngine namespaces 3. Unity.Netcode / Unity packages 4. Colosseum namespaces ```csharp using System; using System.Collections.Generic; using UnityEngine; using Unity.Netcode; using Colosseum.Stats; using Colosseum.Player; ``` ### Naming Conventions | Element | Convention | Example | |---------|------------|---------| | Classes | PascalCase | `PlayerNetworkController` | | Interfaces | IPascalCase | `IDamageable` | | Methods | PascalCase | `TakeDamageRpc()` | | Public Properties | PascalCase | `MaxHealth`, `IsStunned` | | Private Fields | camelCase | `currentHealth`, `characterStats` | | Constants | PascalCase or SCREAMING_SNAKE | `SKILL_STATE_NAME`, `MaxValue` | | Enum values | PascalCase | `DamageType.Physical` | ### Serialization & Inspector Use `[SerializeField]` with `[Header]` and `[Tooltip]` for organization: ```csharp [Header("References")] [Tooltip("CharacterStats component (auto-searched if null)")] [SerializeField] private CharacterStats characterStats; [Header("Settings")] [Min(0f)] [SerializeField] private float baseDamage = 10f; [SerializeField] private DamageType damageType = DamageType.Physical; ``` ### Documentation Use XML documentation comments in **Korean**: ```csharp /// /// 플레이어 네트워크 상태 관리 (HP, MP 등) /// public class PlayerNetworkController : NetworkBehaviour { /// /// 대미지 적용 (서버에서만 실행) /// [Rpc(SendTo.Server)] public void TakeDamageRpc(float damage) { // ... } } ``` ### Network Code Patterns Use Unity Netcode patterns: ```csharp // Network variables for synchronized state private NetworkVariable currentHealth = new NetworkVariable(100f); // Server RPCs for client-to-server calls [Rpc(SendTo.Server)] public void TakeDamageRpc(float damage) { currentHealth.Value = Mathf.Max(0f, currentHealth.Value - damage); } // Check authority before modifying if (IsServer) { currentHealth.Value = MaxHealth; } ``` ### Expression Body Members Use for simple properties and methods: ```csharp public float MaxHealth => vitality.FinalValue * 10f; public bool IsStunned => stunCount > 0; public bool CanAct => !IsStunned; ``` ### Switch Expressions Prefer switch expressions for concise mapping: ```csharp public CharacterStat GetStat(StatType statType) { return statType switch { StatType.Strength => strength, StatType.Dexterity => dexterity, StatType.Intelligence => intelligence, _ => null, }; } ``` ### ScriptableObjects for Data Use ScriptableObject for configuration data: ```csharp [CreateAssetMenu(fileName = "NewSkill", menuName = "Colosseum/Skill")] public class SkillData : ScriptableObject { [SerializeField] private string skillName; [SerializeField] private List effects; public string SkillName => skillName; public IReadOnlyList Effects => effects; } ``` ### Error Handling - Use `Debug.LogWarning()` for recoverable issues - Use `Debug.LogError()` for critical failures - Null-check parameters in public methods ```csharp public void ApplyAbnormality(AbnormalityData data, GameObject source) { if (data == null) { Debug.LogWarning("[Abnormality] ApplyAbnormality called with null data"); return; } // ... } ``` ### Events Use C# events with `Action` or custom delegates: ```csharp public event Action OnAbnormalityAdded; public event Action OnAbnormalityRemoved; public event Action OnAbnormalitiesChanged; // Invoke with null-conditional OnAbnormalityAdded?.Invoke(newAbnormality); ``` ## Key Dependencies | Package | Purpose | |---------|---------| | Unity.Netcode.Runtime | Multiplayer networking | | Unity.InputSystem | New input system | | Unity.TextMeshPro | Text rendering | | Unity.Networking.Transport | Low-level networking | ## Common Patterns ### MonoBehaviour Components ```csharp public class ExampleComponent : MonoBehaviour { [Header("References")] [SerializeField] private Animator animator; public Animator Animator => animator; private void Awake() { if (animator == null) animator = GetComponentInChildren(); } } ``` ### NetworkBehaviour Components ```csharp public class NetworkedComponent : NetworkBehaviour { private NetworkVariable value = new NetworkVariable(); public override void OnNetworkSpawn() { // Initialize networked state } public override void OnNetworkDespawn() { // Cleanup } } ``` ## Notes - For Unity work, prefer Unity MCP for active scene inspection, runtime verification, prefab checks, and console review when it is available in the session. - Never edit code, scenes, prefabs, components, or Unity asset settings while the Unity Editor is in play mode. Stop play mode first, then edit. - After Unity-related edits, refresh or compile as needed and check the Unity console before proceeding. - For networked play tests, prefer a temporary non-conflicting test port when needed and restore the default port after validation. - The user has a strong project preference that play mode must be stopped before edits because network ports can remain occupied otherwise. - Commit messages should follow the recent project history style: use a type prefix such as `feat:`, `fix:`, or `chore:` and write the subject in Korean so the gameplay/UI/system change is clear from the log alone. - When the change is substantial, include a blank line after the subject and add Korean bullet points that summarize the work by feature/purpose, similar to commit `0889bb0` (`feat: 드로그 집행 개시 패턴 및 낙인 디버프 추가`). - Prefer the format `type: 한글 요약` for the subject, then `- 변경 사항` bullet lines for the body. Use `feat:` for feature work, `fix:` for bug fixes, and `chore:` for non-feature maintenance such as scene/prefab cleanup, asset reorganization, or other miscellaneous upkeep. The body should mention key implementation scope, affected systems/assets, and validation or rollback notes when relevant. - All code comments and documentation should be in Korean - Use `[Min()]` attribute for numeric minimums in Inspector - Use `[TextArea]` for multi-line string fields - Private fields should use `camelCase` (no `m_` or `_` prefix) - Prefer `IReadOnlyList` for exposing collections - 프로젝트 용어로는 `필살기`보다 `고위력 기술`을 우선 사용한다. - 보호막은 단일 값이 아니라 `타입별 독립 인스턴스`로 취급한다. 같은 타입은 자기 자신만 갱신되고, 서로 다른 타입은 공존하며, 흡수 순서는 적용 순서를 따른다. - 보스 시그니처 전조는 가능한 한 정확한 진행 수치 UI보다 명확한 모션/VFX로 읽히게 한다. 차단 진행도나 정확한 누적 수치 노출은 명시 요청이 없으면 피한다.