refactor: 집행개시 시그니처 전용 경로를 BT 일반 패턴 스텝으로 통합

- PatternStepType.ChargeWait 및 ChargeStepData 도입으로 충전/차단 판정을 일반 패턴 스텝으로 표현
- UsePatternByRoleAction에서 IsSignature 분기 완전 제거, 일반 패턴 경로로 통합
- BossCombatBehaviorContext에서 시그니처 전용 메서드 10개 이상 제거
- BossStaggerAction(신규): 충전 차단 성공 시 보스 경직 처리
- SignatureFailureEffectsAction(신규): 차단 실패 시 범위 피해/넉백/다운 적용
- RebuildDrogBehaviorAuthoringGraph에 시그니처 Sequence + outcomeBranch 구조 추가
- 집행개시 에셋 스텝 구성을 ChargeWait(3초) → Skill으로 변경
- BossHealthBarUI 시그니처 UI 비활성화, PlayerSkillDebugMenu 디버그 메서드 제거
This commit is contained in:
2026-04-01 14:21:38 +09:00
parent 0a0bc45209
commit e9e6257ad4
14 changed files with 2054 additions and 1893 deletions

View File

@@ -522,56 +522,6 @@ namespace Colosseum.Editor
Debug.Log($"[Debug] 보스를 Phase 2로 강제 전환했습니다. | Target={bossEnemy.name}");
}
[MenuItem("Tools/Colosseum/Debug/Force Boss Signature")]
private static void ForceBossSignature()
{
if (!EditorApplication.isPlaying)
{
Debug.LogWarning("[Debug] 플레이 모드에서만 사용할 수 있습니다.");
return;
}
BossCombatBehaviorContext context = FindBossCombatContext();
if (context == null)
{
Debug.LogWarning("[Debug] 보스 전투 컨텍스트를 찾지 못했습니다.");
return;
}
if (!context.ForceStartSignaturePattern())
{
Debug.LogWarning("[Debug] 집행 개시를 강제로 시작하지 못했습니다. 이미 실행 중이거나 패턴이 비어 있을 수 있습니다.");
return;
}
Debug.Log($"[Debug] 집행 개시를 강제로 시작했습니다. | Target={context.gameObject.name}");
}
[MenuItem("Tools/Colosseum/Debug/Preview Boss Signature Telegraph")]
private static void PreviewBossSignatureTelegraph()
{
if (!EditorApplication.isPlaying)
{
Debug.LogWarning("[Debug] 플레이 모드에서만 사용할 수 있습니다.");
return;
}
BossCombatBehaviorContext context = FindBossCombatContext();
if (context == null)
{
Debug.LogWarning("[Debug] 보스 전투 컨텍스트를 찾지 못했습니다.");
return;
}
if (!context.PreviewSignatureTelegraph())
{
Debug.LogWarning("[Debug] 집행 개시 전조 프리뷰를 시작하지 못했습니다. 이미 다른 스킬이 재생 중일 수 있습니다.");
return;
}
Debug.Log($"[Debug] 집행 개시 전조 프리뷰를 재생했습니다. | Target={context.gameObject.name}");
}
private static void ApplyBossShieldWithType(string assetPath, float amount, float duration)
{
if (!EditorApplication.isPlaying)

View File

@@ -259,15 +259,45 @@ namespace Colosseum.Editor
SetNodeFieldValue(leapUseNode, "Pattern", mobilityPattern, setFieldValueMethod);
LinkTarget(leapUseNode, targetVariable);
// #3 Signature — 집행 개시
// #3 Signature — 집행 개시 (Sequence: 패턴 실행 → 결과 분기)
// signatureBranch.True → Sequence:
// Child 1: 집행개시 패턴 실행 (ChargeWait 포함)
// Child 2: Branch(패턴 성공? = 차단 안 됨) → 범위 효과 또는 보스 경직
// 패턴이 Failure 반환(차단 성공) → Sequence Failure → signatureBranch False → 다음 우선순위
object signatureBranch = CreateNode(graphAsset, createNodeMethod, getNodeInfoMethod, branchCompositeType, new Vector2(branchX, startY + stepY * 2));
AttachPatternReadyCondition(signatureBranch, signaturePattern, authoringAssembly);
AttachPhaseConditionIfNeeded(signatureBranch, signaturePattern, authoringAssembly);
SetBranchRequiresAll(signatureBranch, true);
object signatureUseNode = CreateNode(graphAsset, createNodeMethod, getNodeInfoMethod, typeof(UsePatternByRoleAction), new Vector2(branchX + actionOffsetX, startY + stepY * 2 + actionOffsetY));
// Sequence: 패턴 실행 → 결과 분기
object signatureSequence = CreateNode(graphAsset, createNodeMethod, getNodeInfoMethod,
runtimeAssembly.GetType("Unity.Behavior.SequenceComposite", true),
new Vector2(branchX + 220f, startY + stepY * 2));
// Child 1: 집행개시 패턴 실행
object signatureUseNode = CreateNode(graphAsset, createNodeMethod, getNodeInfoMethod, typeof(UsePatternByRoleAction), new Vector2(branchX + 400f, startY + stepY * 2));
SetNodeFieldValue(signatureUseNode, "Pattern", signaturePattern, setFieldValueMethod);
LinkTarget(signatureUseNode, targetVariable);
// Child 2: 패턴 완료 시 결과 분기
// 패턴이 Success 반환(차단 안 됨 = 충전 완료) → True → 실패 효과 적용
// 패턴이 Failure 반환(차단 성공) → False → 보스 경직
object outcomeBranch = CreateNode(graphAsset, createNodeMethod, getNodeInfoMethod, branchCompositeType, new Vector2(branchX + 220f, startY + stepY * 2 + 180f));
object failureEffectsNode = CreateNode(graphAsset, createNodeMethod, getNodeInfoMethod, typeof(SignatureFailureEffectsAction), new Vector2(branchX + 400f, startY + stepY * 2 + 180f));
object staggerNode = CreateNode(graphAsset, createNodeMethod, getNodeInfoMethod, typeof(BossStaggerAction), new Vector2(branchX + 400f, startY + stepY * 2 + 360f));
// outcomeBranch True → 실패 효과 (충전 완료 = 플레이어들이 차단 실패)
ConnectBranch(graphAsset, connectEdgeMethod, outcomeBranch, "True", failureEffectsNode);
// outcomeBranch False → 보스 경직 (차단 성공)
ConnectBranch(graphAsset, connectEdgeMethod, outcomeBranch, "False", staggerNode);
// Sequence에 자식 연결
ConnectChildren(graphAsset, connectEdgeMethod, signatureSequence, signatureUseNode, outcomeBranch);
// 메인 체인: signatureBranch.True → Sequence
ConnectBranch(graphAsset, connectEdgeMethod, signatureBranch, "True", signatureSequence);
// #4 Combo — 콤보 패턴 + 조건부 도약 (Sequence)
// comboBranch.True → Sequence:
// Child 1: 연타2-강타 실행
@@ -339,7 +369,7 @@ namespace Colosseum.Editor
// ── FloatingPortNodeModel 생성 + 위치 보정 ──
// Branch 노드의 NamedPort(True/False)에 대해 FloatingPortNodeModel을 생성합니다.
// CreateNodePortsForNode는 기본 위치(Branch + 200px Y)를 사용하므로, 생성 후 사용자 조정 기준 위치로 이동합니다.
var allBranches = new List<object> { downBranch, leapBranch, signatureBranch };
var allBranches = new List<object> { downBranch, leapBranch, signatureBranch, outcomeBranch };
if (comboBranch != null) allBranches.Add(comboBranch);
allBranches.AddRange(new[] { primaryBranch, utilityBranch });
foreach (object branch in allBranches)
@@ -366,10 +396,10 @@ namespace Colosseum.Editor
Connect(graphAsset, connectEdgeMethod, GetDefaultOutputPort(startNode), GetDefaultInputPort(repeatNode));
Connect(graphAsset, connectEdgeMethod, GetDefaultOutputPort(repeatNode), GetDefaultInputPort(downBranch));
// 각 Branch의 True FloatingPort → Action (combo는 내부에서 Sequence로 연결됨)
// 각 Branch의 True FloatingPort → Action (combo, signature는 내부에서 Sequence로 연결됨)
ConnectBranch(graphAsset, connectEdgeMethod, downBranch, "True", downUseNode);
ConnectBranch(graphAsset, connectEdgeMethod, leapBranch, "True", leapUseNode);
ConnectBranch(graphAsset, connectEdgeMethod, signatureBranch, "True", signatureUseNode);
// signatureBranch.True는 signatureSequence에 이미 연결됨
ConnectBranch(graphAsset, connectEdgeMethod, primaryBranch, "True", primaryUseNode);
ConnectBranch(graphAsset, connectEdgeMethod, utilityBranch, "True", utilityUseNode);