网站推广方案模板建设通网站是免费的吗
web/
2025/10/9 13:25:09/
文章来源:
网站推广方案模板,建设通网站是免费的吗,seo是干什么的,网站怎么做充值系统下载【分析】
如果行为树的节点很多#xff0c;那么会存在要经过很多节点才会走到动作节点的情况。显然#xff0c;性能上不如状态机。
每帧都需要重新遍历一系列节点才会走到动作节点#xff0c;而实际上很多条件节点在数帧内不会有变化#xff0c;这是造成性能问题的重要原…【分析】
如果行为树的节点很多那么会存在要经过很多节点才会走到动作节点的情况。显然性能上不如状态机。
每帧都需要重新遍历一系列节点才会走到动作节点而实际上很多条件节点在数帧内不会有变化这是造成性能问题的重要原因。
行为树每帧的Update其实就是在轮询这些条件为避免轮询我们自然而然的希望在一帧直接执行动作节点。
为此需要将在Running状态的动作节点缓存直接执行直到成功。
这种方式引起的问题是动作节点不一定总是会执行成功可能在某一帧某些条件改变了动作需要被打断。
为了解决该问题就需要给动作节点引入一些事件当特定事件发生时在动作节点内接收该事件直接结束动作节点的运行返回失败。
随后重新开始整个行为树的轮询找到下一个动作节点。
这就是事件和轮询混合驱动的行为树。
事件本质上就是直接调用当经过动作节点的路径较长也即影响该动作节点的条件过多时不可避免要通过代码调用发多种消息,这就失去了配置的意义。
需要将打断动作节点及节点的逻辑做成单独的Conditional节点这些节点接收消息或监听变化以决定是否打断其子节点。
通过轮询这些Conditional节点以简化发多种消息的调用。
当打断发生时需要重新运行被打断节点的父节点确定新的分支走向。为此需要将路径上所有节点做缓存。
这里要对控制节点做特殊处理控制节点会控制自身的子节点运行其状态受子节点影响当打断存在时子节点可能不需要再次运行因此控制节点在控制子节点运行前需要知道当前是否被打断。
【代码实现】 public class BehaviorTree{public string btName;public int btId;public UpdateType updateType;public DrivenType drivenType;public float updateTime;private float curTime;public GameObject owner;private Node rootNode;private ListNode allNodes new ListNode();private Dictionaryint,Node id2Node new Dictionaryint,Node();private Dictionaryint,NodeInfo id2NodeInfo new Dictionaryint,NodeInfo();private DictionaryType, Dictionarystring, Delegate eventDic new DictionaryType, Dictionarystring, Delegate();private Node curActionNode;private StackNode activeNodes new StackNode();private ListConditionalNode conditionalNodes new ListConditionalNode(); public static Funcstring, BehaviourTreeData loadFunc null;public void Init(GameObject owner, string path, Funcstring, BehaviourTreeData loadFunc){this.owner owner;//这里省略部分边界情况检查的逻辑if (!string.IsNullOrEmpty(path)){var data loadFunc?.Invoke(path);btId owner.GetInstanceID();updateType data.updateType; updateTime data.updateTime;drivenType data.drivenType;//通常初始化有两种写法一种是在管理者中完成管理者自身以及被管理者的数据初始化另一种是管理者完成自身的初始化后将被数据传递给被管理者被管理者自身完成初始化//第二种方式更加灵活可变且不需要关注行为树结构是怎么样的只需每个节点做好自身的初始化//在第二种方式下涉及如何将数据递归传递的问题为统一获取将数据记录在管理者上被管理者根据Id从管理者中获取初始化后可选择将数据释放foreach (var item in data.nodes){id2NodeInfo[item.nodeId] item;}var rootData data.nodes[0];//默认第一个是rootNode数据rootNode new RootNode();rootNode.Init(rootData, this);id2NodeInfo.Clear();//也可以保留}}public void Update(float time){if(drivenType DrivenType.Polling){PollingUpdate(time);}else if(drivenType DrivenType.PollingAndEvent){if (curActionNode ! null){var actionStatus curActionNode.Update();if(actionStatus ! NodeStatus.Running){curActionNode null; PollingUpdate(time);}else{if (updateType UpdateType.FixedTime){curTime time;}}}else{PollingUpdate(time);}}else if(drivenType DrivenType.EventDriven){EventUpdate(time);}}private void PollingUpdate(float time){if (updateType UpdateType.EveryFrame){Update();}else if (updateType UpdateType.FixedTime){curTime time;if (curTime updateTime){curTime 0;Update();}}}private void EventUpdate(float time){int index -1;for (int i 0; i conditionalNodes.Count; i){if (conditionalNodes[i].ConditionChanged()) //当条件节点条件改变其后所有节点都需要重新计算,动作节点需要被打断{index i;break;}}if (index ! -1){ while(activeNodes.Count 0 activeNodes.Peek().nodeId ! conditionalNodes[index].nodeId)//移除其后所有Active节点{PopNode(activeNodes.Peek());}conditionalNodes[index].Update();//重新运行该节点if (conditionalNodes[index].StatusChanged(out var curStatus)){ var curNode (Node)conditionalNodes[index];var parent conditionalNodes[index].parent;while (parent is ControlNode)//如果父节点是控制节点其状态会与子节点相关,这里简化处理直接重新运行{curNode parent;parent parent.parent;}if(curNode ! conditionalNodes[index]){while (activeNodes.Count 0 activeNodes.Peek().nodeId ! curNode.nodeId){PopNode(activeNodes.Peek());}curNode.Update();}}}else{var state activeNodes.Peek().Update();//没有打断再次运行末尾的动作节点if(state ! NodeStatus.Running)//运行结束重新从根节点开始运行也可以选择回退到上一个节点开始运行{activeNodes.Clear();conditionalNodes.Clear();rootNode.Update();}}}public void PushNode(Node node){if (drivenType ! DrivenType.EventDriven)return;activeNodes.Push(node);if(node is ConditionalNode conditionalNode){conditionalNodes.Add(conditionalNode);}}private void PopNode(Node node){if (drivenType ! DrivenType.EventDriven)return;node.End();activeNodes.Pop();if(node is ConditionalNode conditionalNode){conditionalNodes.Remove(conditionalNode);}}public NodeStatus Update(){var status rootNode.Update();if(status ! NodeStatus.Running){rootNode.End();}return status;}public void Destroy(){foreach (var item in allNodes){item.Destroy();}allNodes.Clear();id2Node.Clear();id2NodeInfo.Clear();}public NodeInfo GetNodeInfo(int nodeId){return id2NodeInfo[nodeId];}public void AddNode(Node node){allNodes.Add(node);id2Node[node.nodeId] node;}public void SetActionNode(Node node){curActionNode node;}private void RegisterEvent(string eventName, Delegate handler){if (drivenType DrivenType.Polling)return;if (!eventDic.TryGetValue(handler.GetType(), out var dic)){dic new Dictionarystring, Delegate();eventDic[handler.GetType()] dic;}if (!dic.TryGetValue(eventName, out var value)){dic[eventName] handler;}else{dic[eventName] Delegate.Combine(value, handler);}}public void RegisterEvent(string eventNmae,Action action){RegisterEvent(eventNmae, (Delegate)action);}public void RegisterEventT(string eventNmae, ActionT action){RegisterEvent(eventNmae, (Delegate)action);}public void RegisterEventT1,T2(string eventNmae, ActionT1,T2 action){RegisterEvent(eventNmae, (Delegate)action);}public void RegisterEventT1, T2,T3(string eventNmae, ActionT1, T2,T3 action){RegisterEvent(eventNmae, (Delegate)action);}private Delegate GetDelegate(string eventName,Type type){if (drivenType DrivenType.Polling)return null;if (eventDic.TryGetValue(type, out var dic)){if (dic.TryGetValue(eventName, out var handler)){return handler;}}return null;}public void SendEvent(string eventName){ if(GetDelegate(eventName, typeof(Action)) is Action action){action();}}public void SendEventT(string eventName, T t){if (GetDelegate(eventName, typeof(ActionT)) is ActionT action){action(t);}}public void SendEventT1,T2(string eventName, T1 t1,T2 t2){if (GetDelegate(eventName, typeof(ActionT1,T2)) is ActionT1,T2 action){action(t1,t2);}}public void SendEventT1, T2,T3(string eventName, T1 t1, T2 t2,T3 t3){if (GetDelegate(eventName, typeof(ActionT1, T2,T3)) is ActionT1, T2,T3 action){action(t1, t2,t3);}}}public enum DrivenType{Polling,PollingAndEvent,EventDriven} public class Node{public string nodeName;public int nodeId;public NodeStatus status;public BehaviorTree owner;public Node parent;public void Init(NodeInfo nodeInfo, BehaviorTree owner){this.owner owner;this.nodeName nodeInfo.nodeName;this.nodeId nodeInfo.nodeId;OnInit(nodeInfo);owner.AddNode(this);//对于字段的配置可以通过字段名反射获取字段然后设置值但这里允许的值是有限的我们直接在每个节点写对应的处理}public NodeStatus Update(){owner.PushNode(this);return OnUpdate();}public void End()//方法名字叫Exit也是一样的{OnEnd();}protected virtual void OnInit(NodeInfo nodeInfo){}protected virtual NodeStatus OnUpdate(){return NodeStatus.Success;}protected virtual void OnEnd(){}public virtual void Destroy(){}}public class ConditionalNode:Node{public Node subNode;protected override void OnInit(NodeInfo nodeInfo){if (nodeInfo.subNodes.Count 0){var subNodeInfo owner.GetNodeInfo(nodeInfo.subNodes[0]);Type type Type.GetType(subNodeInfo.nodeType);subNode (Node)Activator.CreateInstance(type);subNode.Init(subNodeInfo, owner);subNode.parent this;}}protected override NodeStatus OnUpdate(){return subNode.Update();}public virtual bool ConditionChanged(){return false;}public virtual bool StatusChanged(out NodeStatus status){status NodeStatus.Success;return false;}public class ActionNode:Node{private bool start;private bool stop;protected override NodeStatus OnUpdate(){if (!start){Start();start true;}var res base.OnUpdate();if(stop){res NodeStatus.Failure;}if (res NodeStatus.Running){owner.SetActionNode(this);}return res;}private void Start(){OnStart();}protected virtual void OnStart(){//各动作节点自定义注册事件}protected override void OnEnd(){start false;stop false;}}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/89653.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!