Files
tianrunCRM/Assets/CoolapeFrame/3rd/Hivemind/Scripts/BehaviorTree.cs
2020-07-04 14:41:25 +08:00

178 lines
3.5 KiB
C#

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/*
* Best practices for serialization:
* - Don't use the `new` constructor
* - Instead use ScriptableObject.CreateInstance()
* - For initialization, use OnEnable() instead of the constructor
*
* Unity calls the constructor, deserializes the data (populating the object) and THEN calls OnEnable(),
* so the data is guaranteed to be there in this method.
*
*/
namespace Hivemind
{
public enum Status
{
Success,
Failure,
Running,
Error
}
public class Context
{
private Dictionary<string, object> context = new Dictionary<string, object>();
public Dictionary<string, object> All {
get { return context; }
}
public bool ContainsKey(string key)
{
return context.ContainsKey(key);
}
public T Get<T>(string key)
{
if (!context.ContainsKey(key)) {
throw new System.MissingMemberException(string.Format("Key {0} not found in the current context", key));
}
T value = (T)context [key];
return value;
}
public T Get<T>(string key, T defaultValue)
{
if (!context.ContainsKey(key)) {
Set<T>(key, defaultValue);
return defaultValue;
}
T value = (T)context [key];
return value;
}
public void Set<T>(string key, T value)
{
context [key] = value;
}
public void Unset(string key)
{
context.Remove(key);
}
}
[System.Serializable]
public class BehaviorTree : ScriptableObject
{
public static string[] NodeTypes = {
"Action", //动作
"Branch", //两分支
"Together", // 汇集
// "Inverter",
// "Parallel",
// "RandomSelector",
// "Repeater",
// "Selector",
// "Sequence",
// "Succeeder",
// "UntilSucceed"
};
public int nodeIndex = 0;
public Root rootNode;
public List<Node> nodes = new List<Node>();
public bool debugMode = false;
public Node currentNode = null;
public int TotalTicks { get; private set; }
public delegate void NodeWillTick(Node node);
public delegate void NodeDidTick(Node node,Status result);
public NodeWillTick nodeWillTick;
public NodeDidTick nodeDidTick;
public Node getNodeByID(int id)
{
for (int i = 0; i < nodes.Count; i++) {
if (nodes [i].id == id) {
return nodes [i];
}
}
return null;
}
public void SetRoot(Root root)
{
rootNode = root;
nodes.Add(root);
root.behaviorTree = this;
}
public T CreateNode<T>() where T : Node
{
T node = (T)ScriptableObject.CreateInstance<T>();
if (rootNode != null) {
rootNode.maxIndex++;
node.index = rootNode.begainIndex + rootNode.maxIndex;
}
node.behaviorTree = this;
return node;
}
// Lifecycle
public void OnEnable()
{
hideFlags = HideFlags.HideAndDontSave;
}
public void OnDestroy()
{
foreach (Node node in nodes) {
DestroyImmediate(node);
}
nodeIndex = 0;
}
public Status Tick(GameObject agent, Context context)
{
BehaviorTreeAgent btAgent = agent.GetComponent<BehaviorTreeAgent>();
if (btAgent) {
debugMode = btAgent.debugMode;
}
TotalTicks++;
Status result = rootNode.Tick(agent, context);
rootNode.lastStatus = result;
rootNode.lastTick = TotalTicks;
return result;
}
public Status Tick(Node node, GameObject agent, Context context)
{
if (nodeWillTick != null && node != currentNode)
nodeWillTick(node);
Status result = node.Tick(agent, context);
if (nodeDidTick != null)
nodeDidTick(node, result);
currentNode = node;
node.lastStatus = result;
node.lastTick = TotalTicks;
return result;
}
}
}