어째서..
몬스터 BT는 DFS(Depth First Search : 깊이우선탐색) 구조로 구성되었다.
현재 기본동작으로 idle, die, track, attack을 구현했지만 이후 플레이어의 패링시 피격(hit)이라던지 attack 모션도 조건문으로 구성되는 다양한 공격들이 존재한다.
INode SettingBT()
{
return new SelectorNode
(
new List<INode>()
{
new SequenceNode
(
new List<INode>()
{
new ConditionNode(() => bossHP ==0, BossDie),
new ActionNode(BossTrack),
new ActionNode(BossNornalAttack1),
}
),
new ActionNode(BossIdle)
}
);
}
조건에 조건으로 계속 들어간다면 이 구조는 한눈에 보기가 어려워진다.
그러면 어떻게 하죠..?
노드를 데이터구조화 시키면 어떨까?
노드를 세팅하고 각 노드에 데이터를 빌드하는 구조라면 앞으로 더 추가될 조건들과 구성 노드를 구성하기 편리할거같다(?)
그렇다면 각 노드를 어떻게 데이터화 시킬것인가?
JSON으로 관리시..
Json
"키" : {"값"}
"selector": { "type", "child" }
"sequence": { "child" }
"if": { "trueCondition", "action"}
attack의 "selector"는 무작위로 구현된다는 조건이 있어 "selector"는 타입이 존재해야한다.
SelectorType
- Normal(0) => 우선 순위 높은 것부터 차례대로 노드를 평가한다.
- Random(1) => 자식 중에서 무작위로 선택하여 평가한다.
{
"selector" : {
"type": 0,
"child": {
"selector": {
"type": 0,
"child": {
"if": {
"trueCondition": "IsEmptyHp",
"action": "BossDie"
.
.
.
},
"BossAttack",
"BossTrack"
}
}
}
}
}
보기 어렵다.
다른 프로젝트의 BT는 어떤식으로 데이터구성을 했을까?
배열에 모든 노드를 저장해서 쓴다.
디자인 패턴
빌더 패턴
enum MinotaurosActionType
{
Die,
Attack,
Track,
Idle
}
[Die][Attack][Track][Idle]
class MinotaurosBuilder : Builder
{
void Init()
{
MinotaurosActionType을 기반으로 배열에 액션 노드를 저장한다.
}
override void Build()
{
selector5 = Selector.
AddChild((GetNode((int)MinotaurosActionType.NormalAttack1))).
AddChild((GetNode((int)MinotaurosActionType.NormalAttack2))).
AddChild((GetNode((int)MinotaurosActionType.ComboAttack1))).
AddChild((GetNode((int)MinotaurosActionType.ComboAttack2))).
SetType(SelectorType.Random).
Build();
sequence = Sequence.
AddChild((GetNode((int)MinotaurosActionType.Backstep))).
AddChild((GetNode((int)MinotaurosActionType.Stumping))).
Build();
selector4 = Selector.
AddChild(sequence.SetCondition(player is behind me)).
AddChild(GetNode((int)MinotaurosActionType.KickAttack).SetCondition(player is defense)).
AddChild(selector5).
Build();
selector3 = ControlNodeBuilder.
AddChild(selctor4.SetCondition(player is in attack range)).
AddChild(GetNode((int)MinotaurosActionType.JumpAttack).SetCondition(player is out of attack range)).
Build<Selector>();
selector2 = Selector.
AddChild(GetNode(Die).SetCondition(hp == 0)).
AddChild(GetNode(Hit).SetCondition(방어 상태)).
AddChild(selector3).
AddChild(GetNode(BossTrack).SetCondition(공격 범위 내에 없다면)).
Build();
selector1 = Selector.
AddChild(selector2.SetCondition(보스룸 진입)).
AddCConhild(GetNode(Idle)).
Build();
Root.child = selector1;
}
}
노드 생성 - 노드 빌드 - 데이터 입력으로 빌드한다.