mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-27 02:36:14 +00:00
提交行为树
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3be96e8bdaa9f2d4cbee49a5a50f1c46
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,26 @@
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class Log : ActionNode
|
||||
{
|
||||
[OutField]
|
||||
public string Text = "";
|
||||
|
||||
public Log()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Log(string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
|
||||
public override TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
UnityEngine.Debug.Log(Text);
|
||||
return TaskResult.OK;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12eb3d1ed40dd6841a70f69a5dbab9b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: -5442936267250999957, guid: 0000000000000000d000000000000000, type: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,38 @@
|
||||
using System.Xml.Serialization;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class Wait : ActionNode
|
||||
{
|
||||
[OutField]
|
||||
public LFloat time = 3;
|
||||
|
||||
LFloat t;
|
||||
|
||||
[ShowMe]
|
||||
private LFloat timer;
|
||||
|
||||
public Wait()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Wait(LFloat time)
|
||||
{
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public override TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
timer += dt;
|
||||
if (timer >= time)
|
||||
{
|
||||
UnityEngine.Debug.Log(timer);
|
||||
timer = 0;
|
||||
return TaskResult.OK;
|
||||
}
|
||||
return TaskResult.Running;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8757ac0a11021a34da305a81f5b8b230
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 3306451490063965843, guid: 0000000000000000d000000000000000, type: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JNGame.Math;
|
||||
using JNGame.Runtime.Util;
|
||||
using UnityEngine;
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// Agent of behavior tree,
|
||||
/// This class is not required.
|
||||
/// You only need to call Entry.update in the right place to drive the behavior tree to run
|
||||
/// use event drive method to communicate data with outside
|
||||
/// </summary>
|
||||
public class BehaviorTree : MonoBehaviour,IBehaviorTree
|
||||
{
|
||||
public bool AutoRun;
|
||||
Dictionary<string, Action<object>> actions = new Dictionary<string, Action<object>>();
|
||||
|
||||
//随机数
|
||||
private Func<LFloat,LFloat,LFloat> nRandomFloat = RandomUtil.SyncRandomFloat(100000);
|
||||
|
||||
public void Regist(string key, Action<object> onEvent)
|
||||
{
|
||||
if (actions.ContainsKey(key))
|
||||
{
|
||||
actions[key] = onEvent;
|
||||
}
|
||||
else
|
||||
{
|
||||
actions.Add(key, onEvent);
|
||||
}
|
||||
}
|
||||
public void UnRegist(string key)
|
||||
{
|
||||
actions.Remove(key);
|
||||
}
|
||||
public void Dispatch(string key, object obj)
|
||||
{
|
||||
if (actions.ContainsKey(key))
|
||||
{
|
||||
actions[key].Invoke(obj);
|
||||
}
|
||||
}
|
||||
public TextAsset config;
|
||||
Entry Entry;
|
||||
public List<GameObject> Obj = new List<GameObject>();
|
||||
Dictionary<string, object> blackBoard = new Dictionary<string, object>();
|
||||
|
||||
public object this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (blackBoard.TryGetValue(key, out object v))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
GameObject obj = Obj.Find(o => o.name.Equals(key));
|
||||
return obj;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (blackBoard.ContainsKey(key))
|
||||
{
|
||||
blackBoard[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
blackBoard.Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Remove(string key)
|
||||
{
|
||||
blackBoard.Remove(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Load();
|
||||
if (AutoRun) Entry?.Enter(this);
|
||||
}
|
||||
|
||||
public Entry Load()
|
||||
{
|
||||
if (Entry == null && config != null)
|
||||
{
|
||||
Entry = XmlUtils.DeSerialize<Entry>(config.text);
|
||||
}
|
||||
return Entry;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
Entry?.Tick(Time.deltaTime.ToLFloat(), this);
|
||||
}
|
||||
|
||||
public LFloat RandomFloat(LFloat min, LFloat max)
|
||||
{
|
||||
return nRandomFloat(min,max);
|
||||
}
|
||||
|
||||
public LFloat RandomFloat()
|
||||
{
|
||||
return RandomFloat(LFloat.L0,LFloat.L1);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81bd213a0dba8f645b8ddd263e34a884
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 8522ed20ce035d14e8d416af9f830453, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8184935def5f8a4ba937d1c55959207
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,34 @@
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
|
||||
public class Entry : Sequence
|
||||
{
|
||||
public string Serielize(TreeNode node)
|
||||
{
|
||||
string s = UnityEngine.JsonUtility.ToJson(node);
|
||||
if (node is ComponentNode)
|
||||
{
|
||||
ComponentNode cp = node as ComponentNode;
|
||||
int count = cp.childs.Count;
|
||||
if (count > 0)
|
||||
{
|
||||
string c = "\"childs\":[";
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
c += Serielize(cp.childs[i]);
|
||||
if (i < count - 1)
|
||||
{
|
||||
c += ",";
|
||||
}
|
||||
}
|
||||
c += "],";
|
||||
int idx = s.IndexOf("Sid");
|
||||
s = s.Insert(idx - 1, c);
|
||||
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d696c6aad8fd4f343affd37d2d186384
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2974397684917235467, guid: 0000000000000000d000000000000000, type: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,44 @@
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class MagicQueue : CompositeNode
|
||||
{
|
||||
TreeNode last;
|
||||
public override void Enter(object args)
|
||||
{
|
||||
|
||||
}
|
||||
public override void Exit(object args)
|
||||
{
|
||||
|
||||
}
|
||||
public override TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
childs.Sort((a, b) => a.x < b.x ? -1 : 1);
|
||||
if (childs.Count == 0)
|
||||
{
|
||||
return TaskResult.Fail;
|
||||
}
|
||||
TreeNode curNode = childs[Index];
|
||||
if (last != curNode)
|
||||
{
|
||||
curNode.Enter(args);
|
||||
}
|
||||
TaskResult result = curNode.Tick(dt, args);
|
||||
last = curNode;
|
||||
curNode.state = result;
|
||||
if (result == TaskResult.Running)
|
||||
{
|
||||
return TaskResult.Running;
|
||||
}
|
||||
if (result == TaskResult.OK)
|
||||
{
|
||||
curNode.Exit(args);
|
||||
Index = (Index + 1) % childs.Count;
|
||||
return TaskResult.OK;
|
||||
}
|
||||
return TaskResult.Fail;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0a3bd4c80e1a724c86971760131c651
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 6519382022992737161, guid: 0000000000000000d000000000000000, type: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,61 @@
|
||||
using JNGame.Math;
|
||||
using Random = System.Random;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class MagicRandom : CompositeNode
|
||||
{
|
||||
|
||||
[OutField]
|
||||
public int[] Power;
|
||||
|
||||
TreeNode last;
|
||||
|
||||
public override TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
if (childs.Count == 0) return TaskResult.Fail;
|
||||
|
||||
childs.Sort((a, b) => a.x < b.x ? -1 : 1);
|
||||
|
||||
if (last == null)
|
||||
{
|
||||
Index = CheckRandom((args as IBehaviorTree));
|
||||
}
|
||||
if (last != childs[Index])
|
||||
{
|
||||
childs[Index].Enter(args);
|
||||
}
|
||||
TreeNode curNode = childs[Index];
|
||||
TaskResult result = curNode.Tick(dt, args);
|
||||
last = curNode;
|
||||
curNode.state = result;
|
||||
if (result == TaskResult.Running)
|
||||
{
|
||||
return TaskResult.Running;
|
||||
}
|
||||
curNode.Exit(args);
|
||||
Index = CheckRandom((args as IBehaviorTree));
|
||||
return result;
|
||||
}
|
||||
int CheckRandom(IBehaviorTree behavior)
|
||||
{
|
||||
int sum = 0;
|
||||
int length = Power.Length <= childs.Count ? Power.Length : childs.Count;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
sum += Power[i];
|
||||
}
|
||||
LFloat r = behavior.RandomFloat() * sum;
|
||||
int cache = 0;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
cache += Power[i];
|
||||
if (cache > r)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return length - 1;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c8836dec99f8324a859ff3a06b603b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 7174288486110832750, guid: 0000000000000000d000000000000000, type: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,70 @@
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class Selector : CompositeNode
|
||||
{
|
||||
public override void Enter(object args)
|
||||
{
|
||||
Index = 0;
|
||||
}
|
||||
private TreeNode last;
|
||||
public override void Add(TreeNode component)
|
||||
{
|
||||
base.Add(component);
|
||||
Index = 0;
|
||||
state = TaskResult.None;
|
||||
}
|
||||
public override TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
childs.Sort((a, b) => a.x < b.x ? -1 : 1);
|
||||
for (int i = Index; i < childs.Count; i++)
|
||||
{
|
||||
if (last != childs[i])
|
||||
{
|
||||
childs[i].Enter(args);
|
||||
}
|
||||
TaskResult rst = childs[i].Tick(dt, args);
|
||||
childs[i].state = rst;
|
||||
last = childs[i];
|
||||
if (rst == TaskResult.OK)
|
||||
{
|
||||
childs[i].Exit(args);
|
||||
return TaskResult.OK;
|
||||
}
|
||||
else if (rst == TaskResult.Running)
|
||||
{
|
||||
bool cdt = false;
|
||||
int cdtCount = 0;
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
if (childs[j] is ConditionalNode)
|
||||
{
|
||||
cdtCount++;
|
||||
cdt |= (childs[j] as ConditionalNode).Check(dt, args);
|
||||
}
|
||||
}
|
||||
if (cdt && cdtCount > 0)
|
||||
{
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
if (childs[j] is ConditionalNode)
|
||||
{
|
||||
(childs[j] as ConditionalNode).IsConditionOK = false;
|
||||
}
|
||||
}
|
||||
childs[i].Exit(args);
|
||||
return TaskResult.OK;
|
||||
}
|
||||
return TaskResult.Running;
|
||||
}
|
||||
else
|
||||
{
|
||||
childs[i].Exit(args);
|
||||
Index = i + 1;
|
||||
}
|
||||
}
|
||||
return TaskResult.Fail;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fc8f80689c7eda542ba6223140cb2ed3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 1206586993520771344, guid: 0000000000000000d000000000000000, type: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,74 @@
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class Sequence : CompositeNode
|
||||
{
|
||||
private TreeNode last;
|
||||
|
||||
public override void Enter(object args)
|
||||
{
|
||||
Index = 0;
|
||||
}
|
||||
public override void Add(TreeNode component)
|
||||
{
|
||||
base.Add(component);
|
||||
Index = 0;
|
||||
state = TaskResult.None;
|
||||
}
|
||||
public override TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
childs.Sort((a, b) => a.x < b.x ? -1 : 1);
|
||||
for (int i = Index; i < childs.Count; i++)
|
||||
{
|
||||
if (last != childs[i])
|
||||
{
|
||||
childs[i].Enter(args);
|
||||
}
|
||||
TaskResult rst = childs[i].Tick(dt, args);
|
||||
childs[i].state = rst;
|
||||
last = childs[i];
|
||||
if (rst == TaskResult.OK || rst == TaskResult.None)
|
||||
{
|
||||
childs[i].Exit(args);
|
||||
Index = i + 1;
|
||||
}
|
||||
else if (rst == TaskResult.Running)
|
||||
{
|
||||
bool cdt = true;
|
||||
int cdtCount = 0;
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
if (childs[j] is ConditionalNode)
|
||||
{
|
||||
cdtCount++;
|
||||
cdt &= (childs[j] as ConditionalNode).Check(dt, args);
|
||||
}
|
||||
}
|
||||
if (cdt && cdtCount > 0)
|
||||
{
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
if (childs[j] is ConditionalNode)
|
||||
{
|
||||
(childs[j] as ConditionalNode).IsConditionOK = false;
|
||||
}
|
||||
}
|
||||
childs[i].Exit(args);
|
||||
Index = i + 1;
|
||||
return TaskResult.OK;
|
||||
}
|
||||
return TaskResult.Running;
|
||||
}
|
||||
else
|
||||
{
|
||||
childs[i].Exit(args);
|
||||
Index = i + 1;
|
||||
return TaskResult.Fail;
|
||||
}
|
||||
}
|
||||
return TaskResult.OK;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e339237f68bd0f3409e91f5c2fea38b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: -5487077368411116049, guid: 0000000000000000d000000000000000, type: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 080fa34971cf43941832712f1ac3987f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class EventCaller : ConditionalNode
|
||||
{
|
||||
[OutField]
|
||||
public string Event;
|
||||
public override void Enter(object args)
|
||||
{
|
||||
BehaviorTree tree = (BehaviorTree)args;
|
||||
if (!string.IsNullOrEmpty(Event))
|
||||
tree.Regist(Event, OnEvent);
|
||||
|
||||
}
|
||||
public override void Exit(object args)
|
||||
{
|
||||
|
||||
}
|
||||
private void OnEvent(object obj)
|
||||
{
|
||||
IsConditionOK = true;
|
||||
}
|
||||
public override TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
return IsConditionOK ? TaskResult.Running : TaskResult.None;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 034fc570e45c74342bba94a7887014bf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class RandomCall : ConditionalNode
|
||||
{
|
||||
[OutField]
|
||||
public LFloat Rand = new LFloat("",200);
|
||||
[OutField]
|
||||
public LFloat Freq=1;
|
||||
[ShowMe]
|
||||
LFloat timer;
|
||||
public override bool Check(LFloat dt, object args)
|
||||
{
|
||||
timer += dt;
|
||||
if (timer > Freq)
|
||||
{
|
||||
timer = 0;
|
||||
IsConditionOK = (args as IBehaviorTree).RandomFloat() < Rand;
|
||||
}
|
||||
return base.Check(dt, args);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98c39464e2b77524492cfbcf228305fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 686c0676a99f6314b93014517e377f30
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,12 @@
|
||||
using BehaviorTreeSlayer;
|
||||
using System;
|
||||
|
||||
public class ActionNode : TreeNode
|
||||
{
|
||||
public override void VisitTree(TreeNode node, Action<TreeNode> action)
|
||||
{
|
||||
action?.Invoke(node);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33894d1d8b8c6e74db14a36ec2d18f04
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class ComponentNode : TreeNode
|
||||
{
|
||||
public List<TreeNode> childs = new List<TreeNode>();
|
||||
[XmlIgnore]
|
||||
public int Index = 0;
|
||||
|
||||
public virtual void Add(TreeNode component)
|
||||
{
|
||||
childs.Add(component);
|
||||
Index = 0;
|
||||
}
|
||||
public virtual void Remove(TreeNode component)
|
||||
{
|
||||
childs.Remove(component);
|
||||
Index = 0;
|
||||
}
|
||||
public override void Enter(object args)
|
||||
{
|
||||
base.Enter(args);
|
||||
Index = 0;
|
||||
}
|
||||
public override void Exit(object args)
|
||||
{
|
||||
base.Exit(args);
|
||||
Index = 0;
|
||||
}
|
||||
public override void VisitTree(TreeNode node, System.Action<TreeNode> action)
|
||||
{
|
||||
action?.Invoke(node);
|
||||
if (node is ComponentNode)
|
||||
{
|
||||
ComponentNode cp = node as ComponentNode;
|
||||
for (int i = 0; i < cp.childs.Count; i++)
|
||||
{
|
||||
VisitTree(cp.childs[i], action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
Index = 0;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 878b80932be62944aa8f0c1c4b12fd3d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,7 @@
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class CompositeNode : ComponentNode
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 737c340275e26864db0128f2adf450d9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,26 @@
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// TaskResult.Running Node will check this for quit
|
||||
/// </summary>
|
||||
public class ConditionalNode : TreeNode
|
||||
{
|
||||
[System.Xml.Serialization.XmlIgnore]
|
||||
public bool IsConditionOK { get; set; }
|
||||
|
||||
public virtual bool Check(LFloat dt, object args)
|
||||
{
|
||||
return IsConditionOK;
|
||||
}
|
||||
public override TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
return TaskResult.None;
|
||||
}
|
||||
public override void Reset()
|
||||
{
|
||||
IsConditionOK = false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb07e1739da08984db81a1af73f128e5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,11 @@
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class DecoratorNode : ComponentNode
|
||||
{
|
||||
public override void Add(TreeNode component)
|
||||
{
|
||||
childs.Clear();
|
||||
base.Add(component);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8464b683c4af17d47b42d115f6947316
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,15 @@
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public interface IState
|
||||
{
|
||||
TaskResult Tick(LFloat dt, object args = null);
|
||||
void Enter(object args);
|
||||
void Exit(object args);
|
||||
}
|
||||
public enum TaskResult : int
|
||||
{
|
||||
None, OK, Fail, Running
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9766e0ff89cd9fa4bb9ec0d937e7bf63
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
[System.Serializable]
|
||||
public class TreeNode : IState
|
||||
{
|
||||
[XmlIgnore]
|
||||
public TaskResult state;
|
||||
/// <summary>
|
||||
/// Editor Pos
|
||||
/// </summary>
|
||||
public LFloat x, y;
|
||||
|
||||
public virtual void Enter(object args)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Exit(object args)
|
||||
{
|
||||
}
|
||||
public TreeNode Copy(TreeNode node)
|
||||
{
|
||||
TreeNode t = this.Clone() as TreeNode;
|
||||
t.x = node.x;
|
||||
t.y = node.y;
|
||||
if (node is ComponentNode)
|
||||
{
|
||||
ComponentNode cp = node as ComponentNode;
|
||||
ComponentNode tt = t as ComponentNode;
|
||||
for (int i = 0; i < cp.childs.Count; i++)
|
||||
{
|
||||
TreeNode child = cp.childs[i];
|
||||
tt.Add(child.Copy(child));
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
public virtual TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
return TaskResult.OK;
|
||||
}
|
||||
public virtual void Reset()
|
||||
{
|
||||
state = TaskResult.None;
|
||||
}
|
||||
TreeNode Clone()
|
||||
{
|
||||
return Activator.CreateInstance(this.GetType()) as TreeNode;
|
||||
}
|
||||
|
||||
public virtual void VisitTree(TreeNode node, System.Action<TreeNode> action)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd323d3daa2a13a41a4a45ba71eeefb4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14276fe27b4d09d409cb47f3a70198eb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class Inverter : DecoratorNode
|
||||
{
|
||||
public override TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
if (childs.Count > 0)
|
||||
{
|
||||
TaskResult rs = childs[0].Tick(dt, args);
|
||||
childs[0].state = rs;
|
||||
switch (rs)
|
||||
{
|
||||
case TaskResult.OK:
|
||||
childs[0].Exit(args);
|
||||
return TaskResult.Fail;
|
||||
case TaskResult.Fail:
|
||||
childs[0].Exit(args);
|
||||
return TaskResult.OK;
|
||||
case TaskResult.Running:
|
||||
return TaskResult.Running;
|
||||
default:
|
||||
return TaskResult.None;
|
||||
}
|
||||
}
|
||||
return TaskResult.Fail;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d52021fdec8f6d84297f35e294a28417
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,30 @@
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class Repeat : DecoratorNode
|
||||
{
|
||||
public override TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
if (childs.Count > 0)
|
||||
{
|
||||
TaskResult rs = childs[0].Tick(dt, args);
|
||||
childs[0].state = rs;
|
||||
switch (rs)
|
||||
{
|
||||
case TaskResult.OK:
|
||||
childs[0].Exit(args);
|
||||
return TaskResult.Running;
|
||||
case TaskResult.Fail:
|
||||
childs[0].Exit(args);
|
||||
return TaskResult.Running;
|
||||
case TaskResult.Running:
|
||||
return TaskResult.Running;
|
||||
default:
|
||||
return TaskResult.None;
|
||||
}
|
||||
}
|
||||
return TaskResult.Fail;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f359536e5bdfae439e7ceb5a315ee38
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class UntilFail : DecoratorNode
|
||||
{
|
||||
public override TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
if (childs.Count > 0)
|
||||
{
|
||||
TaskResult rs = childs[0].Tick(dt, args);
|
||||
childs[0].state = rs;
|
||||
switch (rs)
|
||||
{
|
||||
case TaskResult.OK:
|
||||
childs[0].Exit(args);
|
||||
return TaskResult.Running;
|
||||
case TaskResult.Fail:
|
||||
childs[0].Exit(args);
|
||||
return TaskResult.Fail;
|
||||
case TaskResult.Running:
|
||||
return TaskResult.Running;
|
||||
default:
|
||||
return TaskResult.None;
|
||||
}
|
||||
}
|
||||
return TaskResult.Fail;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6017b9db8461cf43b2e2c2650cff46e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class UntilOk : DecoratorNode
|
||||
{
|
||||
public override TaskResult Tick(LFloat dt, object args = null)
|
||||
{
|
||||
if (childs.Count > 0)
|
||||
{
|
||||
TaskResult rs = childs[0].Tick(dt, args);
|
||||
childs[0].state = rs;
|
||||
switch (rs)
|
||||
{
|
||||
case TaskResult.OK:
|
||||
childs[0].Exit(args);
|
||||
return TaskResult.OK;
|
||||
case TaskResult.Fail:
|
||||
childs[0].Exit(args);
|
||||
return TaskResult.Running;
|
||||
case TaskResult.Running:
|
||||
return TaskResult.Running;
|
||||
default:
|
||||
return TaskResult.None;
|
||||
}
|
||||
}
|
||||
return TaskResult.Fail;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e85da6e1c87d07e478692a67c67d2e87
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,14 @@
|
||||
using JNGame.Math;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public interface IBehaviorTree
|
||||
{
|
||||
/// <summary>
|
||||
/// 随机Float
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract LFloat RandomFloat(LFloat min,LFloat max);
|
||||
public abstract LFloat RandomFloat();
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99f0f308232b4e5ba3f7b497af3098c1
|
||||
timeCreated: 1729925751
|
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using JNGame.Math;
|
||||
using JNGame.Runtime.Util;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// 运行时 行为
|
||||
/// </summary>
|
||||
public class JNBehaviorTree : IBehaviorTree
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 行为核心
|
||||
/// </summary>
|
||||
private Entry Entry;
|
||||
|
||||
/// <summary>
|
||||
/// 行为配置
|
||||
/// </summary>
|
||||
private string Config;
|
||||
|
||||
/// <summary>
|
||||
/// 是否初始化
|
||||
/// </summary>
|
||||
public bool IsInit { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 种子
|
||||
/// </summary>
|
||||
public int Seed { get; private set; }
|
||||
|
||||
//随机数
|
||||
private Func<LFloat,LFloat,LFloat> nRandomFloat;
|
||||
|
||||
public void OnInit(int seed,string config)
|
||||
{
|
||||
if (IsInit) return;
|
||||
Config = config;
|
||||
nRandomFloat = RandomUtil.SyncRandomFloat(seed);
|
||||
|
||||
if (Entry == null && Config != null)
|
||||
{
|
||||
Entry = XmlUtils.DeSerialize<Entry>(Config);
|
||||
IsInit = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsInit = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public LFloat RandomFloat(LFloat min,LFloat max)
|
||||
{
|
||||
return nRandomFloat(min,max);
|
||||
}
|
||||
|
||||
public LFloat RandomFloat()
|
||||
{
|
||||
return RandomFloat(LFloat.L0,LFloat.L1);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a6d4e191dd04e18be61de59dbc9a36c
|
||||
timeCreated: 1729923334
|
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "Slayer",
|
||||
"references":[ "GUID:a035c483e4ff50f4c92f84afd22778cf", "GUID:a6f7937b7f28906409a3ea3ceb2316c6" ]
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4709ba66dcc5cb24bbfb841ed1c50773
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a2a534273cfd1d498854af7ec7faacb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
|
||||
public class NoCreate : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class OutField : Attribute
|
||||
{
|
||||
public Type FieldType;
|
||||
|
||||
public OutField()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public OutField(Type fieldType)
|
||||
{
|
||||
FieldType = fieldType;
|
||||
}
|
||||
}
|
||||
public class ShowMe : Attribute
|
||||
{
|
||||
public string ShowMsg;
|
||||
|
||||
public ShowMe()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ShowMe(string showMsg)
|
||||
{
|
||||
ShowMsg = showMsg;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed213ded68349aa4bbc16893a3763ba3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class SlayerUtils
|
||||
{
|
||||
static Dictionary<Type, Func<string, object>> dic = new Dictionary<Type, Func<string, object>>();
|
||||
public static Dictionary<Type, Func<string, object>> Dic => dic;
|
||||
public static void RegistCustomParser<T>(Func<string, object> func)
|
||||
{
|
||||
Type key = typeof(T);
|
||||
if (dic.ContainsKey(key))
|
||||
{
|
||||
dic[key] = func;
|
||||
}
|
||||
else
|
||||
{
|
||||
dic.Add(key, func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74e1ebc0a31342545a0c4bdc5dc65344
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace BehaviorTreeSlayer
|
||||
{
|
||||
public class XmlUtils
|
||||
{
|
||||
public static T DeSerialize<T>(string path, string name)
|
||||
{
|
||||
FileStream fileStream = File.Open(path + "/" + name, FileMode.Open);
|
||||
XmlSerializer xml = new XmlSerializer(typeof(T));
|
||||
T list;
|
||||
try
|
||||
{
|
||||
list = (T)xml.Deserialize(fileStream);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fileStream.Close();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
public static T DeSerialize<T>(string text)
|
||||
{
|
||||
using (StringReader sr = new StringReader(text))
|
||||
{
|
||||
XmlSerializer xs = new XmlSerializer(typeof(T), Types);
|
||||
return (T)xs.Deserialize(sr);
|
||||
}
|
||||
}
|
||||
public static void XmlWriter<T>(T obj, string path)
|
||||
{
|
||||
using (FileStream fs = new FileStream(path, FileMode.Create))
|
||||
{
|
||||
XmlSerializer xml = new XmlSerializer(obj.GetType(), Types);
|
||||
xml.Serialize(fs, obj);
|
||||
}
|
||||
}
|
||||
static Type[] types;
|
||||
|
||||
public static Type[] Types
|
||||
{
|
||||
get
|
||||
{
|
||||
if (types == null)
|
||||
{
|
||||
types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(a => a.GetTypes().Where(t => t.IsSubclassOf(typeof(TreeNode))))
|
||||
.ToArray();
|
||||
}
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
public static string XmlSerialize<T>(T obj)
|
||||
{
|
||||
string s;
|
||||
|
||||
//派生类序列化
|
||||
XmlSerializer xml = new XmlSerializer(obj.GetType(), Types);
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
xml.Serialize(ms, obj);
|
||||
s = Encoding.UTF8.GetString(ms.ToArray());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93d2405f000836c41afde6b189b28771
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user