feat: 드로그 BT 및 전투 패턴 재구성
- 드로그 BT를 페이즈 전환, 부활 트리거, 가중치 근접 패턴 중심으로 재구성 - 땅 울리기 및 콤보-기본기1_3 패턴/스킬/이펙트를 추가하고 기존 평타 파생 자산을 정리 - 드로그 행동 검증용 PlayMode/Editor 테스트와 관련 런타임 상태 추적을 추가
This commit is contained in:
115
Assets/_Game/Scripts/AI/WeightedPatternSelector.cs
Normal file
115
Assets/_Game/Scripts/AI/WeightedPatternSelector.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using Colosseum.AI.BehaviorActions.Conditions;
|
||||
|
||||
namespace Colosseum.AI
|
||||
{
|
||||
/// <summary>
|
||||
/// 가중치 기반 패턴 선택 후보를 표현합니다.
|
||||
/// </summary>
|
||||
public readonly struct WeightedPatternCandidate
|
||||
{
|
||||
public WeightedPatternCandidate(BossPatternData pattern, float weight)
|
||||
{
|
||||
Pattern = pattern;
|
||||
Weight = weight;
|
||||
}
|
||||
|
||||
public BossPatternData Pattern { get; }
|
||||
|
||||
public float Weight { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 준비된 패턴 후보 중 하나를 가중치 기반으로 선택합니다.
|
||||
/// </summary>
|
||||
public static class WeightedPatternSelector
|
||||
{
|
||||
public static bool HasAnyReadyPattern(GameObject owner, IReadOnlyList<WeightedPatternCandidate> candidates)
|
||||
{
|
||||
if (owner == null || candidates == null)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < candidates.Count; i++)
|
||||
{
|
||||
WeightedPatternCandidate candidate = candidates[i];
|
||||
if (candidate.Pattern == null || candidate.Weight <= 0f)
|
||||
continue;
|
||||
|
||||
if (PatternReadyHelper.IsPatternReady(owner, candidate.Pattern))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TrySelectReadyPattern(GameObject owner, IReadOnlyList<WeightedPatternCandidate> candidates, out BossPatternData selectedPattern)
|
||||
{
|
||||
if (owner == null)
|
||||
{
|
||||
selectedPattern = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return TrySelectPattern(
|
||||
candidates,
|
||||
pattern => PatternReadyHelper.IsPatternReady(owner, pattern),
|
||||
UnityEngine.Random.value,
|
||||
out selectedPattern);
|
||||
}
|
||||
|
||||
public static bool TrySelectPattern(
|
||||
IReadOnlyList<WeightedPatternCandidate> candidates,
|
||||
Predicate<BossPatternData> isPatternReady,
|
||||
float normalizedRoll,
|
||||
out BossPatternData selectedPattern)
|
||||
{
|
||||
selectedPattern = null;
|
||||
|
||||
if (candidates == null || isPatternReady == null)
|
||||
return false;
|
||||
|
||||
List<WeightedPatternCandidate> readyCandidates = new List<WeightedPatternCandidate>(candidates.Count);
|
||||
float totalWeight = 0f;
|
||||
|
||||
for (int i = 0; i < candidates.Count; i++)
|
||||
{
|
||||
WeightedPatternCandidate candidate = candidates[i];
|
||||
if (candidate.Pattern == null || candidate.Weight <= 0f)
|
||||
continue;
|
||||
|
||||
if (!isPatternReady(candidate.Pattern))
|
||||
continue;
|
||||
|
||||
readyCandidates.Add(candidate);
|
||||
totalWeight += candidate.Weight;
|
||||
}
|
||||
|
||||
if (readyCandidates.Count == 0 || totalWeight <= 0f)
|
||||
return false;
|
||||
|
||||
float clampedRoll = Mathf.Clamp01(normalizedRoll);
|
||||
float targetWeight = clampedRoll >= 1f
|
||||
? totalWeight
|
||||
: totalWeight * clampedRoll;
|
||||
float cumulativeWeight = 0f;
|
||||
|
||||
for (int i = 0; i < readyCandidates.Count; i++)
|
||||
{
|
||||
WeightedPatternCandidate candidate = readyCandidates[i];
|
||||
cumulativeWeight += candidate.Weight;
|
||||
|
||||
if (targetWeight < cumulativeWeight || i == readyCandidates.Count - 1)
|
||||
{
|
||||
selectedPattern = candidate.Pattern;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user