怎么把网站地图上传,wordpress 编辑菜单,微信公众平台注册不了,电子商务网站建设考题与答案【动作节点数据共享】
行为树中需要的参数可以来自游戏中的各个模块#xff0c;如果仅需从多个模块获取少量参数#xff0c;那么可以直接在代码中调用其他模块的单例继而层层调用获取数据。
如果获取的参数量很大#xff0c;从架构上看#xff0c;我们需要通过加一个中间…【动作节点数据共享】
行为树中需要的参数可以来自游戏中的各个模块如果仅需从多个模块获取少量参数那么可以直接在代码中调用其他模块的单例继而层层调用获取数据。
如果获取的参数量很大从架构上看我们需要通过加一个中间者去管理各个模块的参数获取调用行为树从中间者获取数据即可。
换一种说法就是要有共享数据的地方通常会采用黑板模式。
综合来说存在以下情况
多个不同的动作节点或条件节点需要获取或设置来自不同模块的属性多个不同的动作节点或条件节点会获取或设置相同模块的同一属性不同动作节点之间有通信A动作节点生成的临时数据是B动作节点所需的数据不同动作节点存在大量重复计算例如距离计算多个动作节点会共用临时存在的多个数据
针对这些情况我们可以通过键值对的形式实现黑板模式
需要注意的是这些黑板不属于节点考虑到不同行为树也会共享数据因此也不一定属于黑板。需要有一个黑板的管理者来做数据管理。
黑板模式的数据管理本质还是通过键值对的方式为处理不同的情况我们需要对每种情况提供不同的Key。这和MVC中的数据管理并无本质区别。
和节点参数配置不同的是这里是要程序做控制的而且不确定性更大无法做明确的规定。
在这种情况下我们需要对每个数据做单独得ID定义每个数据有各自的获取设置方法通过ID映射。
根据行为树ID节点ID数据ID方法ID可以实现不同的数据获取程序只需实现方法ID即可。
在黑板中我们需要根据这些参数生成唯一的Key这里自然而然的就会需要对参数做封装用泛型用对象池。
同样的我们需要有这些参数对应的结果考虑数据类型差异结果有效性等自然也需要做封装。
【动作节点的实现位置】
在整个游戏中与角色相关的模块如下
角色动画基于状态机提供动作切换提供最基础的接口角色运动包括基础移动走、跑等地形移动蹲下、跳跃、攀爬等寻路。会调用角色动画提供的接口角色交互 与物体的交互拾取、推开、握住、抓住、攀绕、踢开等等。会调用角色动画或角色运动提供的接口前者为主与角色的交互主要是打击、少量握手、拥抱等。会调用角色动画或角色运动提供的接口前者为主角色技能技能、Buff、伤害计算、效果表现。会调用角色动画或角色运动或角色交互提供的接口前者为主角色属性记录角色的各类状态角色行为这里就是角色AI会调用角色动画或角色运动或角色交互或角色技能或角色属性提供的接口
因此在实现动作节点时属于其他模块的直接调用其他模块的接口或在其他模块内实现属于角色行为的在动作节点内实现。
例如就技能而言对角色技能来说不同角色的技能各有差异要做不同的实现但对角色AI而言只有普攻、技能、技能、大招等
【代码实现】
数据配置 [Serializable]public class DataConfig{public int dataId;public int setMethodId;public int getMethodId;public DataLife dataLife;public bool multi;//同一类型参数参数值不同结果不同public bool praseType;//如果解析类型做自动化生成public bool cache;//是否做数据缓存}public enum DataLife{Persistent,//永久性数据Conditional,//条件性数据满足某条件出现不满足消失FixedTime,//固定时间内有效的数据FixedFrame,//固定帧数内有效的数据}[CreateAssetMenu(fileName BlackBoard_Data_Config, menuName BT/BlackBoardDataConfig)]public class BlackBoardDataConfig:ScriptableObject{public ListDataConfig dataConfigs new ListDataConfig();}
数据请求 public class BBDataRequest{public int btId;public int nodeId;public int dataId;public virtual void Release() { }}public class BBDataRequestParmas : BBDataRequest{private static ObjectPoolBBDataRequestParmas Pool new ObjectPoolBBDataRequestParmas(GenBBDataRequest);private static BBDataRequestParmas GenBBDataRequest(){return new BBDataRequestParmas();}public static BBDataRequestParmas GetBBDataRequest(){return Pool.Get();}public static void Release(BBDataRequestParmas data){data.Reset();Pool.Release(data);}public virtual int TryAddParams(Parmas data){return -1;}public virtual int TryAddObject(object data){return -1;}public virtual Parmas GetParmas(int index){return default(Parmas);}public virtual object GetObject(int index){return null;}public override void Release(){Release(this);}public virtual void Reset(){}}public class BBDataRequestSingleParmas : BBDataRequestParmas{public Parmas reqParamsNoBoxing;public object reqParams;public override int TryAddParams(Parmas data){reqParamsNoBoxing data;return -1;}public override int TryAddObject(object data){reqParams data;return -1;}public override Parmas GetParmas(int index){return reqParamsNoBoxing;}public override object GetObject(int index){return reqParams;}public override void Reset(){reqParamsNoBoxing default(Parmas);reqParams default(object);}}public class BBDataRequestMultiParmas:BBDataRequestParmas{public DictionaryParmas,int paramsNoBoxingIndex new DictionaryParmas,int();public Dictionaryobject,int paramsIndex new Dictionaryobject,int();private Dictionaryint, Parmas index2ParamsNoBoxing new Dictionaryint, Parmas();private Dictionaryint,object index2Params new Dictionaryint,object();public override int TryAddParams(Parmas data){if(!paramsNoBoxingIndex.TryGetValue(data,out int res)){res paramsNoBoxingIndex.Count;paramsNoBoxingIndex[data] res;}index2ParamsNoBoxing[res] data;return res;}public override int TryAddObject(object data){if(!paramsIndex.TryGetValue(data,out int res)){res paramsIndex.Count;paramsIndex[data] res;}index2Params[res] data;return res;}public override object GetObject(int index){return index2Params[index];}public override Parmas GetParmas(int index){return index2ParamsNoBoxing[index];}public override void Reset(){paramsIndex.Clear();index2Params.Clear();index2ParamsNoBoxing.Clear();paramsNoBoxingIndex.Clear();}}
数据结果 public class BBDataResultResult : IBBDataResult{public int dataId { get; set; }public DataConfig config { get; set; }public BBDataRequest request { get; set; } public float lifeTime;public float curTime;public int curFrame;public bool Valid(){switch(config.dataLife){case DataLife.FixedTime:case DataLife.FixedFrame:return curTime lifeTime;case DataLife.Conditional:case DataLife.Persistent: return true;}return true; }public virtual bool Getted(int frameCount, int index){return false;}public virtual Result GetCurResult(int index){return default(Result);}public virtual void SetGetResult(Result value, int index){}public virtual void SetCurResult(Result value,int index){}public virtual void Tick(float deltaTime){curFrame Time.frameCount;if (config.dataLife DataLife.FixedTime){curTime deltaTime;}if(config.dataLife DataLife.FixedFrame){curTime 1;}}public virtual void Reset(){curTime 0;curFrame 0;}private static ObjectPoolBBDataResultResult Pool new ObjectPoolBBDataResultResult(GenBBDataResult);private static BBDataResultResult GenBBDataResult(){return new BBDataResultResult();}public static BBDataResultResult GetBBDataResult(){return Pool.Get();}public static void Release(BBDataResultResult bbDataResult){bbDataResult.Reset();Pool.Release(bbDataResult);}public void Release(){Release(this);}}public class BBDataResultSingleResult: BBDataResultResult{public Result result;public bool getted;public override void SetGetResult(Result value, int index){result value;getted true;}public override void SetCurResult(Result value,int index){result value;getted false;}public override bool Getted(int frameCount, int index){return getted frameCount curFrame;}public override void Tick(float deltaTime){base.Tick(deltaTime);getted false;}public override void Reset(){getted false;result default(Result);}public override Result GetCurResult(int index){return result;}}public class BBDataResultMultiResult: BBDataResultResult{public Dictionaryint,Result resultIndex new Dictionaryint,Result();public Dictionaryint, bool getted new Dictionaryint, bool();public override void SetGetResult(Result value,int index){resultIndex[index] value;getted[index] true;}public override void SetCurResult(Result value, int index){resultIndex[index] value;getted[index] false;}public override bool Getted(int frameCount,int index){return getted[index] frameCount curFrame;}public override void Tick(float deltaTime){base.Tick(deltaTime);foreach (var item in getted.Keys){getted[item] false;}}public override void Reset(){getted.Clear();resultIndex.Clear();}public override Result GetCurResult(int index){return resultIndex[index];}}
黑板类及其管理者 public class BlackBoardManager{private static BlackBoardManager instance;private BlackBoardManager() { }public static BlackBoardManager Instance{get{if (instance null){instance new BlackBoardManager();}return instance;}}public Dictionaryint, BlackBoard id2BB new Dictionaryint, BlackBoard();private Dictionaryint,DataConfig dataConfig new Dictionaryint, DataConfig();public void Init(){BlackBoard bb new BlackBoard();bb.bbId 1;id2BB[1] bb;//load配置数据 }public void Tick(float deltaTime){foreach (var bb in id2BB.Values){bb.Tick(deltaTime);}}public BlackBoard CreateBlackBoard(bool common){if (common){return id2BB[1];}else{BlackBoard bb new BlackBoard();bb.bbId id2BB.Count 1;id2BB[bb.bbId] bb;return bb;}}public BlackBoard GetBlackBoard(int bbId){id2BB.TryGetValue(bbId, out var bb);return bb;}public DataConfig GetDataConfig(int id){return dataConfig[id];}public void RemoveBlackBoard(BlackBoard bb){id2BB.Remove(bb.bbId);}public void Clear(){foreach(var bb in id2BB.Values){bb.Clear();}id2BB.Clear();dataConfig.Clear();}}public class BlackBoard{public int bbId;public Dictionaryint, IBBDataResult id2Result new Dictionaryint, IBBDataResult();public Dictionaryint,BBDataRequest id2Request;//这里简单根据Id做划分,可以做更复杂的分类以便于收集数据做数据分析或Debugprivate Listint waitRemoveList new Listint();private ListBBDataRequest reqHistory new ListBBDataRequest();//可以收集数据做分析public void Tick(float deltaTime)//Tick检查去掉无效数据{waitRemoveList.Clear();foreach (var item in id2Result){item.Value.Tick(deltaTime);if(!item.Value.Valid()){waitRemoveList.Add(item.Key);}}foreach (var item in waitRemoveList){RemoveData(item);}}public Result GetDataParams,Result(int btId,int nodeId,int dataId, Params reqparams,out bool valid){var config BlackBoardManager.Instance.GetDataConfig(dataId);//根据数据Id获取数据配置var request GetBBDataRequestParams(btId,nodeId,dataId,reqparams,config.multi config.cache, out int index);//根据参数获取请求分为Single请求和Multi请求var result GetBBDataResultResult(dataId, config, request);//获取请求对应的结果//一个数据Id只有一个对应的请求和结果valid result.Valid();if(valid){if(config.praseType){BBDataMethod.DispatchMethoIdParams,Result(result.config.getMethodId, bbId, dataId, index, true);//自动解析传入的参数和结果的类型自动化生成代码适用于简单的值类型}else{BBDataMethod.DispatchMethoId(result.config.getMethodId, bbId, dataId, index);//自定义处理数据类型}return ((BBDataResultResult)result).GetCurResult(index);//同一个数据Id在获取时会传入不同的参数在请求中给参数生成Index根据Index获取其对应的结果} return default(Result);}public Result GetDataResult(int btId, int nodeId, int dataId, object reqparams, out bool valid){var config BlackBoardManager.Instance.GetDataConfig(dataId);var request GetBBDataRequest(btId, nodeId, dataId, reqparams, config.multi config.cache, out int index);var result GetBBDataResultResult(dataId, config, request);valid result.Valid();if (valid){if (config.praseType){BBDataMethod.DispatchMethoIdobject, Result(result.config.getMethodId, bbId, dataId, index, true);}else{BBDataMethod.DispatchMethoId(result.config.getMethodId, bbId, dataId, index);}return ((BBDataResultResult)result).GetCurResult(index);}return default(Result);}public void SetDataParams, Value(int btId, int nodeId, int dataId,Value value, Params reqparams default){var config BlackBoardManager.Instance.GetDataConfig(dataId);//根据数据Id获取数据配置var request GetBBDataRequestParams(btId, nodeId, dataId, reqparams, config.multi config.cache, out int index);//根据参数获取请求分为Single请求和Multi请求var result GetBBDataResultValue(dataId, config, request);//获取请求对应的结果if (!((BBDataResultValue)result).GetCurResult(index).Equals(value))//判断设置的值是否和当前的结果值相当如果相等就不用再设置了{if (config.praseType){BBDataMethod.DispatchMethoIdParams, Result(result.config.setMethodId, bbId, dataId, index, false);}else{BBDataMethod.DispatchMethoId(result.config.setMethodId, bbId, dataId, index);}} }public void SetDataValue(int btId, int nodeId, int dataId, Value value,object reqparams null){var config BlackBoardManager.Instance.GetDataConfig(dataId);var request GetBBDataRequest(btId, nodeId, dataId, reqparams, config.multi config.cache, out int index);var result GetBBDataResult(dataId, config, request);if (!((BBDataResultValue)result).GetCurResult(index).Equals(value)){if (config.praseType){BBDataMethod.DispatchMethoIdobject, Result(result.config.setMethodId, bbId, dataId, index, false);}else{BBDataMethod.DispatchMethoId(result.config.setMethodId, bbId, dataId, index);}}}public bool RemoveData(int dataId){int count 0;if(id2Result.TryGetValue(dataId,out var result)){result.Release();id2Result.Remove(dataId);count;}if(id2Request.TryGetValue(dataId,out var request)){request.Release();id2Request.Remove(dataId);count;}return count 2;}public BBDataRequest GetDataRequest(int dataId){id2Request.TryGetValue(dataId, out var result);return result;}public IBBDataResult GetDataResult(int dataId){id2Result.TryGetValue(dataId, out var result);return result;}public void Clear(){id2Request.Clear();id2Result.Clear();waitRemoveList.Clear();//SaveHistoryreqHistory.Clear();}private BBDataRequest GetBBDataRequestT(int btId, int nodeId, int dataId,T data,bool multi,out int index){if(!id2Request.TryGetValue(dataId,out var request)){request multi ? BBDataRequestMultiT.GetBBDataRequest() : BBDataRequestSingleT.GetBBDataRequest();request.btId btId;request.nodeId nodeId;request.dataId dataId;//reqHistory.Add(request);}var res request as BBDataRequestT;index res.TryAddParams(data);//将获取数据传入的参数封装在 BBDataRequest中return res;}private BBDataRequest GetBBDataRequest(int btId, int nodeId, int dataId, object data,bool multi,out int index){if (!id2Request.TryGetValue(dataId, out var request)){request multi ? BBDataRequestMultiobject.GetBBDataRequest() : BBDataRequestSingleobject.GetBBDataRequest();request.btId btId;request.nodeId nodeId;request.dataId dataId;//reqHistory.Add(request);}var res request as BBDataRequestobject;index res.TryAddObject(data);return res;}private IBBDataResult GetBBDataResultT(int dataId,DataConfig config,BBDataRequest request){if (!id2Result.TryGetValue(dataId, out var result)){BBDataResultT res (config.multi config.cache) ? BBDataResultMultiT.GetBBDataResult() : BBDataResultSingleT.GetBBDataResult();if (!config.cache) res.SetCurResult(default(T), 0);result res;result.dataId dataId;result.config config;}result.request request;return result;}private IBBDataResult GetBBDataResult(int dataId, DataConfig config, BBDataRequest request){if (!id2Result.TryGetValue(dataId, out var result)){BBDataResultobject res (config.multi config.cache) ? BBDataResultMultiobject.GetBBDataResult() : BBDataResultSingleobject.GetBBDataResult();if (!config.cache) res.SetCurResult(null, 0);result res;result.dataId dataId;result.config config;}result.request request;return result;}}
数据的GetSet方法实 public static class BBDataDefinition{//这里通过配置自动生成public const int Def_获取血量 11223344;public const int Def_设置血量 11223345;public const int Def_获取资源数量 121212123;public const int Def_设置资源数量 121212124;}public partial class BBDataMethod{//这里通过配置自动生成private static Dictionary(Type, Type), ActionBBDataRequest,IBBDataResult,int,int,bool TypeToPraseAction new Dictionary(Type, Type), ActionBBDataRequest, IBBDataResult, int, int,bool(){[(typeof(void),typeof(int))] PraseVoidAndInt,[(typeof(int), typeof(int))] PraseIntAndInt,[(typeof(int), typeof(void))] PraseIntAndVoid,};private static Dictionaryint, Funcint GetIntValue new Dictionaryint, Funcint(){[BBDataDefinition.Def_获取资源数量] GetResCount,};private static Dictionaryint, Actionint SetIntValue new Dictionaryint, Actionint(){[BBDataDefinition.Def_设置资源数量] SetResCount,};private static Dictionaryint, Funcint,int GetIntValueByInt new Dictionaryint, Funcint,int(){};private static Dictionaryint, Actionint, int SetIntValueByInt new Dictionaryint, Actionint, int(){};public static void DispatchMethoIdParams,Result(int methodId,int bbId,int dataId,int index,bool get){var bb BlackBoardManager.Instance.GetBlackBoard(bbId);var res bb.GetDataResult(dataId);if (get res ! null res.Getted(Time.frameCount, index)){return;}var req bb.GetDataRequest(dataId);if (req ! null res ! null){var typeReq typeof(Params);var typeRes typeof(Result);TypeToPraseAction.TryGetValue((typeReq, typeRes), out var action);if (action ! null){action(req, res, methodId, index, get);}}}public static void DispatchMethoId(int methodId, int bbId, int dataId, int index){switch (methodId){case BBDataDefinition.Def_获取血量: GetRoleHp(bbId, dataId, index); break;case BBDataDefinition.Def_设置血量: SetRoleHp(bbId, dataId, index); break;}}private static void PraseVoidAndInt(BBDataRequest req, IBBDataResult res, int methodId, int index,bool get){if(get){int intValue GetIntValue[methodId].Invoke();var intResult res as BBDataResultint;intResult.SetGetResult(intValue, index);}}private static void PraseIntAndVoid(BBDataRequest req, IBBDataResult res, int methodId, int index, bool get){if (!get){var intResult res as BBDataResultint;int intValue intResult.GetCurResult(index);SetIntValue[methodId].Invoke(intValue);}}private static void PraseIntAndInt(BBDataRequest req, IBBDataResult res, int methodId, int index, bool get){if(get){var intReq req as BBDataRequestint;int intParams intReq.GetParmas(index);int intValue GetIntValueByInt[methodId].Invoke(intParams);var intResult res as BBDataResultint;intResult.SetGetResult(intValue, index);}else{var intReq req as BBDataRequestint;int intParams intReq.GetParmas(index);var intResult res as BBDataResultint;int intValue intResult.GetCurResult(index);SetIntValueByInt[methodId].Invoke(intParams, intValue);}}}public partial class BBDataMethod{public static void GetRoleHp(int bbId, int dataId,int index){var bb BlackBoardManager.Instance.GetBlackBoard(bbId);//获取数据所在的BBvar res bb.GetDataResult(dataId);//获取数据对应的结果if(res ! null res.Getted(Time.frameCount,index))//判断当前帧该数据是否已经获取过{return;}var req bb.GetDataRequest(dataId);//获取数据对应的请求 if(req ! null ){ var intReq req as BBDataRequestint;int roleId intReq.GetParmas(index);//获取请求的参数int hp 100;//通过角色Id获取角色属性,属性系统固定时这些类似的获取值的代码都可以通过自动化配置生成 var intResult res as BBDataResultint;intResult.SetGetResult(hp,index);//设置获取的结果}}public static void SetRoleHp(int bbId, int dataId,int index){var bb BlackBoardManager.Instance.GetBlackBoard(bbId);var res bb.GetDataResult(dataId);var req bb.GetDataRequest(dataId);if (req ! null res ! null){var intReq req as BBDataRequestint;int roleId intReq.GetParmas(index);var intResult res as BBDataResultint;int hp intResult.GetCurResult(index); //调用接口设置角色血量}}public static int GetResCount() { return 100; }public static void SetResCount(int value) { }}