using System; using UnityEngine; namespace WL.Player { /// /// 플레이어 레벨·경험치 런타임 상태 (PD #727). 씬에 1개("PlayerProgress")를 둔다. /// 값은 PlayerProgressSettings 에서 읽고(C45), 바뀔 때 Changed 를 발화한다 — HUD 가 구독한다. /// 경험치는 Enemy.AnyDied(처치 1회)마다 설정의 xpPerKill 만큼 더한다 — 표기가 실제로 움직이도록 최소 연결(임시값). /// public class PlayerProgress : MonoBehaviour { [Header("설정 (ScriptableObject)")] [SerializeField] private PlayerProgressSettings settings; public int Level { get; private set; } public long Xp { get; private set; } public long XpToNext { get; private set; } public PlayerProgressSettings Settings { get { return settings; } } /// 레벨·경험치가 바뀔 때. public event Action Changed; private void Awake() { ResetFromSettings(); } private void OnEnable() { Enemy.AnyDied += OnAnyEnemyDied; } private void OnDisable() { Enemy.AnyDied -= OnAnyEnemyDied; } private void OnAnyEnemyDied(Enemy e) { if (e != null && e.IsInvincible) return; // 무적 더미 봇은 죽지 않지만 방어적으로 제외 OnEnemyKilled(); } /// 설정값으로 되돌린다(시작 시·검증용). public void ResetFromSettings() { Level = settings != null ? Mathf.Max(settings.startLevel, 1) : 1; Xp = settings != null ? Math.Max(settings.startXp, 0L) : 0L; XpToNext = settings != null ? settings.XpToNext(Level) : 100L; if (Changed != null) Changed(); } /// 경험치를 더하고 필요 경험치를 넘으면 레벨업한다(여러 단계 연속 가능). public void AddXp(long amount) { if (amount <= 0) return; Xp += amount; int guard = 0; while (Xp >= XpToNext && guard++ < 1000) { Xp -= XpToNext; Level++; XpToNext = settings != null ? settings.XpToNext(Level) : XpToNext; } if (Changed != null) Changed(); } /// 몬스터 처치 보상(설정 xpPerKill). 처치 이벤트 연결 시 호출한다. public void OnEnemyKilled() { if (settings == null) return; AddXp(settings.xpPerKill); } } }