feat: 드로그 보스 AI 및 런타임 상태 구조 재구성
- 드로그 전투 컨텍스트를 BossBehaviorRuntimeState 중심 구조로 정리하고 BossEnemy, 패턴 액션, 조건 노드가 마지막 실행 결과와 phase 상태를 직접 사용하도록 갱신 - BT_Drog와 재빌드 에디터 스크립트를 확장해 phase 전환, 집행 결과 분기, 거리/쿨타임 기반 패턴 선택을 드로그 전용 자산과 노드 파라미터로 재구성 - 드로그 패턴/스킬/이펙트/애니메이션 플레이스홀더 자산을 재생성하고 보스 프리팹이 새 런타임 상태 및 등록 클립 구성을 참조하도록 정리
This commit is contained in:
@@ -28,6 +28,17 @@ namespace Colosseum.Skills
|
||||
Revive,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 마지막 스킬 실행 결과입니다.
|
||||
/// </summary>
|
||||
public enum SkillExecutionResult
|
||||
{
|
||||
None,
|
||||
Running,
|
||||
Completed,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 스킬 실행을 관리하는 컴포넌트.
|
||||
/// 애니메이션 이벤트 기반으로 효과가 발동됩니다.
|
||||
@@ -61,6 +72,8 @@ namespace Colosseum.Skills
|
||||
[SerializeField] private string lastCancelledSkillName = string.Empty;
|
||||
[Tooltip("마지막 강제 취소 이유")]
|
||||
[SerializeField] private SkillCancelReason lastCancelReason = SkillCancelReason.None;
|
||||
[Tooltip("마지막 스킬 실행 결과")]
|
||||
[SerializeField] private SkillExecutionResult lastExecutionResult = SkillExecutionResult.None;
|
||||
|
||||
// 현재 실행 중인 스킬
|
||||
private SkillData currentSkill;
|
||||
@@ -97,6 +110,7 @@ namespace Colosseum.Skills
|
||||
public Animator Animator => animator;
|
||||
public SkillCancelReason LastCancelReason => lastCancelReason;
|
||||
public string LastCancelledSkillName => lastCancelledSkillName;
|
||||
public SkillExecutionResult LastExecutionResult => lastExecutionResult;
|
||||
public GameObject CurrentTargetOverride => currentTargetOverride;
|
||||
public bool IsChannelingActive => isChannelingActive;
|
||||
|
||||
@@ -233,6 +247,8 @@ namespace Colosseum.Skills
|
||||
{
|
||||
if (currentSkill == null || animator == null) return;
|
||||
|
||||
UpdateCastTargetTracking();
|
||||
|
||||
// 채널링 중일 때
|
||||
if (isChannelingActive)
|
||||
{
|
||||
@@ -263,7 +279,7 @@ namespace Colosseum.Skills
|
||||
// 모든 클립과 반복이 끝나면 종료
|
||||
if (debugMode) Debug.Log($"[Skill] Animation complete: {currentSkill.SkillName}");
|
||||
RestoreBaseController();
|
||||
ClearCurrentSkillState();
|
||||
CompleteCurrentSkillExecution(SkillExecutionResult.Completed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,6 +291,14 @@ namespace Colosseum.Skills
|
||||
return ExecuteSkill(SkillLoadoutEntry.CreateTemporary(skill));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 타겟 오버라이드와 함께 스킬 시전
|
||||
/// </summary>
|
||||
public bool ExecuteSkill(SkillData skill, GameObject targetOverride)
|
||||
{
|
||||
return ExecuteSkill(SkillLoadoutEntry.CreateTemporary(skill), targetOverride);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 슬롯 엔트리 기준으로 스킬 시전
|
||||
/// </summary>
|
||||
@@ -340,6 +364,7 @@ namespace Colosseum.Skills
|
||||
currentLoadoutEntry = loadoutEntry != null ? loadoutEntry.CreateCopy() : SkillLoadoutEntry.CreateTemporary(skill);
|
||||
currentSkill = skill;
|
||||
lastCancelReason = SkillCancelReason.None;
|
||||
lastExecutionResult = SkillExecutionResult.Running;
|
||||
BuildResolvedEffects(currentLoadoutEntry);
|
||||
currentRepeatCount = currentLoadoutEntry.GetResolvedRepeatCount();
|
||||
currentIterationIndex = 0;
|
||||
@@ -706,7 +731,7 @@ namespace Colosseum.Skills
|
||||
Debug.Log($"[Skill] Cancelled: {currentSkill.SkillName} / reason={reason}");
|
||||
|
||||
RestoreBaseController();
|
||||
ClearCurrentSkillState();
|
||||
CompleteCurrentSkillExecution(SkillExecutionResult.Cancelled);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -945,7 +970,7 @@ namespace Colosseum.Skills
|
||||
Debug.Log($"[Skill] 채널링 종료: {currentSkill?.SkillName}");
|
||||
|
||||
RestoreBaseController();
|
||||
ClearCurrentSkillState();
|
||||
CompleteCurrentSkillExecution(SkillExecutionResult.Completed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1023,6 +1048,65 @@ namespace Colosseum.Skills
|
||||
currentIterationIndex = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 시전 중인 스킬을 지정 결과로 종료합니다.
|
||||
/// </summary>
|
||||
private void CompleteCurrentSkillExecution(SkillExecutionResult result)
|
||||
{
|
||||
lastExecutionResult = result;
|
||||
ClearCurrentSkillState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 적 스킬이 시전 중일 때 대상 추적 정책을 적용합니다.
|
||||
/// </summary>
|
||||
private void UpdateCastTargetTracking()
|
||||
{
|
||||
if (currentSkill == null || currentTargetOverride == null || !currentTargetOverride.activeInHierarchy)
|
||||
return;
|
||||
|
||||
var enemyBase = GetComponent<Colosseum.Enemy.EnemyBase>();
|
||||
if (enemyBase == null)
|
||||
return;
|
||||
|
||||
if (IsSpawned && !IsServer)
|
||||
return;
|
||||
|
||||
Vector3 direction = currentTargetOverride.transform.position - transform.position;
|
||||
direction.y = 0f;
|
||||
if (direction.sqrMagnitude < 0.0001f)
|
||||
return;
|
||||
|
||||
if (currentSkill.CastTargetTrackingMode == SkillCastTargetTrackingMode.FaceTarget ||
|
||||
currentSkill.CastTargetTrackingMode == SkillCastTargetTrackingMode.MoveTowardTarget)
|
||||
{
|
||||
Quaternion targetRotation = Quaternion.LookRotation(direction.normalized);
|
||||
float rotationSpeed = Mathf.Max(0f, currentSkill.CastTargetRotationSpeed);
|
||||
if (rotationSpeed <= 0f)
|
||||
transform.rotation = targetRotation;
|
||||
else
|
||||
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotationSpeed * 360f * Time.deltaTime);
|
||||
}
|
||||
|
||||
if (currentSkill.CastTargetTrackingMode != SkillCastTargetTrackingMode.MoveTowardTarget || currentSkill.UseRootMotion)
|
||||
return;
|
||||
|
||||
UnityEngine.AI.NavMeshAgent navMeshAgent = GetComponent<UnityEngine.AI.NavMeshAgent>();
|
||||
if (navMeshAgent == null || !navMeshAgent.enabled)
|
||||
return;
|
||||
|
||||
float stopDistance = Mathf.Max(0f, currentSkill.CastTargetStopDistance);
|
||||
if (direction.magnitude <= stopDistance)
|
||||
{
|
||||
navMeshAgent.isStopped = true;
|
||||
navMeshAgent.ResetPath();
|
||||
return;
|
||||
}
|
||||
|
||||
navMeshAgent.isStopped = false;
|
||||
navMeshAgent.SetDestination(currentTargetOverride.transform.position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 트리거 인덱스에 연결된 젬 이상상태를 적중 대상에게 적용합니다.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user