feat: 드로그 보스 AI 및 런타임 상태 구조 재구성
- 드로그 전투 컨텍스트를 BossBehaviorRuntimeState 중심 구조로 정리하고 BossEnemy, 패턴 액션, 조건 노드가 마지막 실행 결과와 phase 상태를 직접 사용하도록 갱신 - BT_Drog와 재빌드 에디터 스크립트를 확장해 phase 전환, 집행 결과 분기, 거리/쿨타임 기반 패턴 선택을 드로그 전용 자산과 노드 파라미터로 재구성 - 드로그 패턴/스킬/이펙트/애니메이션 플레이스홀더 자산을 재생성하고 보스 프리팹이 새 런타임 상태 및 등록 클립 구성을 참조하도록 정리
This commit is contained in:
@@ -25,7 +25,7 @@ public abstract partial class BossPatternActionBase : Action
|
||||
protected BossEnemy bossEnemy;
|
||||
protected EnemyBase enemyBase;
|
||||
protected SkillController skillController;
|
||||
protected BossCombatBehaviorContext combatBehaviorContext;
|
||||
protected BossBehaviorRuntimeState runtimeState;
|
||||
protected UnityEngine.AI.NavMeshAgent navMeshAgent;
|
||||
protected AbnormalityManager abnormalityManager;
|
||||
|
||||
@@ -34,6 +34,7 @@ public abstract partial class BossPatternActionBase : Action
|
||||
private int currentStepIndex;
|
||||
private bool isWaiting;
|
||||
private float waitEndTime;
|
||||
private bool isSkillStepExecuting;
|
||||
|
||||
private bool isChargeWaiting;
|
||||
private float chargeEndTime;
|
||||
@@ -47,6 +48,11 @@ public abstract partial class BossPatternActionBase : Action
|
||||
/// </summary>
|
||||
protected abstract bool TryResolvePattern(out BossPatternData pattern, out GameObject target);
|
||||
|
||||
/// <summary>
|
||||
/// 패턴이 의미 있는 결과와 함께 종료되었을 때, 실패 결과도 다음 노드로 넘길지 결정합니다.
|
||||
/// </summary>
|
||||
protected virtual bool ContinueSequenceOnResolvedFailure => false;
|
||||
|
||||
protected override Status OnStart()
|
||||
{
|
||||
ResolveReferences();
|
||||
@@ -55,13 +61,13 @@ public abstract partial class BossPatternActionBase : Action
|
||||
if (!IsReady())
|
||||
return Status.Failure;
|
||||
|
||||
if (combatBehaviorContext.IsBehaviorSuppressed)
|
||||
if (runtimeState.IsBehaviorSuppressed)
|
||||
{
|
||||
StopMovement();
|
||||
return Status.Failure;
|
||||
}
|
||||
|
||||
if (bossEnemy.IsDead || bossEnemy.IsTransitioning)
|
||||
if (bossEnemy.IsDead)
|
||||
return Status.Failure;
|
||||
|
||||
if (skillController.IsPlayingAnimation)
|
||||
@@ -72,10 +78,16 @@ public abstract partial class BossPatternActionBase : Action
|
||||
|
||||
activePattern = pattern;
|
||||
activeTarget = target;
|
||||
runtimeState.BeginPatternExecution(activePattern);
|
||||
|
||||
runtimeState.WasChargeBroken = false;
|
||||
runtimeState.LastChargeStaggerDuration = 0f;
|
||||
|
||||
if (Target != null)
|
||||
Target.Value = target;
|
||||
|
||||
runtimeState.SetCurrentTarget(target);
|
||||
|
||||
StopMovement();
|
||||
return ExecuteCurrentStep();
|
||||
}
|
||||
@@ -83,16 +95,16 @@ public abstract partial class BossPatternActionBase : Action
|
||||
protected override Status OnUpdate()
|
||||
{
|
||||
if (!IsReady() || activePattern == null)
|
||||
return Status.Failure;
|
||||
return FinalizePatternFailure(BossPatternExecutionResult.Failed);
|
||||
|
||||
if (combatBehaviorContext.IsBehaviorSuppressed)
|
||||
if (runtimeState.IsBehaviorSuppressed)
|
||||
{
|
||||
StopMovement();
|
||||
return Status.Failure;
|
||||
return FinalizePatternFailure(BossPatternExecutionResult.Cancelled);
|
||||
}
|
||||
|
||||
if (bossEnemy.IsDead || bossEnemy.IsTransitioning)
|
||||
return Status.Failure;
|
||||
if (bossEnemy.IsDead)
|
||||
return FinalizePatternFailure(BossPatternExecutionResult.Cancelled);
|
||||
|
||||
if (isChargeWaiting)
|
||||
{
|
||||
@@ -100,9 +112,11 @@ public abstract partial class BossPatternActionBase : Action
|
||||
{
|
||||
EndChargeWait(broken: true);
|
||||
skillController?.CancelSkill(SkillCancelReason.Interrupt);
|
||||
runtimeState.WasChargeBroken = true;
|
||||
runtimeState.SetPatternCooldown(activePattern);
|
||||
LogDebug($"충전 차단 성공: 누적 {chargeAccumulatedDamage:F1} / 필요 {chargeRequiredDamage:F1}");
|
||||
CombatBalanceTracker.RecordBossEvent("집행 개시 차단 성공");
|
||||
return Status.Failure;
|
||||
return FinalizeResolvedPattern(BossPatternExecutionResult.Failed);
|
||||
}
|
||||
|
||||
if (Time.time < chargeEndTime)
|
||||
@@ -117,16 +131,21 @@ public abstract partial class BossPatternActionBase : Action
|
||||
|
||||
isWaiting = false;
|
||||
}
|
||||
else if (skillController.IsPlayingAnimation)
|
||||
else if (isSkillStepExecuting)
|
||||
{
|
||||
return Status.Running;
|
||||
if (skillController.IsPlayingAnimation)
|
||||
return Status.Running;
|
||||
|
||||
isSkillStepExecuting = false;
|
||||
if (skillController.LastExecutionResult != SkillExecutionResult.Completed)
|
||||
return FinalizePatternFailure(BossPatternExecutionResult.Cancelled);
|
||||
}
|
||||
|
||||
currentStepIndex++;
|
||||
if (currentStepIndex >= activePattern.Steps.Count)
|
||||
{
|
||||
UsePatternAction.MarkPatternUsed(GameObject, activePattern);
|
||||
return Status.Success;
|
||||
runtimeState.SetPatternCooldown(activePattern);
|
||||
return FinalizeResolvedPattern(BossPatternExecutionResult.Succeeded);
|
||||
}
|
||||
|
||||
return ExecuteCurrentStep();
|
||||
@@ -205,7 +224,7 @@ public abstract partial class BossPatternActionBase : Action
|
||||
|
||||
protected void LogDebug(string message)
|
||||
{
|
||||
combatBehaviorContext?.LogDebug(GetType().Name, message);
|
||||
runtimeState?.LogDebug(GetType().Name, message);
|
||||
}
|
||||
|
||||
private Status ExecuteCurrentStep()
|
||||
@@ -241,7 +260,7 @@ public abstract partial class BossPatternActionBase : Action
|
||||
{
|
||||
if (activePattern != null && activePattern.SkipJumpStepOnNoTarget)
|
||||
{
|
||||
UsePatternAction.MarkPatternUsed(GameObject, activePattern);
|
||||
runtimeState.SetPatternCooldown(activePattern);
|
||||
LogDebug($"점프 대상 없음, 조합 패턴 조기 종료: {activePattern.PatternName}");
|
||||
return Status.Success;
|
||||
}
|
||||
@@ -253,12 +272,13 @@ public abstract partial class BossPatternActionBase : Action
|
||||
enemyBase?.SetJumpTarget(skillTarget.transform.position);
|
||||
}
|
||||
|
||||
if (!skillController.ExecuteSkill(step.Skill))
|
||||
if (!skillController.ExecuteSkill(step.Skill, skillTarget))
|
||||
{
|
||||
Debug.LogWarning($"[{GetType().Name}] 스킬 실행 실패: {step.Skill.SkillName}");
|
||||
return Status.Failure;
|
||||
return FinalizePatternFailure(BossPatternExecutionResult.Failed);
|
||||
}
|
||||
|
||||
isSkillStepExecuting = true;
|
||||
LogDebug($"패턴 실행: {activePattern.PatternName} / Step={currentStepIndex} / Skill={step.Skill.SkillName}");
|
||||
return Status.Running;
|
||||
}
|
||||
@@ -308,7 +328,7 @@ public abstract partial class BossPatternActionBase : Action
|
||||
|
||||
if (broken && activeChargeData != null)
|
||||
{
|
||||
combatBehaviorContext.LastChargeStaggerDuration = activeChargeData.StaggerDuration;
|
||||
runtimeState.LastChargeStaggerDuration = activeChargeData.StaggerDuration;
|
||||
}
|
||||
|
||||
activeChargeData = null;
|
||||
@@ -327,7 +347,7 @@ public abstract partial class BossPatternActionBase : Action
|
||||
|
||||
private bool IsReady()
|
||||
{
|
||||
return bossEnemy != null && enemyBase != null && skillController != null && combatBehaviorContext != null;
|
||||
return bossEnemy != null && enemyBase != null && skillController != null && runtimeState != null;
|
||||
}
|
||||
|
||||
private void ResolveReferences()
|
||||
@@ -341,8 +361,8 @@ public abstract partial class BossPatternActionBase : Action
|
||||
if (skillController == null)
|
||||
skillController = GameObject.GetComponent<SkillController>();
|
||||
|
||||
if (combatBehaviorContext == null)
|
||||
combatBehaviorContext = GameObject.GetComponent<BossCombatBehaviorContext>();
|
||||
if (runtimeState == null)
|
||||
runtimeState = GameObject.GetComponent<BossBehaviorRuntimeState>();
|
||||
|
||||
if (navMeshAgent == null)
|
||||
navMeshAgent = GameObject.GetComponent<UnityEngine.AI.NavMeshAgent>();
|
||||
@@ -360,6 +380,22 @@ public abstract partial class BossPatternActionBase : Action
|
||||
activeTarget = null;
|
||||
currentStepIndex = 0;
|
||||
isWaiting = false;
|
||||
isSkillStepExecuting = false;
|
||||
waitEndTime = 0f;
|
||||
}
|
||||
|
||||
private Status FinalizeResolvedPattern(BossPatternExecutionResult result)
|
||||
{
|
||||
runtimeState?.CompletePatternExecution(activePattern, result);
|
||||
if (result == BossPatternExecutionResult.Failed && ContinueSequenceOnResolvedFailure)
|
||||
return Status.Success;
|
||||
|
||||
return Status.Success;
|
||||
}
|
||||
|
||||
private Status FinalizePatternFailure(BossPatternExecutionResult result)
|
||||
{
|
||||
runtimeState?.CompletePatternExecution(activePattern, result);
|
||||
return Status.Failure;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user