为了制作具有群体性行为的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;
}
}