需求:模拟企鹅群以一种三角形的阵型移动,并向目标发动冲击。冲击时候的企鹅不在跟随阵型移动,阵型内的企鹅跟随阵型移动,并且会自动补全阵型。
企鹅群体大概是这样的阵型:
o
o o
o o o
可以抽象成一个数组:
fromation = new int[,]{
{ 0,0,1,0,0 },
{ 0,1,0,1,0 },
{ 1,0,1,0,1 }
};
class PenguinComp
{
Vector2Int index;
bool isMoving;
}
1记为有企鹅的位置,0记为没企鹅的位置,给企鹅的类加入一个二维数组的索引,用来判断企鹅所在的位置,并通过比对来判定目标位置是否有可用的企鹅。
那么formation的数组的每个位置有三种情况:
1.这个位置不需要企鹅:记为0
2.这个位置需要且被企鹅占用:记为 1
3.这个位置需要且没被企鹅占用:记为 -1
在每一帧的时候去查找目标位置,在若对应位置 为-1的时候则从下一行获取为1的位置来记录来进行往上偏移的队伍补全。
然后当企鹅在移动的时候把对应的-1格子置为1,企鹅原来的格子置为-1,并且把企鹅isMoving设置为true。
表示目标对象的位置被企鹅占用了,但是占用的企鹅还在路上。
这样只要搜索到位置为-1的位置,并在下一排找到位置为1且占用的企鹅已经抵达的格子进行补全就行了。
然后会发现,进行移动的企鹅都是最左边的位置的企鹅进行移动。按道理来讲,若有企鹅补全,应该是在后面一行的临近位置进行补全的。
在补全的时候添加一个范围,
例如:
若要在(i,j)补全一只企鹅 则后面搜索企鹅的范围应该先在(i-1,j+1) 和(i+1,j+1)之间进行搜索,然后再从其他位置进行搜索。
进行了上述改动之后又会发现,这次所选择的企鹅变成限制了范围后的最左边的企鹅。讲道理的话应该需要轮流使用。
这样不妨使用权重的方式进行:
每次有企鹅从这个位置出发时候就先进行+1在进行相反数处理,则第N次出发后这个位置的值就会变成 -N,那么在它抵达之后把当前位置再进行一个相反数,则当前位置的数值变成N。
这样的话,数值越大,证明这个位置移动的企鹅越多,这样的话,下次这个遍历(i-1,j+1) 和(i+1,j+1)之间选择企鹅的时候,选择数值小的,就可以使得左右两边的企鹅移动次数更加平均。
最后代码大概这样:
void LineUpPengineGroup()
{
//PrintDoubleArray(fromation);
for (int i = 0; i < fromationHeight;i++)
{
for(int j = 0;j< fromationWidth; j++)
{
//不需要排新的企鹅
if (fromation[i, j] >= 0) continue;
PenguinComp penguin = null;
//最后一排之前用后面排得企鹅排
if (i < fromationHeight - 1)
{
// 检索的左右边界
int left = ((j - 1) >= 0)? j - 1: 0;
int right = ((j + 1) < fromationWidth) ? j + 1: fromationWidth - 1;
//选择之前没移动过的企鹅
int weight = 999;
for(int k = left; k <= right; k++)
{
PenguinComp penguinTemp = FindPenguinByIndex(new Vector2Int(i + 1, k));
if ((weight < fromation[i + 1, k] || fromation[i + 1, k] < 1) || penguinTemp == null) continue;
weight = fromation[i + 1, k];
penguin = penguinTemp;
}
}
//最后一排的企鹅
else
{
penguin = PopPenguinOutOfScreen();
if (penguin == null) break;
}
//计算坐标并归位
if (penguin != null) LineUpPengine(penguin, new Vector2Int(i, j));
}
}
}