- 수성바탕체와 마루 부리 기반 UI 폰트 규칙, TMP 에셋 생성, 일괄 적용용 에디터 도구를 추가하고 로비 빌더도 같은 규칙을 따르도록 정리 - 기존 UI 프리팹과 Lobby/Test 씬의 TMP 폰트를 역할별로 교체하고 강조 텍스트와 HUD 계층에 맞는 자간을 반영 - 넥슨 Lv.2 고딕 검토 후 제외하고 액션바, HP/MP, 보스 체력바 숫자와 라벨을 마루 부리 기준으로 재조정 - Assets/_Game/Fonts 경로에 원본 폰트와 TMP 에셋을 정리하고 공유 Obsidian Vault 경로를 AGENTS에 기록 - Unity 리프레시와 HUD 보정 적용 후 콘솔 경고/에러 없는 상태를 확인
9.3 KiB
9.3 KiB
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\Colosseumfor 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.
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:
- Flat: Add fixed value
- PercentAdd: Sum percentages, then multiply
- 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.
# 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)
# 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:
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:
- System namespaces
- UnityEngine namespaces
- Unity.Netcode / Unity packages
- Colosseum namespaces
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:
[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:
/// <summary>
/// 플레이어 네트워크 상태 관리 (HP, MP 등)
/// </summary>
public class PlayerNetworkController : NetworkBehaviour
{
/// <summary>
/// 대미지 적용 (서버에서만 실행)
/// </summary>
[Rpc(SendTo.Server)]
public void TakeDamageRpc(float damage)
{
// ...
}
}
Network Code Patterns
Use Unity Netcode patterns:
// Network variables for synchronized state
private NetworkVariable<float> currentHealth = new NetworkVariable<float>(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:
public float MaxHealth => vitality.FinalValue * 10f;
public bool IsStunned => stunCount > 0;
public bool CanAct => !IsStunned;
Switch Expressions
Prefer switch expressions for concise mapping:
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:
[CreateAssetMenu(fileName = "NewSkill", menuName = "Colosseum/Skill")]
public class SkillData : ScriptableObject
{
[SerializeField] private string skillName;
[SerializeField] private List<SkillEffect> effects;
public string SkillName => skillName;
public IReadOnlyList<SkillEffect> Effects => effects;
}
Error Handling
- Use
Debug.LogWarning()for recoverable issues - Use
Debug.LogError()for critical failures - Null-check parameters in public methods
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<T> or custom delegates:
public event Action<ActiveAbnormality> OnAbnormalityAdded;
public event Action<ActiveAbnormality> 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
public class ExampleComponent : MonoBehaviour
{
[Header("References")]
[SerializeField] private Animator animator;
public Animator Animator => animator;
private void Awake()
{
if (animator == null)
animator = GetComponentInChildren<Animator>();
}
}
NetworkBehaviour Components
public class NetworkedComponent : NetworkBehaviour
{
private NetworkVariable<int> value = new NetworkVariable<int>();
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:orfix:and describe the actual gameplay/UI/system change in Korean with enough detail to understand the scope from the log alone. - 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(nom_or_prefix) - Prefer
IReadOnlyList<T>for exposing collections