提交行为树

This commit is contained in:
PC-20230316NUNE\Administrator
2024-10-26 19:59:47 +08:00
parent 1ad20b67da
commit 82513fea04
320 changed files with 51310 additions and 30015 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3be96e8bdaa9f2d4cbee49a5a50f1c46
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -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:

View File

@@ -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;
}
}
}

View File

@@ -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:

View File

@@ -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);
}
}
}

View File

@@ -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:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d8184935def5f8a4ba937d1c55959207
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -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:

View File

@@ -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;
}
}
}

View File

@@ -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:

View File

@@ -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;
}
}
}

View File

@@ -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:

View File

@@ -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;
}
}
}

View File

@@ -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:

View File

@@ -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;
}
}
}

View File

@@ -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:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 080fa34971cf43941832712f1ac3987f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 034fc570e45c74342bba94a7887014bf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 98c39464e2b77524492cfbcf228305fa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 686c0676a99f6314b93014517e377f30
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using BehaviorTreeSlayer;
using System;
public class ActionNode : TreeNode
{
public override void VisitTree(TreeNode node, Action<TreeNode> action)
{
action?.Invoke(node);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 33894d1d8b8c6e74db14a36ec2d18f04
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 878b80932be62944aa8f0c1c4b12fd3d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
namespace BehaviorTreeSlayer
{
public class CompositeNode : ComponentNode
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 737c340275e26864db0128f2adf450d9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cb07e1739da08984db81a1af73f128e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
namespace BehaviorTreeSlayer
{
public class DecoratorNode : ComponentNode
{
public override void Add(TreeNode component)
{
childs.Clear();
base.Add(component);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8464b683c4af17d47b42d115f6947316
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9766e0ff89cd9fa4bb9ec0d937e7bf63
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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)
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bd323d3daa2a13a41a4a45ba71eeefb4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 14276fe27b4d09d409cb47f3a70198eb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d52021fdec8f6d84297f35e294a28417
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1f359536e5bdfae439e7ceb5a315ee38
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f6017b9db8461cf43b2e2c2650cff46e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e85da6e1c87d07e478692a67c67d2e87
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 99f0f308232b4e5ba3f7b497af3098c1
timeCreated: 1729925751

View File

@@ -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()
{
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2a6d4e191dd04e18be61de59dbc9a36c
timeCreated: 1729923334

View File

@@ -0,0 +1,4 @@
{
"name": "Slayer",
"references":[ "GUID:a035c483e4ff50f4c92f84afd22778cf", "GUID:a6f7937b7f28906409a3ea3ceb2316c6" ]
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4709ba66dcc5cb24bbfb841ed1c50773
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3a2a534273cfd1d498854af7ec7faacb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ed213ded68349aa4bbc16893a3763ba3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 74e1ebc0a31342545a0c4bdc5dc65344
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 93d2405f000836c41afde6b189b28771
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: