Unity嘗試實現簡單的行為樹-01
初次嘗試,僅供參考,如有錯誤,懇請糾正
一、行為樹
行為樹是一個用來處理複雜邏輯的樹狀結構。
它會自頂向下搜尋到對應的葉子結點來執行相應的操作。
行為樹設計類似於組合設計模式。
行為樹的結點這裡粗略的分為枝結點和葉結點。
枝結點用來組織一個或以上的子節點,而葉結點用來進行判斷或執行相應的邏輯。
首先先實現枝節點中的以下型別:
- 根結點(Root):僅用來組織子結點以及啟動行為樹的搜尋。
- 選擇結點(Choose): 從眾多子結點中任選一個執行。
- 順序結點(Sequence):依次執行所有子結點。
以及以下葉結點:
- 執行結點(Do): 執行一個實際的操作。
- 判斷結點(If): 判斷一個條件,為true執行一個操作,為false執行另一個操作。
首先是所有結點的抽象類。
無論是葉子結點還是枝結點,執行具體的方法全部呼叫Execute()
public abstract class BTNode
{
public abstract void Execute();
}
二、枝結點
枝結點抽象類
public abstract class BTBranch : BTNode
{
//所有子結點的列表
private List<BTNode> childList = new List<BTNode>();
//建構函式初始化子結點
public BTBranch(params BTNode[] children) { if (children.Length == 0) return; OpenBranch(children); }
//初始子結點的方法,可直接呼叫或在建構函式呼叫
public BTBranch OpenBranch(params BTNode[] children)
{
if (children.Length == 0)
{
Debug.LogWarning("The params of OpenBranch() are empty!");
return this;
}
if (childList.Count != 0)
{
return NewBranch(children);
}
foreach (BTNode child in children)
{
childList.Add(child);
}
//模板方法模式,保留可重寫方法OpenBranchGain()留給子類實現
OpenBranchGain();
//返回自身物件,鏈式程式設計
return this;
}
//重設子結點列表
public BTBranch NewBranch(params BTNode[] children)
{
return ClearBranch().OpenBranch(children);
}
//清空子結點列表
public BTBranch ClearBranch()
{
List<BTNode> childList = ChildList();
childList.Clear();
return this;
}
//模板方法,留給子類增強OpenBranch()方法
protected virtual void OpenBranchGain() { }
public List<BTNode> ChildList() { return childList; }
}
根結點(Root)
public class Root : BTBranch
{
//呼叫父類構造,初始化子節點列表
public Root(params BTNode[] children) : base(children) { }
public override void Execute()
{
if (ChildList().Count == 0)
//自定義異常
throw new NoElementException("There is no element in ChildList, be sure use OpenBranch to init!");
//遍歷子節點執行
foreach (BTNode child in ChildList())
{
child.Execute();
}
}
}
選擇結點(Choose)
public class Choose : BTBranch
{
public Choose(params BTNode[] children) : base(children) { }
//從子節點任選其一執行
public override void Execute()
{
List<BTNode> childList = ChildList();
if (childList.Count == 0)
throw new NoElementException("There is no element for Choose Branch to choose!");
childList[UnityEngine.Random.Range(0, childList.Count)].Execute();
}
}
順序結點和根結點邏輯相同,僅在用途上做區分。
三、葉結點
葉結點抽象類
public abstract class BTLeaf : BTNode
{
//葉結點下一執行結點
protected BTNode next;
public BTLeaf(BTNode _next = null)
{
next = _next;
}
public virtual BTNode SetNext(BTNode _next)
{
next = _next;
return this;
}
}
葉結點兩種委託抽象
public abstract class FuncBehavior<T> : BTLeaf
{
protected Func<T> func;
public FuncBehavior(Func<T> _func, BTNode _next = null) : base(_next)
{
func = _func;
}
}
public abstract class ActionBehavior : BTLeaf
{
protected Action action;
public ActionBehavior(Action _action, BTNode _next = null) : base(_next)
{
action = _action;
}
}
判斷結點(If)
public class If : FuncBehavior<bool>
{
//判斷為false時執行結點
private BTNode nextFalse;
public If(Func<bool> _func, BTNode _next = null, BTNode _else = null)
: base(_func, _next)
{
nextFalse = _else;
}
public override void Execute()
{
if (func == null)
throw new BehaviorIsNullException("Func<> is null in If Leaf!");
//判斷並選擇執行下一結點
if (func.Invoke())
{
if (next != null)
{
next.Execute();
}
}
else
{
if (nextFalse != null)
{
nextFalse.Execute();
}
}
}
}
執行結點(Do)
public class Do : ActionBehavior
{
public Do(Action _action, BTNode _next) : base(_action, _next) { }
public override void Execute()
{
if (action == null)
throw new BehaviorIsNullException("Action is null in Do Leaf!");
action.Invoke();
if (next != null)
{
next.Execute();
}
}
}
結點靜態工廠
public static class BT
{
public static Root Root(params BTNode[] children) { return new Root(children); }
public static Choose Choose(params BTNode[] children) { return new Choose(children); }
public static Sequence Sequence(params BTNode[] children) { return new Sequence(children); }
public static Do Do(Action _action, BTNode _next = null) { return new Do(_action, _next); }
public static If If(Func<bool> _func, BTNode _next = null, BTNode _else = null) { return new If(_func, _next, _else); }
}
例項測試A
private void Start()
{
Root root = BT.Root();
root.OpenBranch(
BT.If(
() => { return false; },
BT.Do(
() => { Debug.Log("If結點返回true後的執行結點"); },
BT.Do(() => { Debug.Log("下一結點1"); })),
BT.Do(
() => { Debug.Log("If結點返回false後的執行結點"); },
BT.Do(() => { Debug.Log("下一結點2"); }))
)
).Execute();
}
結構
輸出
測試例項B
root.NewBranch(
BT.Choose(
BT.Do(() => { Debug.Log("選擇結點執行者A"); }),
BT.Do(() => { Debug.Log("選擇結點執行者B"); }),
BT.Do(() => { Debug.Log("選擇結點執行者C"); })
)
).Execute();
結構
輸出
測試例項C
root.NewBranch(
BT.Sequence(
BT.Do(() => { Debug.Log("順序結點執行者1"); }),
BT.Do(() => { Debug.Log("順序結點執行者2"); }),
BT.Do(() => { Debug.Log("順序結點執行者3"); })
)
);
root.Execute();
結構同選擇結點
輸出
如有錯誤,懇請糾正
下接:
相關文章
- Unity實現簡單的物件池Unity物件
- kd樹的簡單實現
- 字典樹(字首樹)簡單實現
- 嘗試讓查詢更簡單
- MySQL刪除資料的簡單嘗試MySql
- go1.18泛型的簡單嘗試Go泛型
- ajax實現列表連動的嘗試
- 【開源之路】溫蒂、一次簡單的嘗試
- MySQL控制程式碼恢復的簡單嘗試MySql
- unity3d 嘗試 基於地理定位的 擴增實境Unity3D
- 6 個可以嘗試的樹莓派教程樹莓派
- Unity 高清渲染管線 ShaderGraph 實現簡單的表面水流效果Unity
- 在Unity中實現一個簡單的訊息管理器Unity
- JavaScript實現簡單二叉查詢樹JavaScript
- 嘗試做一個.NET簡單、高效、避免OOM的Excel工具OOMExcel
- 在 PC 上嘗試樹莓派的 PIXEL OS樹莓派
- MySQL 5.5複製升級到5.7的一點簡單嘗試MySql
- 【原創】簡單嘗試脫“愛加密”官網加固的DEX殼加密
- 實現簡單的BitMap
- ArrayList的簡單實現
- AOP的簡單實現
- 簡單的 HashMap 實現HashMap
- 簡單的Filter實現Filter
- Promise的簡單實現Promise
- 試著用Proxy 實現一個簡單mvvmMVVM
- 簡單介紹Angular單元測試之事件觸發的實現Angular事件
- 【unity】 Loom實現多執行緒UnityOOM執行緒
- 簡單的Java實現Netty進行通訊JavaNetty
- 執行緒池的介紹及簡單實現執行緒
- 推薦五款簡潔而實用的工具,值得你嘗試
- Unity基於NGUI的簡單並可直接使用的虛擬搖桿實現(一)UnityNGUI
- 簡單的實現vue原理Vue
- 簡單的實現React原理React
- java實現簡單的JDBCJavaJDBC
- php實現簡單的SQLBuilderPHPSQLUI
- 用unity製作簡單的太空遊戲(2)-簡單炮臺Unity遊戲
- 簡單實現Laravel獲取當前執行的SQLLaravelSQL
- Promise 簡單實現Promise