1.怎么判断直线通往目标的路径上有障碍物?
这种情况下,DDA算法比A*更快,如果没有障碍物,那么直接前进即可,不用A*算法,对于coc这种百人寻路是可以节省不少性能的。
代码如下:
public bool CheckCanGoForward(Vector3 startPos, Vector3 endPos, int extNum)
{
//init: gather starting location information.
int startCell = GetCellIndex(startPos);
int lastCell = GetCellIndex (endPos);
if(lastCell < 0)
{
Debug.Log(“endPos is valid”);
return false;
}
float maxDis = (endPos - startPos).sqrMagnitude;
Vector2 dir = new Vector2 (endPos.x - startPos.x, endPos.z - startPos.z);
bool bInBounds = ( startCell >= 0 && startCell < NumberOfCells );
if (!bInBounds)
{
System.Diagnostics.Debug.Assert(bInBounds, “starting position of the ray is not in bounds in call to Raycast2D” +
“Add logic to find the starting cell when the ray position starts out of bounds”);
return false;
}
int X = GetColumn(startCell);
int Y = GetRow(startCell);
int stepX = Math.Sign(dir.x);
int stepY = Math.Sign(dir.y);
float nearestGridX = (stepX < 0) ? (startPos.x) : (startPos.x + m_cellSize);
float nearestGridY = (stepY < 0) ? (startPos.z - m_cellSize) : (startPos.z);
float thetaInDegrees = Vector3.Angle( kXAxis, dir);
float thetaInRadians = thetaInDegrees * Mathf.Deg2Rad;
float cosTheta = Mathf.Cos( thetaInRadians );
float sinTheta = Mathf.Sin( thetaInRadians );
//parametric form requires taking ray.Position as the origin, hence the ” - ray.Position”
float tMaxX = Math.Abs((nearestGridX - startPos.x) / cosTheta);
float tMaxY = Math.Abs((nearestGridY - startPos.z) / sinTheta);
float tDeltaX = Math.Abs(m_cellSize / cosTheta);
float tDeltaY = Math.Abs(m_cellSize / sinTheta);
//loop: traverse the cells until there is a collision or ray is out of bounds.
bool bHitMapEdge = false;
int prevX = X;
int prevY = Y;
int maxCount = 100;
int nowCount = 0;
while (nowCount < maxCount)
{
nowCount++;
if (tMaxX < tMaxY)
{
prevX = X;
tMaxX += tDeltaX;
X += stepX;
}
else
{
prevY = Y;
tMaxY += tDeltaY;
Y += stepY;
}
Vector3 nowPos = startPos + new Vector3(stepX * tMaxX, 0f, stepY * tMaxY);
int cell = GetCellIndex(nowPos);
if(!checkCanGo(cell, extNum, null))
{
return false;
}
if((nowPos - startPos).sqrMagnitude >= maxDis)
{
return true;
}
}
Debug.Log (“can not find forward pos to Go“);
return false;
}
2.如果目标点是不可寻路点,怎么找到最近的一点可行走区域。采用螺旋型搜索,可以最快找到目标。
public Vector3 GetNearestCanGoPos(Vector3 position, int extNum, Dictionary<int, bool> otherAgent)
{
// Save this value off, in case we need to use it to search for a valid location further along in this function.
Vector3 originalPosition = position;
int cellIndex = GetCellIndex(position);
if(cellIndex == SimpleAI.Planning.Node.kInvalidIndex)
{
Debug.Log(“targetPos is out of bounds”);
return Vector3.zero;
}
int maxCount = 25;
int nowCount = 0;
int len = 1;
if (checkCanGo(cellIndex, extNum, otherAgent))
{
return position;
}
eNeighborDirection dir = eNeighborDirection.kTop;
int index = cellIndex;
while(nowCount < maxCount)
{
nowCount ++;
if(len == 0)
{
len = Mathf.FloorToInt((nowCount + 1) / 2);
switch(dir)
{
case eNeighborDirection.kTop:
dir = eNeighborDirection.kLeft;
break;
case eNeighborDirection.kLeft:
dir = eNeighborDirection.kBottom;
break;
case eNeighborDirection.kBottom:
dir = eNeighborDirection.kRight;
break;
case eNeighborDirection.kRight:
dir = eNeighborDirection.kTop;
break;
}
}
index = GetNeighbor(index, dir);
if(checkCanGo(index, extNum, otherAgent))
{
return GetCellPosition(index);
}
len–;
}
return Vector3.zero;
}
3.一个物体,怎么判断它踩住了多少个格子。特别是不规则的物体。
首先,你要计算出这个物体的边界,剩下就是对边界内的所有格子进行判断,那么我们怎么知道这个格子到底是被物体踩住了,还是空心的呢?
利用射线,可以很快得出结果:
public int[] GetObstructedCells(Grid grid, out int numObstructedCells)
{
numObstructedCells = 0;
if ( collider == null )
{
return null;
}
Bounds bounds = collider.bounds;
bounds.Expand(m_scale);
// lowerLeftPos Represents the center of the first cell that is covered, in the lower left corner. We march right and up
// from this cell.
Vector3 upperLeftPos = new Vector3( bounds.min.x, grid.Origin.y, bounds.max.z );
Vector3 upperRightPos = new Vector3( bounds.max.x, grid.Origin.y, bounds.max.z );
Vector3 lowerLeftPos = new Vector3( bounds.min.x, grid.Origin.y, bounds.min.z );
Vector3 lowerRightPos = new Vector3( bounds.max.x, grid.Origin.y, bounds.min.z );
Vector3 horizDir = (upperRightPos - upperLeftPos).normalized;
Vector3 vertDir = (upperLeftPos - lowerLeftPos).normalized;
float horizLength = bounds.size.x;
float vertLength = bounds.size.z;
UpdateObstructedCellPool(grid);
// Determine which cells are actually obstructed
for ( int rowCount = 0; rowCount < m_numObstructedCellPoolRows; rowCount++ )
{
float currentVertLength = rowCount * grid.CellSize;
for ( int colCount = 0; colCount < m_numObstructedCellPoolColumns; colCount++ )
{
float currentHorizLength = colCount * grid.CellSize;
Vector3 testPos = lowerLeftPos + horizDir * currentHorizLength + vertDir * currentVertLength;
testPos.x = Mathf.Clamp(testPos.x, bounds.min.x, bounds.max.x);
testPos.z = Mathf.Clamp(testPos.z, bounds.min.z, bounds.max.z);
if ( grid.IsInBounds(testPos) )
{
Vector3 above = testPos + (Vector3.up * 0.5f);
Vector3 below = testPos + (Vector3.down * 0.5f);
if (Physics.CheckCapsule(above, below, grid.CellSize / 2f - 0.1f, 1 << LayerMask.NameToLayer(“Default”)))
{
int obstructedCellIndex = grid.GetCellIndex(testPos);
m_obstructedCellPool[numObstructedCells] = obstructedCellIndex;
numObstructedCells++;
}
}
if ( currentHorizLength > horizLength )
{
break;
}
}
if ( currentVertLength > vertLength )
{
break;
}
}
return m_obstructedCellPool;
}