为了制作具有群体性行为的AI,又一次踏上了征途。群体性行为和策略,同个体行为的结构是很像的,但更复杂的是,我们的底层必要有一个机制自动的辅助系统能获得哪些AI应该被形成一个组,为了解决这个问题,我们确立了发起者和响应者。
发起者会检测四周范围响应者,并加入到响应者队列里,最后在这个队列中检测出相应的组,并为这个组的成员分配编号,然后激活这个组所有实体的组行为。
另外,行为节点,行为转化节点的形式也大有不同,定义如下:
public delegate void GroupStateRT(AIEntity pSponsor,AIEntity[] pResponses,int pid); public delegate void GroupStateEnter(AIEntity pSponsor,AIEntity[] pResponses,int pid); public delegate void GroupStateExit(AIEntity pSponsor,AIEntity[] pResponses,int pid); public delegate float GroupStateTransfer(AIEntity pSponsor,AIEntity[] pResponses,int pid);
在一个组行为中,你必须知道,发起者是谁,同组的有谁,以及在这个组中,你扮演的角色编号,你才能完全清楚这个组行为的全部信息,所以本来想要集成在FSM里计划完全泡汤,只能再独立出一个系统,现给出这个系统的一些代码:
public class GroupManager:UComponent { public List<List<GroupBehaviourNode>> mGroupLists; public SponsorNode[] mSponsors; public ResponseNode[] mResponses; public int mSponsorCount = 0; public int mResponseCount = 0; public Dictionary<string,List<int>> Dictionaryfortag2groupid; public Dictionary<int,GroupAllocation> Dictionaryforid2Allocation; public Dictionary<int,GroupStrategyRT> Dictionaryforid2Strategy; public Dictionary<int,GroupDissolve> Dictionaryforid2Dissolve; public Dictionary<EntityStrategyNode,GroupStrategyRT> DictionaryforStrategy; public Dictionary<EntityStrategyNode,AIGroupState> DictionaryforGroupState; //List<AIEntity> private static GroupManager mGroupManagerSington; public static GroupManager getInstance() { if (mGroupManagerSington == null) { mGroupManagerSington = new GroupManager (); } return mGroupManagerSington; } public GroupManager() { mGroupLists = new List<List<GroupBehaviourNode>> (); mSponsors = new SponsorNode[50]; mResponses = new ResponseNode[500]; Dictionaryfortag2groupid = new Dictionary<string, List<int>> (); Dictionaryforid2Allocation = new Dictionary<int, GroupAllocation> (); Dictionaryforid2Dissolve = new Dictionary<int, GroupDissolve> (); Dictionaryforid2Strategy = new Dictionary<int, GroupStrategyRT> (); DictionaryforStrategy = new Dictionary<EntityStrategyNode, GroupStrategyRT> (); DictionaryforGroupState = new Dictionary<EntityStrategyNode, AIGroupState> (); } public void AddGroupList(List<GroupBehaviourNode> pList,GroupDissolve pDissolve,GroupStrategyRT pStrategy,GroupAllocation pAllocation) { mGroupLists.Add (pList); int index = mGroupLists.IndexOf (pList); Dictionaryforid2Allocation.Add (index,pAllocation); Dictionaryforid2Dissolve.Add (index,pDissolve); Dictionaryforid2Strategy.Add (index,pStrategy); } public void AddSponsor(AIEntity pEntity) { SponsorNode tSponsor = new SponsorNode (); tSponsor.mSponsor = pEntity; tSponsor.mGroupListID = Dictionaryfortag2groupid [pEntity.tag]; mSponsors [mSponsorCount] = tSponsor; mSponsorCount++; } public void AddResponse(AIEntity pEntity) { ResponseNode tResponseNode = new ResponseNode (); tResponseNode.mResponse = pEntity; mResponses [mResponseCount] = tResponseNode; mResponseCount++; } public void AddKey(string tag,List<int> pids) { Dictionaryfortag2groupid.Add (tag,pids); } public void AddStrategy(string tag,int id,GroupStrategyRT pStrategyRT,AIGroupState pStateRT) { EntityStrategyNode esn = new EntityStrategyNode (); esn.tagName = tag; esn.id = id; DictionaryforStrategy.Add (esn,pStrategyRT); DictionaryforGroupState.Add (esn,pStateRT); } } public class GroupBehaviourSystem:USystem { public override void Init () { base.Init (); this.AddRequestComponent (typeof(GroupManager)); } public override void Update (UEntity uEntity) { base.Update (uEntity); for (int i = 0; i < uEntity.GetComponent<GroupManager> ().mResponseCount; i++) { if (!uEntity.GetComponent<GroupManager> ().mResponses [i].mSucceedTeam) uEntity.GetComponent<GroupManager> ().mResponses [i].mLeader = null; } for (int i = 0; i < uEntity.GetComponent<GroupManager> ().mSponsorCount; i++) { if (uEntity.GetComponent<GroupManager> ().mSponsors [i].members [0].mSucceedTeam) { if (uEntity.GetComponent<GroupManager> ().mSponsors [i].mDissloveTimer < 1.0f) uEntity.GetComponent<GroupManager> ().mSponsors [i].mDissloveTimer += Time.deltaTime; else { GroupDissolve tDissolve= uEntity.GetComponent<GroupManager> ().Dictionaryforid2Dissolve [uEntity.GetComponent<GroupManager> ().mSponsors [i].tempGroupID]; AIEntity[] pEntitys = new AIEntity[uEntity.GetComponent<GroupManager> ().mSponsors[i].memebercount]; for (int j = 0; j < uEntity.GetComponent<GroupManager> ().mSponsors [i].memebercount; j++) pEntitys [j] = uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mResponse; float rate = tDissolve (uEntity.GetComponent<GroupManager>().mSponsors[i].mSponsor,pEntitys); if (Random.Range (0.0f, 1.0f) < rate) { for (int j = 0; j < uEntity.GetComponent<GroupManager> ().mSponsors [i].memebercount; j++) { uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mResponse.isGrouping = false; uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mSucceedTeam = false; uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mLeader = null; uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mGroupID = -1; } uEntity.GetComponent<GroupManager> ().mSponsors [i].memebercount = 0; uEntity.GetComponent<GroupManager> ().mSponsors [i].mDissloveTimer = 0.0f; uEntity.GetComponent<GroupManager> ().mSponsors [i].mSponsor.isGrouping= false; uEntity.GetComponent<GroupManager> ().mSponsors [i].tempGroupID = -1; } } } else { uEntity.GetComponent<GroupManager> ().mSponsors [i].memebercount = 0; AIEntity[] mEntity = AIEntity.getAllEntityWithSphere (uEntity.GetComponent<GroupManager> ().mSponsors [i].mSponsor,10.0f); List<ResponseNode> mResponseList = new List<ResponseNode> (); for (int j = 0; j < mEntity.Length; j++) { for(int k=0;k<uEntity.GetComponent<GroupManager>().mResponseCount;k++) { ResponseNode rn = uEntity.GetComponent<GroupManager> ().mResponses [k]; if (rn.mResponse == mEntity [j] && rn.mLeader == null) { mResponseList.Add (rn); break; } } } int count = Mathf.Min (mResponseList.Count,uEntity.GetComponent<GroupManager>().mSponsors[i].members.Length); for(int j=0;j<count;j++) { uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j] = mResponseList [j]; uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mLeader = uEntity.GetComponent<GroupManager> ().mSponsors [i].mSponsor; } GroupAllocation tAlloc = uEntity.GetComponent<GroupManager>().Dictionaryforid2Allocation[uEntity.GetComponent<GroupManager> ().mSponsors [i].tempGroupID]; AIEntity[] pEntitys = new AIEntity[uEntity.GetComponent<GroupManager> ().mSponsors[i].memebercount]; for (int j = 0; j < uEntity.GetComponent<GroupManager> ().mSponsors [i].memebercount; j++) pEntitys [j] = uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mResponse; int[] ids = tAlloc (uEntity.GetComponent<GroupManager> ().mSponsors [i].mSponsor,pEntitys); uEntity.GetComponent<GroupManager> ().mSponsors [i].mSponsor.isGrouping = true; uEntity.GetComponent<GroupManager> ().mSponsors [i].mSponsor.GetComponent<AIGroupState> ().tempGroupID = 0; EntityStrategyNode esn = new EntityStrategyNode ();esn.id = uEntity.GetComponent<GroupManager> ().mSponsors [i].tempGroupID; esn.tagName = uEntity.GetComponent<GroupManager> ().mSponsors [i].mSponsor.tag; AIGroupState mStateRT = uEntity.GetComponent<GroupManager> ().DictionaryforGroupState[esn]; uEntity.GetComponent<GroupManager> ().mSponsors [i].mSponsor.GetComponent<AIGroupState> ().SimpleClone (mStateRT); uEntity.GetComponent<GroupManager> ().mSponsors [i].mSponsor.GetComponent<AIGroupState> ().pLeader = uEntity.GetComponent<GroupManager> ().mSponsors [i].mSponsor; uEntity.GetComponent<GroupManager> ().mSponsors [i].mSponsor.GetComponent<AIGroupState> ().pMembers = pEntitys; for(int j=0;j<uEntity.GetComponent<GroupManager>().mSponsors[i].memebercount;j++) { uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mGroupID = ids [j]; uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mResponse.isGrouping = true; uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mResponse.GetComponent<AIGroupState> ().tempGroupID = ids [j]; EntityStrategyNode esn1 = new EntityStrategyNode ();esn1.id = uEntity.GetComponent<GroupManager> ().mSponsors [i].tempGroupID; esn1.tagName = uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mResponse.tag; AIGroupState mStateRT1 = uEntity.GetComponent<GroupManager> ().DictionaryforGroupState[esn1]; uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mResponse.GetComponent<AIGroupState> ().SimpleClone (mStateRT1); uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mResponse.GetComponent<AIGroupState> ().pLeader = uEntity.GetComponent<GroupManager> ().mSponsors [i].mSponsor; uEntity.GetComponent<GroupManager> ().mSponsors [i].members [j].mResponse.GetComponent<AIGroupState> ().pMembers = pEntitys; } } } } } public struct GroupStateTransferNode { public int id; public GroupStateTransfer mTransfer; } public class AIGroupState:UComponent { public int tempGroupID; public AIEntity pLeader; public AIEntity[] pMembers; public GroupStateRT[] mGroupStateRTs; public GroupStateEnter[] mGroupStateEnters; public GroupStateExit[] mGroupStateExits; public List<GroupStateTransferNode>[] mGroupStateTransfers; public List<GroupStateTransferNode> mGroupStateAnyTransfers; public Dictionary<int,string> mAnimationDic; public int tempID; public int GroupStateCount = 0; public int TransferCount = 0; public AIGroupState() { mGroupStateEnters = new GroupStateEnter[15]; mGroupStateEnters = new GroupStateEnter[15]; mGroupStateRTs = new GroupStateRT[15]; mGroupStateTransfers = new List<GroupStateTransferNode>[30]; for (int i = 0; i < 30; i++) { mGroupStateTransfers [i] = new List<GroupStateTransferNode> (); } mAnimationDic = new Dictionary<int, string> (); mGroupStateAnyTransfers = new List<GroupStateTransferNode> (); isEnable = false; } public int AddGroupState(GroupStateRT prt,GroupStateEnter penter,GroupStateExit pexit) { mGroupStateRTs [GroupStateCount] = prt; mGroupStateEnters [GroupStateCount] = penter; mGroupStateExits [GroupStateCount] = pexit; GroupStateCount++; return GroupStateCount - 1; } public void AddTransfer (int id1,int id2,GroupStateTransfer pTransfer) { GroupStateTransferNode gstn = new GroupStateTransferNode (); gstn.id = id2; gstn.mTransfer = pTransfer; mGroupStateTransfers [id1].Add (gstn); } public void AddAnyTransfer(int id1,GroupStateTransfer pTransfer) { GroupStateTransferNode gstn = new GroupStateTransferNode (); gstn.id = id1; gstn.mTransfer = pTransfer; mGroupStateAnyTransfers.Add (gstn); } public void AddAnim(int id,string name) { mAnimationDic.Add (id,name); } public void SimpleClone(AIGroupState pGroupState) { Dictionary<int,string> mdic = new Dictionary<int, string> (); foreach(var item in pGroupState.mAnimationDic) { int ti = item.Key; string ts = item.Value; mdic.Add (ti,ts); } mAnimationDic = mdic; GroupStateCount = pGroupState.GroupStateCount; for (int i = 0; i < GroupStateCount; i++) { mGroupStateEnters [i] = pGroupState.mGroupStateEnters [i]; mGroupStateExits [i] = pGroupState.mGroupStateExits [i]; mGroupStateRTs [i] = pGroupState.mGroupStateRTs [i]; } TransferCount = pGroupState.TransferCount; for (int i = 0; i < TransferCount; i++) { mGroupStateTransfers [i] = pGroupState.mGroupStateTransfers [i]; } tempID = pGroupState.tempID; } } public class GroupStateUpdateSystem:USystem { public override void Init () { base.Init (); this.AddRequestComponent (typeof(AIGroupState)); } public override void Update (UEntity uEntity) { base.Update (uEntity); if (!uEntity.GetComponent<AIGroupState> ().isEnable) return; AIEntity pLeader = uEntity.GetComponent<AIGroupState> ().pLeader; AIEntity[] pMembers = uEntity.GetComponent<AIGroupState> ().pMembers; int pid = uEntity.GetComponent<AIGroupState> ().tempGroupID; foreach(GroupStateTransferNode gstn in uEntity.GetComponent<AIGroupState>().mGroupStateAnyTransfers) { int id = gstn.id; if (id == uEntity.GetComponent<AIGroupState> ().tempID) { continue; } GroupStateTransfer tTransfer = gstn.mTransfer; float rate = tTransfer (pLeader,pMembers,pid); if (rate * Time.deltaTime > Random.Range (0.0f, 1.0f)) { GroupStateExit tExit = uEntity.GetComponent<AIGroupState>().mGroupStateExits[uEntity.GetComponent<AIGroupState>().tempID]; tExit (pLeader,pMembers,pid); uEntity.GetComponent<AIGroupState> ().tempID = id; GroupStateEnter tEnter = uEntity.GetComponent<AIGroupState>().mGroupStateEnters[uEntity.GetComponent<AIGroupState>().tempID]; tEnter (pLeader,pMembers,pid); GroupStateRT ttRT = uEntity.GetComponent<AIGroupState> ().mGroupStateRTs [uEntity.GetComponent<AIGroupState> ().tempID]; ttRT (pLeader,pMembers,pid); string ttName = uEntity.GetComponent<AIGroupState>().mAnimationDic[uEntity.GetComponent<AIGroupState> ().tempID]; uEntity.GetComponent<AIAnimation> ().tempAnim = ttName; return; } } foreach(GroupStateTransferNode gstn in uEntity.GetComponent<AIGroupState>().mGroupStateTransfers[uEntity.GetComponent<AIGroupState>().tempID]) { int id = gstn.id; GroupStateTransfer tTransfer = gstn.mTransfer; float rate = tTransfer (pLeader,pMembers,pid); if (rate * Time.deltaTime > Random.Range (0.0f, 1.0f)) { GroupStateExit tExit = uEntity.GetComponent<AIGroupState>().mGroupStateExits[uEntity.GetComponent<AIGroupState>().tempID]; tExit (pLeader,pMembers,pid); uEntity.GetComponent<AIGroupState> ().tempID = id; GroupStateEnter tEnter = uEntity.GetComponent<AIGroupState>().mGroupStateEnters[uEntity.GetComponent<AIGroupState>().tempID]; tEnter (pLeader,pMembers,pid); break; } } GroupStateRT tRT = uEntity.GetComponent<AIGroupState> ().mGroupStateRTs [uEntity.GetComponent<AIGroupState> ().tempID]; tRT (pLeader,pMembers,pid); string tName = uEntity.GetComponent<AIGroupState>().mAnimationDic[uEntity.GetComponent<AIGroupState> ().tempID]; uEntity.GetComponent<AIAnimation> ().tempAnim = tName; } }