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 context = new Dictionary(); public Dictionary All { get { return context; } } public bool ContainsKey(string key) { return context.ContainsKey(key); } public T Get(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(string key, T defaultValue) { if (!context.ContainsKey(key)) { Set(key, defaultValue); return defaultValue; } T value = (T)context [key]; return value; } public void Set(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 nodes = new List(); 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() where T : Node { T node = (T)ScriptableObject.CreateInstance(); 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(); 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; } } }