feat: 방어 시스템과 드로그 검증 경로 정리
- 애니메이션 이벤트 기반 방어/유지/해제 흐름과 HUD 피드백, 방어 디버그 로그를 추가했다. - 드로그 기본기1 테스트 패턴을 정리하고 공격 판정을 OnEffect 기반으로 옮기며 드로그 범위 효과의 타겟 레이어를 정상화했다. - 플레이어 퀵슬롯 테스트 세팅과 적-플레이어 겹침 방지 로직을 조정해 충돌 시 적이 수평 이동을 멈추고 최소 분리만 수행하게 했다.
This commit is contained in:
@@ -26,6 +26,9 @@ namespace Colosseum.Player
|
||||
[Tooltip("이상상태 관리자 (없으면 자동 검색)")]
|
||||
[SerializeField] private AbnormalityManager abnormalityManager;
|
||||
|
||||
[Tooltip("방어 상태 관리자 (없으면 자동 검색)")]
|
||||
[SerializeField] private PlayerDefenseController defenseController;
|
||||
|
||||
[Header("Shield")]
|
||||
[Tooltip("보호막 타입이 지정되지 않았을 때 사용할 기본 보호막 이상상태 데이터")]
|
||||
[SerializeField] private AbnormalityData shieldStateAbnormality;
|
||||
@@ -101,6 +104,13 @@ namespace Colosseum.Player
|
||||
abnormalityManager = GetComponent<AbnormalityManager>();
|
||||
}
|
||||
|
||||
if (defenseController == null)
|
||||
{
|
||||
defenseController = GetComponent<PlayerDefenseController>();
|
||||
if (defenseController == null)
|
||||
defenseController = gameObject.AddComponent<PlayerDefenseController>();
|
||||
}
|
||||
|
||||
EnsurePassiveRuntimeReferences();
|
||||
|
||||
currentHealth.OnValueChanged += HandleHealthChanged;
|
||||
@@ -197,7 +207,7 @@ namespace Colosseum.Player
|
||||
[Rpc(SendTo.Server)]
|
||||
public void TakeDamageRpc(float damage)
|
||||
{
|
||||
ApplyDamageInternal(damage, null);
|
||||
ApplyDamageInternal(new DamageContext(damage));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -206,10 +216,7 @@ namespace Colosseum.Player
|
||||
[Rpc(SendTo.Server)]
|
||||
public void UseManaRpc(float amount)
|
||||
{
|
||||
if (isDead.Value)
|
||||
return;
|
||||
|
||||
currentMana.Value = Mathf.Max(0f, currentMana.Value - amount);
|
||||
SpendMana(amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -230,10 +237,7 @@ namespace Colosseum.Player
|
||||
[Rpc(SendTo.Server)]
|
||||
public void RestoreManaRpc(float amount)
|
||||
{
|
||||
if (isDead.Value)
|
||||
return;
|
||||
|
||||
currentMana.Value = Mathf.Min(MaxMana, currentMana.Value + amount);
|
||||
RestoreMana(amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -665,7 +669,15 @@ namespace Colosseum.Player
|
||||
/// </summary>
|
||||
public float TakeDamage(float damage, object source = null)
|
||||
{
|
||||
return ApplyDamageInternal(damage, source);
|
||||
return ApplyDamageInternal(new DamageContext(damage, source));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 대미지 컨텍스트를 사용해 대미지를 적용합니다.
|
||||
/// </summary>
|
||||
public float TakeDamage(DamageContext damageContext)
|
||||
{
|
||||
return ApplyDamageInternal(damageContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -682,6 +694,32 @@ namespace Colosseum.Player
|
||||
return actualHeal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 마나를 소모하고 실제 소모량을 반환합니다.
|
||||
/// </summary>
|
||||
public float SpendMana(float amount)
|
||||
{
|
||||
if (!IsServer || isDead.Value || amount <= 0f)
|
||||
return 0f;
|
||||
|
||||
float actualSpent = Mathf.Min(amount, currentMana.Value);
|
||||
currentMana.Value = Mathf.Max(0f, currentMana.Value - actualSpent);
|
||||
return actualSpent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 마나를 회복하고 실제 회복량을 반환합니다.
|
||||
/// </summary>
|
||||
public float RestoreMana(float amount)
|
||||
{
|
||||
if (!IsServer || isDead.Value || amount <= 0f)
|
||||
return 0f;
|
||||
|
||||
float actualRestore = Mathf.Min(amount, MaxMana - currentMana.Value);
|
||||
currentMana.Value = Mathf.Min(MaxMana, currentMana.Value + actualRestore);
|
||||
return actualRestore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 보호막을 적용합니다.
|
||||
/// </summary>
|
||||
@@ -724,17 +762,29 @@ namespace Colosseum.Player
|
||||
return remainingDamage;
|
||||
}
|
||||
|
||||
private float ApplyDamageInternal(float damage, object source)
|
||||
private float ApplyDamageInternal(DamageContext damageContext)
|
||||
{
|
||||
if (!IsServer || isDead.Value || IsDamageImmune())
|
||||
return 0f;
|
||||
|
||||
float finalDamage = damage * GetIncomingDamageMultiplier();
|
||||
if (defenseController == null)
|
||||
defenseController = GetComponent<PlayerDefenseController>();
|
||||
|
||||
float rawDamage = damageContext.Amount;
|
||||
if (rawDamage <= 0f)
|
||||
return 0f;
|
||||
|
||||
if (defenseController != null)
|
||||
{
|
||||
rawDamage = defenseController.ResolveIncomingDamage(damageContext.WithAmount(rawDamage));
|
||||
}
|
||||
|
||||
float finalDamage = rawDamage * GetIncomingDamageMultiplier();
|
||||
float mitigatedDamage = ConsumeShield(finalDamage);
|
||||
float actualDamage = Mathf.Min(mitigatedDamage, currentHealth.Value);
|
||||
currentHealth.Value = Mathf.Max(0f, currentHealth.Value - actualDamage);
|
||||
|
||||
CombatBalanceTracker.RecordDamage(source as GameObject, gameObject, actualDamage);
|
||||
CombatBalanceTracker.RecordDamage(damageContext.SourceGameObject, gameObject, actualDamage);
|
||||
|
||||
if (currentHealth.Value <= 0f)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user