add
This commit is contained in:
851
Assets/CoolapeFrame/AIPath/Scripts/CLAStarPathSearch.cs
Normal file
851
Assets/CoolapeFrame/AIPath/Scripts/CLAStarPathSearch.cs
Normal file
@@ -0,0 +1,851 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coolape
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// CLAS tar path search. 我写的A星寻路,只支持2D
|
||||
/// </summary>
|
||||
public class CLAStarPathSearch : MonoBehaviour
|
||||
{
|
||||
public static CLAStarPathSearch current;
|
||||
public int numRows = 10;
|
||||
public int numCols = 10;
|
||||
public float cellSize = 1;
|
||||
//寻路是4方向还是8方向
|
||||
public NumNeighbours numNeighbours = NumNeighbours.Eight;
|
||||
//扫描类型
|
||||
public ScanType scanType = ScanType.ObstructNode;
|
||||
//障碍
|
||||
public LayerMask obstructMask;
|
||||
//可以通行的layer
|
||||
public LayerMask passableMask;
|
||||
//检测障碍时用
|
||||
public float rayDis4Scan = 1;
|
||||
//检测障碍时用
|
||||
public RayDirection rayDirection = RayDirection.Up;
|
||||
//自动扫描一次障碍,init后自己用调用
|
||||
public bool isAutoScan = true;
|
||||
//缓存路径
|
||||
public bool needCachePaths = false;
|
||||
//过滤掉多余的节(当为true时,障碍物的collider尽量和障碍物保持一至大小,因为是通过射线来检测过滤多余的节点)
|
||||
public bool isFilterPathByRay = false;
|
||||
|
||||
//柔化路径
|
||||
public bool isSoftenPath = true;
|
||||
public CLAIPathUtl.SoftenPathType softenPathType = CLAIPathUtl.SoftenPathType.Line;
|
||||
public int softenFactor = 3;
|
||||
|
||||
//网格基础数据
|
||||
public GridBase grid = new GridBase();
|
||||
//节点map
|
||||
public Dictionary<int, CLAStarNode> nodesMap = new Dictionary<int, CLAStarNode>();
|
||||
public bool showGrid = true;
|
||||
public bool showObstruct = true;
|
||||
public bool isIninted = false;
|
||||
[HideInInspector]
|
||||
public Vector3 originPos = Vector3.zero;
|
||||
public ArrayList OnGridStateChgCallbacks = new ArrayList();
|
||||
//当ray检测后,再检测一次Sphere以保当节点在障碍内部时也可能检测成功
|
||||
float radius4CheckSphere = 1;
|
||||
|
||||
//异步的
|
||||
bool isSearching = false;
|
||||
ListPool listPool = new ListPool();
|
||||
Queue<ArrayList> searchQueue = new Queue<ArrayList>();
|
||||
Queue<ArrayList> finishSearchQueue = new Queue<ArrayList>();
|
||||
Dictionary<string, float> nodesDisMap = new Dictionary<string, float>();
|
||||
Dictionary<string, List<Vector3>> pathsCache = new Dictionary<string, List<Vector3>>();
|
||||
|
||||
public CLAStarPathSearch()
|
||||
{
|
||||
current = this;
|
||||
}
|
||||
WaitCallback _threadSearch;
|
||||
WaitCallback threadSearch
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_threadSearch == null) {
|
||||
_threadSearch = new WaitCallback(doSearchPathAsyn);
|
||||
}
|
||||
return _threadSearch;
|
||||
}
|
||||
}
|
||||
// Use this for initialization
|
||||
public void Start()
|
||||
{
|
||||
if (isAutoScan)
|
||||
{
|
||||
init();
|
||||
}
|
||||
}
|
||||
public void init()
|
||||
{
|
||||
init(transform.position);
|
||||
}
|
||||
/// <summary>
|
||||
/// Init this instance.初始化网格
|
||||
/// </summary>
|
||||
public void init(Vector3 origin)
|
||||
{
|
||||
isSearching = false;
|
||||
originPos = origin;
|
||||
radius4CheckSphere = cellSize / 4;
|
||||
grid.init(origin, numRows, numCols, cellSize);
|
||||
|
||||
nodesMap.Clear();
|
||||
nodesDisMap.Clear();
|
||||
pathsCache.Clear();
|
||||
for (int i = 0; i < grid.NumberOfCells; i++)
|
||||
{
|
||||
nodesMap[i] = new CLAStarNode(i, grid.GetCellCenter(i));
|
||||
}
|
||||
|
||||
//设置每个节点的左右上下一周的节点
|
||||
for (int i = 0; i < grid.NumberOfCells; i++)
|
||||
{
|
||||
CLAStarNode left = null;
|
||||
nodesMap.TryGetValue(grid.LeftIndex(i), out left);
|
||||
CLAStarNode right = null;
|
||||
nodesMap.TryGetValue(grid.RightIndex(i), out right);
|
||||
CLAStarNode up = null;
|
||||
nodesMap.TryGetValue(grid.UpIndex(i), out up);
|
||||
CLAStarNode down = null;
|
||||
nodesMap.TryGetValue(grid.DownIndex(i), out down);
|
||||
CLAStarNode leftUp = null;
|
||||
nodesMap.TryGetValue(grid.LeftUpIndex(i), out leftUp);
|
||||
CLAStarNode leftDown = null;
|
||||
nodesMap.TryGetValue(grid.LeftDownIndex(i), out leftDown);
|
||||
CLAStarNode rightUp = null;
|
||||
nodesMap.TryGetValue(grid.RightUpIndex(i), out rightUp);
|
||||
CLAStarNode rightDown = null;
|
||||
nodesMap.TryGetValue(grid.RightDownIndex(i), out rightDown);
|
||||
if (nodesMap[i] != null)
|
||||
{
|
||||
nodesMap[i].init(left, right, up, down, leftUp, leftDown, rightUp, rightDown);
|
||||
}
|
||||
}
|
||||
isIninted = true;
|
||||
if (isAutoScan)
|
||||
{
|
||||
scan();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan this instance.扫描网格哪些是障碍格
|
||||
/// </summary>
|
||||
public void scan()
|
||||
{
|
||||
pathsCache.Clear();
|
||||
if (!isIninted)
|
||||
{
|
||||
init();
|
||||
}
|
||||
for (int i = 0; i < grid.NumberOfCells; i++)
|
||||
{
|
||||
scanOne(i);
|
||||
}
|
||||
onGridStateChg();
|
||||
}
|
||||
|
||||
void scanOne(int index)
|
||||
{
|
||||
if (!nodesMap.ContainsKey(index))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Vector3 position = nodesMap[index].position;
|
||||
if (scanType == ScanType.ObstructNode)
|
||||
{
|
||||
nodesMap[index].isObstruct = raycastCheckCell(position, obstructMask);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool ispass = raycastCheckCell(position, passableMask);
|
||||
bool ishit = raycastCheckCell(position, obstructMask);
|
||||
nodesMap[index].isObstruct = ishit || !ispass;
|
||||
}
|
||||
}
|
||||
|
||||
bool raycastCheckCell(Vector3 cellPos, LayerMask mask)
|
||||
{
|
||||
bool ishit = false;
|
||||
if (rayDirection == RayDirection.Both)
|
||||
{
|
||||
ishit = Physics.Raycast(cellPos, Vector3.up, rayDis4Scan, mask)
|
||||
|| Physics.Raycast(cellPos, -Vector3.up, rayDis4Scan, mask);
|
||||
}
|
||||
else if (rayDirection == RayDirection.Up)
|
||||
{
|
||||
ishit = Physics.Raycast(cellPos, Vector3.up, rayDis4Scan, mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
ishit = Physics.Raycast(cellPos, -Vector3.up, rayDis4Scan, mask);
|
||||
}
|
||||
|
||||
if (!ishit)
|
||||
{
|
||||
ishit = Physics.CheckSphere(cellPos, radius4CheckSphere, mask);
|
||||
}
|
||||
return ishit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshs the range.刷新坐标center,半径为r的网格的障碍状态
|
||||
/// </summary>
|
||||
/// <param name="center">Center.</param>
|
||||
/// <param name="r">The red component.半径格子数</param>
|
||||
public void scanRange(Vector3 center, int r)
|
||||
{
|
||||
int centerIndex = grid.GetCellIndex(center);
|
||||
scanRange(centerIndex, r);
|
||||
}
|
||||
|
||||
public void scanRange(int centerIndex, int r)
|
||||
{
|
||||
List<int> cells = grid.getCells(centerIndex, r * 2);
|
||||
for (int i = 0; i < cells.Count; i++)
|
||||
{
|
||||
scanOne(cells[i]);
|
||||
}
|
||||
onGridStateChg();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the grid state callback. 添加当网格有变化时的回调
|
||||
/// </summary>
|
||||
/// <param name="callback">Callback.</param>
|
||||
public void addGridStateChgCallback(object callback)
|
||||
{
|
||||
if (!OnGridStateChgCallbacks.Contains(callback))
|
||||
{
|
||||
OnGridStateChgCallbacks.Add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the grid state callback.移除当网格有变化时的回调
|
||||
/// </summary>
|
||||
/// <param name="callback">Callback.</param>
|
||||
public void removeGridStateChgCallback(object callback)
|
||||
{
|
||||
OnGridStateChgCallbacks.Remove(callback);
|
||||
}
|
||||
|
||||
void onGridStateChg()
|
||||
{
|
||||
for (int i = 0; i < OnGridStateChgCallbacks.Count; i++)
|
||||
{
|
||||
Utl.doCallback(OnGridStateChgCallbacks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Revises from node.修正寻路开始节点
|
||||
/// </summary>
|
||||
/// <returns>The from node.</returns>
|
||||
/// <param name="orgFromNode">Org from node.</param>
|
||||
CLAStarNode reviseFromNode(Vector3 fromPos, CLAStarNode orgFromNode)
|
||||
{
|
||||
if (!orgFromNode.isObstruct) return orgFromNode;
|
||||
int count = orgFromNode.aroundList.Count;
|
||||
CLAStarNode node = null;
|
||||
CLAStarNode fromNode = null;
|
||||
float dis = -1;
|
||||
float tmpDis = 0;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
node = orgFromNode.aroundList[i];
|
||||
if (node != null && !node.isObstruct)
|
||||
{
|
||||
tmpDis = Vector3.Distance(node.position, fromPos);
|
||||
if (dis < 0 || tmpDis < dis)
|
||||
{
|
||||
dis = tmpDis;
|
||||
fromNode = orgFromNode.aroundList[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return fromNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searchs the path. 异步的寻路
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if path was searched,可以到达 <c>false</c> otherwise.不可到过</returns>
|
||||
/// <param name="from">From.出发点坐标</param>
|
||||
/// <param name="to">To.目标点坐标</param>
|
||||
/// <param name="finishSearchCallback">finish Search Callback</param>
|
||||
public void searchPathAsyn(Vector3 from, Vector3 to, object finishSearchCallback)
|
||||
{
|
||||
|
||||
//bool canReach = false;
|
||||
//List<Vector3> vectorList = new List<Vector3>();
|
||||
//if (getCachePath(from, to, ref vectorList, ref canReach))
|
||||
//{
|
||||
// Utl.doCallback(finishSearchCallback, canReach, vectorList);
|
||||
// return;
|
||||
//}
|
||||
|
||||
ArrayList list = listPool.borrow();
|
||||
list.Add(from);
|
||||
list.Add(to);
|
||||
list.Add(finishSearchCallback);
|
||||
searchQueue.Enqueue(list);
|
||||
if (!isSearching)
|
||||
{
|
||||
ThreadEx.exec2(threadSearch);
|
||||
}
|
||||
}
|
||||
|
||||
void doSearchPathAsyn(object obj)
|
||||
{
|
||||
if (searchQueue.Count == 0)
|
||||
{
|
||||
isSearching = false;
|
||||
return;
|
||||
}
|
||||
isSearching = true;
|
||||
ArrayList list = searchQueue.Dequeue();
|
||||
Vector3 from = (Vector3)(list[0]);
|
||||
Vector3 to = (Vector3)(list[1]);
|
||||
object callback = list[2];
|
||||
int fromIndex = grid.GetCellIndex(from);
|
||||
int toIndex = grid.GetCellIndex(to);
|
||||
|
||||
List<Vector3> outPath = null;
|
||||
bool isCachePath = false;
|
||||
bool canReach = searchPath(from, to, ref outPath, ref isCachePath, true);
|
||||
list.Clear();
|
||||
list.Add(callback);
|
||||
list.Add(canReach);
|
||||
list.Add(outPath);
|
||||
list.Add(isCachePath);
|
||||
list.Add(fromIndex);
|
||||
list.Add(toIndex);
|
||||
finishSearchQueue.Enqueue(list);
|
||||
|
||||
doSearchPathAsyn(null);
|
||||
}
|
||||
|
||||
//缓存数据,方便可以快速找到数据
|
||||
void cachePaths(int fromIndex, int toIndex, List<Vector3> vectorList)
|
||||
{
|
||||
int rang = 6;
|
||||
List<int> list1 = null;
|
||||
List<int> list2 = null;
|
||||
list1 = grid.getCells(fromIndex, rang);
|
||||
list2 = grid.getCells(toIndex, rang);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
string key = "";
|
||||
for (int i = 0; i < list1.Count; i++)
|
||||
{
|
||||
for (int j = 0; j < list2.Count; j++)
|
||||
{
|
||||
if (list1[i] < 0 || list2[j] < 0) continue;
|
||||
sb.Clear();
|
||||
key = sb.Append(list1[i]).Append("_").Append(list2[j]).ToString();
|
||||
pathsCache[key] = vectorList;
|
||||
sb.Clear();
|
||||
key = sb.Append(list2[j]).Append("_").Append(list1[i]).ToString();
|
||||
pathsCache[key] = vectorList;
|
||||
}
|
||||
}
|
||||
sb.Clear();
|
||||
}
|
||||
|
||||
public bool getCachePath(Vector3 from, Vector3 to, ref List<Vector3> vectorList, ref bool canReach)
|
||||
{
|
||||
int fromIndex = grid.GetCellIndex(from);
|
||||
int toIndex = grid.GetCellIndex(to);
|
||||
string key = fromIndex + "_" + toIndex;
|
||||
List<Vector3> tmpPath = null;
|
||||
if (pathsCache.TryGetValue(key, out tmpPath))
|
||||
{
|
||||
if (vectorList == null)
|
||||
{
|
||||
vectorList = new List<Vector3>();
|
||||
}
|
||||
else
|
||||
{
|
||||
vectorList.Clear();
|
||||
}
|
||||
vectorList.Add(from); //把路径的第一个点换成新的起始点
|
||||
for (int i = 1; i < tmpPath.Count; i++)
|
||||
{
|
||||
vectorList.Add(tmpPath[i]);
|
||||
}
|
||||
int index = grid.GetCellIndex(vectorList[vectorList.Count - 1]);
|
||||
if (index == toIndex)
|
||||
{
|
||||
canReach = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
canReach = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Searchs the path.寻路
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if path was searched,可以到达 <c>false</c> otherwise.不可到过</returns>
|
||||
/// <param name="from">From.出发点坐标</param>
|
||||
/// <param name="to">To.目标点坐标</param>
|
||||
/// <param name="vectorList">Vector list.路径点坐标列表</param>
|
||||
public bool searchPath(Vector3 from, Vector3 to, ref List<Vector3> vectorList)
|
||||
{
|
||||
bool isCachePath = false;
|
||||
return searchPath(from, to, ref vectorList, ref isCachePath);
|
||||
}
|
||||
public bool searchPath(Vector3 from, Vector3 to, ref List<Vector3> vectorList, ref bool isCachePath, bool notPocSoftenPath = false)
|
||||
{
|
||||
if (!isIninted)
|
||||
{
|
||||
init();
|
||||
}
|
||||
isCachePath = false;
|
||||
int fromIndex = grid.GetCellIndex(from);
|
||||
int toIndex = grid.GetCellIndex(to);
|
||||
if (fromIndex < 0 || toIndex < 0)
|
||||
{
|
||||
Debug.LogWarning("Can not reach");
|
||||
return false;
|
||||
}
|
||||
CLAStarNode fromNode = nodesMap[fromIndex];
|
||||
if (fromNode.isObstruct)
|
||||
{
|
||||
fromNode = reviseFromNode(from, fromNode);
|
||||
if (fromNode == null)
|
||||
{
|
||||
Debug.LogWarning("无法到达");
|
||||
//无法到达
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (vectorList == null)
|
||||
{
|
||||
vectorList = new List<Vector3>();
|
||||
}
|
||||
else
|
||||
{
|
||||
vectorList.Clear();
|
||||
}
|
||||
|
||||
if (fromIndex == toIndex)
|
||||
{
|
||||
//就在目标点,直接判断为到达
|
||||
vectorList.Add(from);
|
||||
vectorList.Add(to);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool canReach = false;
|
||||
if (getCachePath(from, to, ref vectorList, ref canReach))
|
||||
{
|
||||
isCachePath = true;
|
||||
return canReach;
|
||||
}
|
||||
|
||||
// 本次寻路的唯一key,(并发同时处理多个寻路时会用到)
|
||||
string key = fromIndex + "_" + toIndex;
|
||||
|
||||
CLAStarNode toNode = nodesMap[toIndex];
|
||||
|
||||
List<CLAStarNode> openList = new List<CLAStarNode>();
|
||||
Dictionary<int, bool> closedList = new Dictionary<int, bool>();
|
||||
// F值缓存
|
||||
Dictionary<int, float> fValueMap = new Dictionary<int, float>();
|
||||
|
||||
//先把开始点加入到closedList
|
||||
closedList[fromIndex] = true;
|
||||
//计算一次open点列表
|
||||
calculationOpenList(key, fromNode, toNode, ref fValueMap, ref openList, closedList);
|
||||
|
||||
//离目标点最近的节点
|
||||
CLAStarNode nodeNearest = fromNode;
|
||||
CLAStarNode node = null;
|
||||
float dis4Target = -1;
|
||||
float tmpdis4Target = 0;
|
||||
int count = openList.Count;
|
||||
while (count > 0)
|
||||
{
|
||||
node = openList[count - 1];
|
||||
openList.RemoveAt(count - 1); //从openlist中移除
|
||||
closedList[node.index] = true;//设为closed
|
||||
|
||||
if (node.index == toNode.index)
|
||||
{
|
||||
//reached
|
||||
nodeNearest = node;
|
||||
canReach = true;
|
||||
break;
|
||||
}
|
||||
// 设置离目标点最新的点
|
||||
tmpdis4Target = distance(node, toNode);
|
||||
if (dis4Target < 0 || tmpdis4Target < dis4Target)
|
||||
{
|
||||
dis4Target = tmpdis4Target;
|
||||
nodeNearest = node;
|
||||
}
|
||||
//重新处理新的open点
|
||||
calculationOpenList(key, node, toNode, ref fValueMap, ref openList, closedList);
|
||||
count = openList.Count;
|
||||
}
|
||||
//回溯路径======================
|
||||
CLAStarNode parentNode = null;
|
||||
if (canReach)
|
||||
{
|
||||
vectorList.Insert(0, to);
|
||||
parentNode = nodeNearest.getParentNode(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
parentNode = nodeNearest;
|
||||
}
|
||||
|
||||
while (parentNode != null && parentNode != fromNode)
|
||||
{
|
||||
vectorList.Insert(0, parentNode.position);
|
||||
parentNode = parentNode.getParentNode(key);
|
||||
}
|
||||
if (vectorList.Count > 0)
|
||||
{
|
||||
vectorList.Insert(0, from);
|
||||
canReach = false;
|
||||
if (!notPocSoftenPath)
|
||||
{
|
||||
softenPath(ref vectorList);
|
||||
}
|
||||
}
|
||||
return canReach;
|
||||
}
|
||||
|
||||
public void softenPath(ref List<Vector3> vectorList)
|
||||
{
|
||||
if (isFilterPathByRay)
|
||||
{
|
||||
filterPath(ref vectorList);
|
||||
}
|
||||
if (isSoftenPath)
|
||||
{
|
||||
CLAIPathUtl.softenPath(ref vectorList, softenPathType, softenFactor, cellSize);
|
||||
}
|
||||
}
|
||||
|
||||
public bool isObstructNode(Vector3 pos)
|
||||
{
|
||||
int index = grid.GetCellIndex(pos);
|
||||
return isObstructNode(index);
|
||||
}
|
||||
|
||||
public bool isObstructNode(int index)
|
||||
{
|
||||
if (grid.IsInBounds(index))
|
||||
{
|
||||
CLAStarNode node = nodesMap[index];
|
||||
return node.isObstruct;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filters the path.过滤掉多余的节(障碍物的collider尽量和障碍物保持一至大小,因为是通过射线来检测过滤多余的节点)
|
||||
/// </summary>
|
||||
/// <param name="list">List.</param>
|
||||
public void filterPath(ref List<Vector3> list)
|
||||
{
|
||||
if (list == null || list.Count < 4)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Vector3 from = list[0];
|
||||
int i = 2;
|
||||
int fromIndex = grid.GetCellIndex(from);
|
||||
CLAStarNode fromNode = nodesMap[fromIndex];
|
||||
if (fromNode.isObstruct)
|
||||
{
|
||||
//因为list[0]有可能正好在障碍物的里面,这时射线是检测不到的
|
||||
from = list[1];
|
||||
i = 3;
|
||||
}
|
||||
|
||||
float dis = 0;
|
||||
while (i < list.Count)
|
||||
{
|
||||
dis = Vector3.Distance(from, list[i]);
|
||||
if (Physics.Raycast(from, list[i] - from, dis, obstructMask))
|
||||
{
|
||||
from = list[i - 1];
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
list.RemoveAt(i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculations the open list.计算可行的点
|
||||
/// </summary>
|
||||
/// <param name="from">From.</param>
|
||||
/// <param name="to">To.</param>
|
||||
/// <param name="openList">Open list.</param>
|
||||
void calculationOpenList(string key, CLAStarNode from, CLAStarNode to, ref Dictionary<int, float> fValueMap, ref List<CLAStarNode> openList, Dictionary<int, bool> closedList)
|
||||
{
|
||||
if (isNewOpenNode(from.up, openList, closedList))
|
||||
{
|
||||
addOpenNode(key, from.up, from, to, ref fValueMap, ref openList);
|
||||
}
|
||||
if (isNewOpenNode(from.down, openList, closedList))
|
||||
{
|
||||
addOpenNode(key, from.down, from, to, ref fValueMap, ref openList);
|
||||
}
|
||||
if (isNewOpenNode(from.left, openList, closedList))
|
||||
{
|
||||
addOpenNode(key, from.left, from, to, ref fValueMap, ref openList);
|
||||
}
|
||||
if (isNewOpenNode(from.right, openList, closedList))
|
||||
{
|
||||
addOpenNode(key, from.right, from, to, ref fValueMap, ref openList);
|
||||
}
|
||||
if (numNeighbours == NumNeighbours.Eight)
|
||||
{
|
||||
if (isNewOpenNode(from.leftUp, openList, closedList))
|
||||
{
|
||||
addOpenNode(key, from.leftUp, from, to, ref fValueMap, ref openList);
|
||||
}
|
||||
if (isNewOpenNode(from.leftDown, openList, closedList))
|
||||
{
|
||||
addOpenNode(key, from.leftDown, from, to, ref fValueMap, ref openList);
|
||||
}
|
||||
if (isNewOpenNode(from.rightUp, openList, closedList))
|
||||
{
|
||||
addOpenNode(key, from.rightUp, from, to, ref fValueMap, ref openList);
|
||||
}
|
||||
if (isNewOpenNode(from.rightDown, openList, closedList))
|
||||
{
|
||||
addOpenNode(key, from.rightDown, from, to, ref fValueMap, ref openList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the open node.新加入node,list的最后一位是f值最小的
|
||||
/// </summary>
|
||||
/// <param name="node">Node.</param>
|
||||
/// <param name="from">From.</param>
|
||||
/// <param name="to">To.</param>
|
||||
/// <param name="fValueMap">F value map.</param>
|
||||
/// <param name="openList">Open list.</param>
|
||||
void addOpenNode(string key, CLAStarNode node, CLAStarNode from, CLAStarNode to, ref Dictionary<int, float> fValueMap, ref List<CLAStarNode> openList)
|
||||
{
|
||||
float fval = distance(node, from) + distance(node, to);
|
||||
fValueMap[node.index] = fval;
|
||||
int i = openList.Count - 1;
|
||||
for (; i >= 0; i--)
|
||||
{
|
||||
float fval2 = fValueMap[openList[i].index];
|
||||
if (fval <= fval2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
//列表最后是F值最小的
|
||||
openList.Insert(i + 1, node);
|
||||
//设置该点的父节点,以便路径回溯时用
|
||||
node.setParentNode(from, key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ises the new open node. 节点是否需要新加入open
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if new open node was ised, <c>false</c> otherwise.</returns>
|
||||
/// <param name="node">Node.</param>
|
||||
/// <param name="openList">Open list.</param>
|
||||
/// <param name="closedList">Closed list.</param>
|
||||
bool isNewOpenNode(CLAStarNode node, List<CLAStarNode> openList, Dictionary<int, bool> closedList)
|
||||
{
|
||||
if (node == null
|
||||
|| node.isObstruct
|
||||
|| openList.Contains(node)
|
||||
|| closedList.ContainsKey(node.index)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Distance the specified node1 and node2.两个节点之间的距离
|
||||
/// </summary>
|
||||
/// <returns>The distance.</returns>
|
||||
/// <param name="node1">Node1.</param>
|
||||
/// <param name="node2">Node2.</param>
|
||||
public float distance(CLAStarNode node1, CLAStarNode node2)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
string key = sb.Append(node1.index).Append("_").Append(node2.index).ToString();
|
||||
sb.Clear();
|
||||
string key2 = sb.Append(node2.index).Append("_").Append(node1.index).ToString();
|
||||
sb.Clear();
|
||||
float dis = 0;
|
||||
if (nodesDisMap.TryGetValue(key, out dis))
|
||||
{
|
||||
return dis;
|
||||
}
|
||||
dis = Vector3.Distance(node1.position, node2.position);
|
||||
nodesDisMap[key] = dis;
|
||||
nodesDisMap[key2] = dis;
|
||||
return dis;
|
||||
}
|
||||
|
||||
public virtual void Update()
|
||||
{
|
||||
if (finishSearchQueue.Count > 0)
|
||||
{
|
||||
ArrayList list = finishSearchQueue.Dequeue();
|
||||
object callback = list[0];
|
||||
bool canReach = (bool)(list[1]);
|
||||
List<Vector3> outPath = list[2] as List<Vector3>;
|
||||
bool isCachePath = (bool)(list[3]);
|
||||
int fromIndex = (int)(list[4]);
|
||||
int toIndex = (int)(list[5]);
|
||||
if (!isCachePath && outPath != null && outPath.Count > 1)
|
||||
{
|
||||
softenPath(ref outPath);
|
||||
if (needCachePaths)
|
||||
{
|
||||
cachePaths(fromIndex, toIndex, outPath);
|
||||
}
|
||||
}
|
||||
Utl.doCallback(callback, canReach, outPath);
|
||||
listPool.release(list);
|
||||
}
|
||||
}
|
||||
//=============================================================
|
||||
//=============================================================
|
||||
//=============================================================
|
||||
#if UNITY_EDITOR
|
||||
Camera sceneCamera;
|
||||
//List<Vector3> _pathList;
|
||||
//public void showPath(List<Vector3> path) {
|
||||
// _pathList = path;
|
||||
//}
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
if (showGrid)
|
||||
{
|
||||
GridBase.DebugDraw(originPos, numRows, numCols, cellSize, Color.white);
|
||||
}
|
||||
if (showObstruct)
|
||||
{
|
||||
Vector3 pos;
|
||||
for (int i = 0; i < grid.NumberOfCells; i++)
|
||||
{
|
||||
CLAStarNode node = nodesMap[i];
|
||||
if (node.isObstruct)
|
||||
{
|
||||
//显示障碍格子
|
||||
pos = node.position;
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawCube(pos, Vector3.one * cellSize);
|
||||
Gizmos.color = Color.white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================
|
||||
//显示cell的周围格子============================
|
||||
/*
|
||||
Vector3 mousePosition = Event.current.mousePosition;
|
||||
sceneCamera = SceneView.lastActiveSceneView.camera;
|
||||
mousePosition.y = sceneCamera.pixelHeight - mousePosition.y;
|
||||
mousePosition = sceneCamera.ScreenToWorldPoint(mousePosition);
|
||||
//mousePosition.y = -mousePosition.y;
|
||||
mousePosition.y = 0;
|
||||
int index = grid.GetCellIndex(mousePosition);
|
||||
if (index >= 0)
|
||||
{
|
||||
CLAStarNode node = nodesMap[index];
|
||||
if (node != null)
|
||||
{
|
||||
for (int j = 0; j < node.aroundList.Count; j++)
|
||||
{
|
||||
pos = node.aroundList[j].position;
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawCube(pos, Vector3.one * cellSize);
|
||||
Gizmos.color = Color.white;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
//===========================================
|
||||
//===========================================
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//==============================================
|
||||
//==============================================
|
||||
public enum RayDirection
|
||||
{
|
||||
Up, /**< Casts the ray from the bottom upwards */
|
||||
Down, /**< Casts the ray from the top downwards */
|
||||
Both /**< Casts two rays in either direction */
|
||||
}
|
||||
public enum NumNeighbours
|
||||
{
|
||||
Four,
|
||||
Eight
|
||||
}
|
||||
public enum ScanType
|
||||
{
|
||||
ObstructNode,
|
||||
PassableNode
|
||||
}
|
||||
|
||||
public class ListPool
|
||||
{
|
||||
Queue queue = new Queue();
|
||||
public ArrayList borrow()
|
||||
{
|
||||
if (queue.Count == 0)
|
||||
{
|
||||
newList();
|
||||
}
|
||||
return queue.Dequeue() as ArrayList;
|
||||
}
|
||||
|
||||
public void release(ArrayList list)
|
||||
{
|
||||
list.Clear();
|
||||
queue.Enqueue(list);
|
||||
}
|
||||
|
||||
void newList()
|
||||
{
|
||||
queue.Enqueue(new ArrayList());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/CoolapeFrame/AIPath/Scripts/CLAStarPathSearch.cs.meta
Normal file
11
Assets/CoolapeFrame/AIPath/Scripts/CLAStarPathSearch.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f586ea662f494e128cefbccf74c0bbc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
406
Assets/CoolapeFrame/AIPath/Scripts/CLSeeker.cs
Normal file
406
Assets/CoolapeFrame/AIPath/Scripts/CLSeeker.cs
Normal file
@@ -0,0 +1,406 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coolape
|
||||
{
|
||||
public class CLSeeker : MonoBehaviour
|
||||
{
|
||||
public CLAStarPathSearch mAStarPathSearch;
|
||||
public Transform target;
|
||||
public Vector3 targetPos;
|
||||
//移动速度
|
||||
public float speed = 1;
|
||||
//转向速度(当为负=硬转向)
|
||||
public float turningSpeed = 5;
|
||||
//离目标多远就停止移动
|
||||
public float endReachedDistance = 0.2f;
|
||||
public bool canSearchPath = true;
|
||||
public bool canMove = false;
|
||||
public bool autoMoveOnFinishSeek = true;
|
||||
public MovingBy movingBy = MovingBy.Update;
|
||||
public bool unscaledTime = false;
|
||||
|
||||
public bool showPath = true;
|
||||
[System.NonSerialized]
|
||||
public List<Vector3> pathList = new List<Vector3>();
|
||||
public object onFinishSeekCallback;
|
||||
public object onMovingCallback;
|
||||
public object onArrivedCallback;
|
||||
[HideInInspector]
|
||||
public bool isSeekTargetLoop = false;
|
||||
public float seekTargetLoopIntvalSec = 1;
|
||||
public float nextSeekTargetTime = 0;
|
||||
|
||||
Transform _mTransform;
|
||||
public Transform mTransform
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_mTransform == null)
|
||||
{
|
||||
_mTransform = gameObject.transform;
|
||||
}
|
||||
return _mTransform;
|
||||
}
|
||||
}
|
||||
|
||||
// Use this for initialization
|
||||
public virtual void Start()
|
||||
{
|
||||
if (mAStarPathSearch == null)
|
||||
{
|
||||
mAStarPathSearch = CLAStarPathSearch.current;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual float cellSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return mAStarPathSearch.cellSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init the specified onFinishSeekCallback, onMovingCallback and onArrivedCallback.
|
||||
/// </summary>
|
||||
/// <param name="onFinishSeekCallback">On finish seek callback.完成寻路后的回(其实是同步模式)</param>
|
||||
/// <param name="onMovingCallback">On moving callback.移动时的回调</param>
|
||||
/// <param name="onArrivedCallback">On arrived callback.到达目的地的回调</param>
|
||||
public virtual void init(object onFinishSeekCallback, object onMovingCallback, object onArrivedCallback)
|
||||
{
|
||||
this.onFinishSeekCallback = onFinishSeekCallback;
|
||||
this.onMovingCallback = onMovingCallback;
|
||||
this.onArrivedCallback = onArrivedCallback;
|
||||
}
|
||||
|
||||
public virtual List<Vector3> seekTarget(Transform target)
|
||||
{
|
||||
return seekTarget(target, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seeks the target.寻找目标对
|
||||
/// </summary>
|
||||
/// <returns>The target.</returns>
|
||||
/// <param name="target">Target.目标对象</param>
|
||||
/// <param name="searchIntvalSec">Search intval sec.每隔xx秒重新寻路</param>
|
||||
public virtual List<Vector3> seekTarget(Transform target, float searchIntvalSec)
|
||||
{
|
||||
if (target == null) return null;
|
||||
this.target = target;
|
||||
canSearchPath = true;
|
||||
//fixedInvoke((Callback)seekTargetLoop, searchIntvalSec, searchIntvalSec);
|
||||
seekTargetLoopIntvalSec = searchIntvalSec;
|
||||
isSeekTargetLoop = true;
|
||||
nextSeekTargetTime = Time.realtimeSinceStartup + seekTargetLoopIntvalSec;
|
||||
return seek(target.position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the seek target.取消对目标的寻路
|
||||
/// </summary>
|
||||
public virtual void cancelSeekTarget()
|
||||
{
|
||||
isSeekTargetLoop = false;
|
||||
//cancelFixedInvoke4Lua((Callback)seekTargetLoop);
|
||||
}
|
||||
|
||||
void seekTargetLoop()
|
||||
{
|
||||
if (!canSearchPath || target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//float searchIntvalSec = (float)(objs[0]);
|
||||
seek(target.position);
|
||||
nextSeekTargetTime = Time.realtimeSinceStartup + seekTargetLoopIntvalSec;
|
||||
//fixedInvoke((Callback)seekTargetLoop, searchIntvalSec, searchIntvalSec);
|
||||
}
|
||||
|
||||
public virtual void seekAsyn(Vector3 toPos)
|
||||
{
|
||||
targetPos = toPos;
|
||||
canMove = false;
|
||||
stopMove();
|
||||
//pathList.Clear();
|
||||
mAStarPathSearch.searchPathAsyn(mTransform.position, toPos, (Callback)onSeekAsynCallback);
|
||||
}
|
||||
|
||||
void onSeekAsynCallback(params object[] objs)
|
||||
{
|
||||
bool canReach = (bool)(objs[0]);
|
||||
pathList = objs[1] as List<Vector3>;
|
||||
|
||||
//回调的第一个参数是路径,第二个参数是能否到达目标点
|
||||
Utl.doCallback(onFinishSeekCallback, pathList, canReach);
|
||||
|
||||
if (autoMoveOnFinishSeek)
|
||||
{
|
||||
//开始移动
|
||||
startMove();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual List<Vector3> seek(Vector3 toPos, float endReachDis)
|
||||
{
|
||||
endReachedDistance = endReachDis;
|
||||
return seek(toPos);
|
||||
}
|
||||
/// <summary>
|
||||
/// Seek the specified toPos.寻路
|
||||
/// </summary>
|
||||
/// <returns>The seek.路径列表</returns>
|
||||
/// <param name="toPos">To position.</param>
|
||||
public virtual List<Vector3> seek(Vector3 toPos)
|
||||
{
|
||||
targetPos = toPos;
|
||||
canMove = false;
|
||||
stopMove();
|
||||
pathList.Clear();
|
||||
bool canReach = mAStarPathSearch.searchPath(mTransform.position, toPos, ref pathList);
|
||||
|
||||
//回调的第一个参数是路径,第二个参数是能否到达目标点
|
||||
Utl.doCallback(onFinishSeekCallback, pathList, canReach);
|
||||
|
||||
if (autoMoveOnFinishSeek)
|
||||
{
|
||||
//开始移动
|
||||
startMove();
|
||||
}
|
||||
return pathList;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
public virtual void Update()
|
||||
{
|
||||
if(isSeekTargetLoop) {
|
||||
if(Time.realtimeSinceStartup >= nextSeekTargetTime) {
|
||||
seekTargetLoop();
|
||||
}
|
||||
}
|
||||
if (canMove && movingBy == MovingBy.Update)
|
||||
{
|
||||
if (unscaledTime)
|
||||
{
|
||||
moving(Time.unscaledDeltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
moving(Time.deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void FixedUpdate()
|
||||
{
|
||||
if (canMove && movingBy == MovingBy.FixedUpdate)
|
||||
{
|
||||
if (unscaledTime)
|
||||
{
|
||||
moving(Time.fixedUnscaledDeltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
moving(Time.fixedDeltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nextPahtIndex = 0;
|
||||
float movePersent = 0;
|
||||
bool finishOneSubPath = false;
|
||||
float offsetSpeed = 0;
|
||||
Vector3 diff4Moving = Vector3.zero;
|
||||
Vector3 fromPos4Moving = Vector3.zero;
|
||||
/// <summary>
|
||||
/// Begains the move.
|
||||
/// </summary>
|
||||
public virtual void startMove()
|
||||
{
|
||||
canMove = false;
|
||||
if (pathList == null || pathList.Count < 2)
|
||||
{
|
||||
if (pathList == null)
|
||||
{
|
||||
Debug.LogError("pathList == null!");
|
||||
}
|
||||
Debug.LogError("Path list error!");
|
||||
stopMove();
|
||||
Utl.doCallback(onArrivedCallback);
|
||||
return;
|
||||
}
|
||||
if (Vector3.Distance(mTransform.position, pathList[0]) < 0.001f)
|
||||
{
|
||||
//说明是在原点
|
||||
movePersent = 0;
|
||||
finishOneSubPath = false;
|
||||
fromPos4Moving = pathList[0];
|
||||
diff4Moving = pathList[1] - pathList[0];
|
||||
offsetSpeed = 1.0f / Vector3.Distance(pathList[0], pathList[1]);
|
||||
nextPahtIndex = 1;
|
||||
rotateTowards(diff4Moving, true);
|
||||
canMove = true;
|
||||
}
|
||||
else if (Vector3.Distance(mTransform.position, pathList[pathList.Count - 1]) <= endReachedDistance)
|
||||
{
|
||||
//到达目标点
|
||||
Utl.doCallback(onArrivedCallback);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
float dis = 0;
|
||||
float dis1 = 0;
|
||||
float dis2 = 0;
|
||||
for (int i = 1; i < pathList.Count; i++)
|
||||
{
|
||||
dis = Vector3.Distance(pathList[i - 1], pathList[i]);
|
||||
dis1 = Vector3.Distance(mTransform.position, pathList[i - 1]);
|
||||
dis2 = Vector3.Distance(mTransform.position, pathList[i]);
|
||||
if (Mathf.Abs(dis - (dis1 + dis2)) < 0.01f)
|
||||
{
|
||||
movePersent = dis1 / dis;
|
||||
finishOneSubPath = false;
|
||||
nextPahtIndex = i;
|
||||
fromPos4Moving = pathList[i - 1];
|
||||
diff4Moving = pathList[i] - pathList[i - 1];
|
||||
offsetSpeed = 1.0f / Vector3.Distance(pathList[i - 1], pathList[i]);
|
||||
rotateTowards(diff4Moving, true);
|
||||
canMove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!canMove)
|
||||
{
|
||||
Debug.LogWarning("说明没有找到起点,但是还是强制设置成可以移动");
|
||||
canMove = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void stopMove()
|
||||
{
|
||||
canMove = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moving the specified deltaTime.处理移动
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">Delta time.会根据不同的情况传入</param>
|
||||
protected void moving(float deltaTime)
|
||||
{
|
||||
if (pathList == null || nextPahtIndex >= pathList.Count)
|
||||
{
|
||||
Debug.LogError("moving error");
|
||||
if (pathList == null)
|
||||
{
|
||||
Debug.LogError("pathList == null!");
|
||||
}
|
||||
|
||||
stopMove();
|
||||
Utl.doCallback(onArrivedCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
movePersent += (deltaTime * speed * 0.3f * offsetSpeed);
|
||||
if (movePersent >= 1)
|
||||
{
|
||||
movePersent = 1;
|
||||
finishOneSubPath = true;
|
||||
}
|
||||
if (turningSpeed > 0)
|
||||
{
|
||||
rotateTowards(diff4Moving, false);
|
||||
}
|
||||
mTransform.position = fromPos4Moving + diff4Moving * movePersent;
|
||||
|
||||
Utl.doCallback(onMovingCallback);
|
||||
|
||||
if (nextPahtIndex == pathList.Count - 1)
|
||||
{
|
||||
//最后一段路径,即将要到达目的地
|
||||
if (finishOneSubPath ||
|
||||
Vector3.Distance(mTransform.position, pathList[pathList.Count - 1]) <= endReachedDistance)
|
||||
{
|
||||
stopMove();
|
||||
Utl.doCallback(onArrivedCallback);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (finishOneSubPath)
|
||||
{
|
||||
//移动完成一段路径,进入下一段路径的准备(一些变量的初始化)
|
||||
nextPahtIndex++;
|
||||
movePersent = 0;
|
||||
finishOneSubPath = false;
|
||||
fromPos4Moving = pathList[nextPahtIndex - 1];
|
||||
diff4Moving = pathList[nextPahtIndex] - pathList[nextPahtIndex - 1];
|
||||
offsetSpeed = 1.0f / Vector3.Distance(pathList[nextPahtIndex - 1], pathList[nextPahtIndex]);
|
||||
if (turningSpeed <= 0)
|
||||
{
|
||||
rotateTowards(diff4Moving, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the towards.转向
|
||||
/// </summary>
|
||||
/// <param name="dir">Dir.方向</param>
|
||||
/// <param name="immediately">If set to <c>true</c> immediately.立即转向,否则为慢慢转</param>
|
||||
protected void rotateTowards(Vector3 dir, bool immediately)
|
||||
{
|
||||
if (dir == Vector3.zero) return;
|
||||
|
||||
Quaternion rot = mTransform.rotation;
|
||||
Quaternion toTarget = Quaternion.LookRotation(dir);
|
||||
|
||||
if (immediately)
|
||||
{
|
||||
rot = toTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
rot = Quaternion.Slerp(rot, toTarget, turningSpeed * Time.deltaTime);
|
||||
}
|
||||
Vector3 euler = rot.eulerAngles;
|
||||
euler.z = 0;
|
||||
euler.x = 0;
|
||||
rot = Quaternion.Euler(euler);
|
||||
|
||||
mTransform.rotation = rot;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
//====================================================================
|
||||
#if UNITY_EDITOR
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawSphere(targetPos, 0.5f);
|
||||
Gizmos.color = Color.white;
|
||||
|
||||
if (showPath && pathList != null && pathList.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < pathList.Count - 1; i++)
|
||||
{
|
||||
Debug.DrawLine(pathList[i], pathList[i + 1], Color.green);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//====================================================================
|
||||
//====================================================================
|
||||
public enum MovingBy
|
||||
{
|
||||
Update,
|
||||
FixedUpdate
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/CoolapeFrame/AIPath/Scripts/CLSeeker.cs.meta
Normal file
11
Assets/CoolapeFrame/AIPath/Scripts/CLSeeker.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26e01a5dc8c554427b335736a19173a2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
658
Assets/CoolapeFrame/AIPath/Scripts/CLSeekerByRay.cs
Normal file
658
Assets/CoolapeFrame/AIPath/Scripts/CLSeekerByRay.cs
Normal file
@@ -0,0 +1,658 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Coolape;
|
||||
|
||||
namespace Coolape
|
||||
{
|
||||
/// <summary>
|
||||
/// CLAIP ath by ray simple.寻路通过射线[[只能处理简单的寻路,特别在凹形地形时可能无法寻到路]]
|
||||
/// </summary>
|
||||
[ExecuteInEditMode]
|
||||
public class CLSeekerByRay : CLSeeker
|
||||
{
|
||||
public LayerMask obstructMask; //障碍
|
||||
public float rayDistance = 1f; //射线长度
|
||||
//public float selfSize = 1;
|
||||
public float rayHeight = 0.5f;
|
||||
public SearchDirs rayDirs = SearchDirs._8;
|
||||
public int maxSearchTimes = 100; //最大寻路次数
|
||||
|
||||
//柔化路径
|
||||
public bool isSoftenPath = true;
|
||||
public CLAIPathUtl.SoftenPathType softenPathType = CLAIPathUtl.SoftenPathType.Line;
|
||||
public int softenFactor = 3;
|
||||
//---------------------------------------------
|
||||
List<Vector3> pointsDirLeft = new List<Vector3>(); //左边的方向的点
|
||||
List<Vector3> pointsDirRight = new List<Vector3>(); //右边的方向的点
|
||||
bool canLeftSearch = true;
|
||||
bool canRightSearch = true;
|
||||
//---------------------------------------------
|
||||
//几个方向
|
||||
public enum SearchDirs
|
||||
{
|
||||
_4,
|
||||
_8,
|
||||
_16,
|
||||
_32,
|
||||
}
|
||||
|
||||
public enum _Dir
|
||||
{
|
||||
up,
|
||||
bottom,
|
||||
left,
|
||||
right,
|
||||
}
|
||||
|
||||
public int dirNum
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (rayDirs)
|
||||
{
|
||||
case SearchDirs._4:
|
||||
return 4;
|
||||
case SearchDirs._8:
|
||||
return 8;
|
||||
case SearchDirs._16:
|
||||
return 16;
|
||||
case SearchDirs._32:
|
||||
return 32;
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the origin position.起点
|
||||
/// </summary>
|
||||
/// <value>The origin position.</value>
|
||||
public Vector3 originPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
Vector3 pos = mTransform.position;
|
||||
pos.y = rayHeight;
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
//resetCache();
|
||||
}
|
||||
|
||||
public override float cellSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return rayDistance;
|
||||
}
|
||||
}
|
||||
|
||||
public void resetCache()
|
||||
{
|
||||
canLeftSearch = true;
|
||||
canRightSearch = true;
|
||||
pathList = null;
|
||||
tmpVectorList1.Clear();
|
||||
tmpVectorList2.Clear();
|
||||
pointsDirLeft.Clear();
|
||||
pointsDirRight.Clear();
|
||||
getPoints(originPosition, mTransform.eulerAngles, rayDistance, ref pointsDirLeft, ref pointsDirRight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the points.
|
||||
/// </summary>
|
||||
/// <param name="center">From position.中心点</param>
|
||||
/// <param name="eulerAngles">Euler angles.朝向</param>
|
||||
/// <param name="r">The red component.半径</param>
|
||||
/// <param name="left">Left.左半点列表</param>
|
||||
/// <param name="right">Right.右半点列表</param>
|
||||
public void getPoints(Vector3 center, Vector3 eulerAngles, float r, ref List<Vector3> left, ref List<Vector3> right)
|
||||
{
|
||||
// float angle = 360.0f / (dirNum + 1);
|
||||
float angle = 360.0f / (dirNum);
|
||||
int half = dirNum / 2;
|
||||
Vector3 pos = Vector3.zero;
|
||||
for (int i = 0; i <= half; i++)
|
||||
{
|
||||
pos = AngleEx.getCirclePointStartWithYV3(center, r, eulerAngles.y - i * angle);
|
||||
pos.y = rayHeight;
|
||||
left.Add(pos);
|
||||
|
||||
pos = AngleEx.getCirclePointStartWithYV3(center, r, eulerAngles.y - (dirNum - i) * angle);
|
||||
pos.y = rayHeight;
|
||||
right.Add(pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override List<Vector3> seek(Vector3 toPos)
|
||||
{
|
||||
targetPos = toPos;
|
||||
canMove = false;
|
||||
resetCache();
|
||||
begainTime = Time.time;
|
||||
bool isCanReach = false;
|
||||
List<Vector3> leftPath = trySearchPathLeft(toPos);
|
||||
List<Vector3> rightPath = trySearchPathRight(toPos);
|
||||
if (leftPath != null && leftPath.Count > 0 && (rightPath == null || rightPath.Count == 0))
|
||||
{
|
||||
isCanReach = true;
|
||||
pathList = leftPath;
|
||||
}
|
||||
else if ((leftPath == null || leftPath.Count == 0) && rightPath != null && rightPath.Count > 0)
|
||||
{
|
||||
isCanReach = true;
|
||||
pathList = rightPath;
|
||||
}
|
||||
else if (leftPath != null && leftPath.Count > 0 && rightPath != null && rightPath.Count > 0)
|
||||
{
|
||||
isCanReach = true;
|
||||
pathList = getShortList(leftPath, rightPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
filterPath(ref tmpVectorList1);
|
||||
leftPath = tmpVectorList1;
|
||||
leftPath.Insert(0, mTransform.position);
|
||||
filterPath(ref tmpVectorList2);
|
||||
rightPath = tmpVectorList2;
|
||||
rightPath.Insert(0, mTransform.position);
|
||||
float dis1 = Vector3.Distance(leftPath[leftPath.Count - 1], toPos);
|
||||
float dis2 = Vector3.Distance(rightPath[rightPath.Count - 1], toPos);
|
||||
if (dis1 < dis2)
|
||||
{
|
||||
pathList = leftPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
pathList = rightPath;
|
||||
}
|
||||
|
||||
//计算离目标点最近的点
|
||||
float minDis = -1;
|
||||
float tmpMinDis = 0;
|
||||
int index = -1;
|
||||
for (int i = 0; i < pathList.Count; i++)
|
||||
{
|
||||
tmpMinDis = Vector3.Distance(pathList[i], toPos);
|
||||
if(minDis < 0 || tmpMinDis < minDis) {
|
||||
minDis = tmpMinDis;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
for (int i = index + 1; i < pathList.Count; i++) {
|
||||
pathList.RemoveAt(i);
|
||||
}
|
||||
|
||||
isCanReach = false;
|
||||
#if UNITY_EDITOR
|
||||
Debug.LogWarning("Cannot search path");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (isSoftenPath)
|
||||
{
|
||||
CLAIPathUtl.softenPath(ref pathList, softenPathType, softenFactor, cellSize);
|
||||
}
|
||||
|
||||
//回调的第一个参数是路径,第二个参数是能否到达目标点
|
||||
Utl.doCallback(onFinishSeekCallback, pathList, isCanReach);
|
||||
|
||||
if (autoMoveOnFinishSeek)
|
||||
{
|
||||
//开始移动
|
||||
startMove();
|
||||
}
|
||||
return pathList;
|
||||
}
|
||||
|
||||
public List<Vector3> trySearchPathLeft(Vector3 toPos)
|
||||
{
|
||||
//searchTime = 0;
|
||||
canLeftSearch = true;
|
||||
canRightSearch = false;
|
||||
tmpVectorList1.Clear();
|
||||
return doSearchPath(toPos);
|
||||
}
|
||||
|
||||
public List<Vector3> trySearchPathRight(Vector3 toPos)
|
||||
{
|
||||
//searchTime = 0;
|
||||
canLeftSearch = false;
|
||||
canRightSearch = true;
|
||||
tmpVectorList2.Clear();
|
||||
return doSearchPath(toPos);
|
||||
}
|
||||
|
||||
List<Vector3> tmpVectorList1 = new List<Vector3>();
|
||||
List<Vector3> tmpVectorList2 = new List<Vector3>();
|
||||
float begainTime = 0;
|
||||
public List<Vector3> doSearchPath(Vector3 toPos)
|
||||
{
|
||||
List<Vector3> list = null;
|
||||
|
||||
if (canReach(originPosition, toPos, endReachedDistance))
|
||||
{
|
||||
list = new List<Vector3>();
|
||||
list.Add(mTransform.position);
|
||||
list.Add(toPos);
|
||||
return list;
|
||||
}
|
||||
int searchTime = 0;
|
||||
list = searchPathByRay(originPosition, originPosition, toPos, Utl.getAngle(mTransform, toPos), ref searchTime);
|
||||
filterPath(ref list);
|
||||
if (list != null && list.Count > 0)
|
||||
{
|
||||
list.Insert(0, mTransform.position);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ises the in circle. 判断pos是不是正好在回路中
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if in circle was ised, <c>false</c> otherwise.</returns>
|
||||
/// <param name="list">List.</param>
|
||||
/// <param name="pos">Position.</param>
|
||||
public bool isInCircle(Vector3 pos, List<Vector3> list)
|
||||
{
|
||||
if (list.Count >= 4)
|
||||
{
|
||||
float minDis = cellSize / 10.0f;
|
||||
if (Vector3.Distance(list[list.Count - 4], pos) < minDis)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
for (int i = list.Count - 1; i > 0; i--)
|
||||
{
|
||||
if (Vector3.Distance(list[i], pos) < minDis)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searchs the path by ray.
|
||||
/// </summary>
|
||||
/// <returns>The path by ray.</returns>
|
||||
/// <param name="prefromPos">Prefrom position.前一个起始点</param>
|
||||
/// <param name="fromPos">From position.当前的起始点</param>
|
||||
/// <param name="toPos">To position.目标点</param>
|
||||
/// <param name="angle">Angle.当前点的朝向角度</param>
|
||||
List<Vector3> searchPathByRay(Vector3 prefromPos, Vector3 fromPos, Vector3 toPos, Vector3 angle, ref int searchTime)
|
||||
{
|
||||
if (maxSearchTimes > 0 && (searchTime + 1) >= maxSearchTimes)
|
||||
{
|
||||
Debug.LogWarning("search times at the maxtimes=" + maxSearchTimes);
|
||||
return null;
|
||||
}
|
||||
//Vector3 dir = toPos - fromPos;
|
||||
List<Vector3> vetorList = null;
|
||||
if (canReach(fromPos, toPos, 0))
|
||||
{
|
||||
//可以到达目标点,把该点加到路径中返回
|
||||
vetorList = new List<Vector3>();
|
||||
vetorList.Add(toPos);
|
||||
return vetorList;
|
||||
}
|
||||
else
|
||||
{
|
||||
//起始点不能到达目标点,则从起始点的周围开始重新寻路
|
||||
Vector3 angle2 = angle;
|
||||
Vector3 from = fromPos;
|
||||
//left
|
||||
List<Vector3> left = new List<Vector3>();
|
||||
//right
|
||||
List<Vector3> right = new List<Vector3>();
|
||||
getPoints(from, angle2, rayDistance, ref left, ref right);
|
||||
List<Vector3> leftResult = null;
|
||||
List<Vector3> rightResult = null;
|
||||
//------------------------------------------------------------------
|
||||
int count = left.Count;
|
||||
Vector3 oldPos = Vector3.zero;
|
||||
bool isFirstLeft = true;
|
||||
bool isFirstRight = true;
|
||||
_Dir curTargetDir = getTargetDir(from, prefromPos);
|
||||
_Dir toPosTargetDir = getTargetDir(from, toPos);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (canLeftSearch && searchTime < maxSearchTimes)
|
||||
{
|
||||
if (canReach(from, left[i], 0) && !isInCircle(left[i], tmpVectorList1))
|
||||
{
|
||||
_Dir nextTargetDir = getTargetDir(left[i], from);
|
||||
|
||||
if ((curTargetDir == nextTargetDir)
|
||||
|| (curTargetDir == _Dir.up && (nextTargetDir == _Dir.left || nextTargetDir == _Dir.right))
|
||||
|| (curTargetDir == _Dir.bottom && (nextTargetDir == _Dir.left || nextTargetDir == _Dir.right))
|
||||
|| (curTargetDir == _Dir.left && (nextTargetDir == _Dir.up || nextTargetDir == _Dir.bottom))
|
||||
|| (curTargetDir == _Dir.right && (nextTargetDir == _Dir.up || nextTargetDir == _Dir.bottom))
|
||||
)
|
||||
{
|
||||
//Debug.Log("left:" + searchTime + "," + curTargetDir + "," + nextTargetDir);
|
||||
Vector3 tmpPos1 = left[i];//from;
|
||||
Vector3 tmpPos2 = toPos;
|
||||
if (isFirstLeft)
|
||||
{
|
||||
isFirstLeft = false;
|
||||
//oldPos = left[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpPos2 = left[i - 1];
|
||||
tmpPos1 = left[i];
|
||||
}
|
||||
_Dir _targetDir = getTargetDir(left[i], toPos);
|
||||
if (_targetDir == _Dir.left ||
|
||||
_targetDir == _Dir.right)
|
||||
{
|
||||
tmpPos1.z = 0;
|
||||
tmpPos2.z = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpPos1.x = 0;
|
||||
tmpPos2.x = 0;
|
||||
}
|
||||
|
||||
tmpPos1.y = 0;
|
||||
tmpPos2.y = 0;
|
||||
angle2 = Utl.getAngle(tmpPos1, tmpPos2);
|
||||
|
||||
|
||||
//加入到临时点列表中
|
||||
tmpVectorList1.Add(left[i]);
|
||||
//把新的起始点当作起始点重新寻路
|
||||
searchTime++;
|
||||
leftResult = searchPathByRay(from, left[i], toPos, angle2, ref searchTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (canRightSearch && searchTime < maxSearchTimes)
|
||||
{
|
||||
if (canReach(from, right[i], 0) && !isInCircle(right[i], tmpVectorList2))
|
||||
{
|
||||
_Dir nextTargetDir = getTargetDir(right[i], from);
|
||||
|
||||
if ((curTargetDir == nextTargetDir)
|
||||
|| (curTargetDir == _Dir.up && (nextTargetDir == _Dir.left || nextTargetDir == _Dir.right))
|
||||
|| (curTargetDir == _Dir.bottom && (nextTargetDir == _Dir.left || nextTargetDir == _Dir.right))
|
||||
|| (curTargetDir == _Dir.left && (nextTargetDir == _Dir.up || nextTargetDir == _Dir.bottom))
|
||||
|| (curTargetDir == _Dir.right && (nextTargetDir == _Dir.up || nextTargetDir == _Dir.bottom))
|
||||
)
|
||||
{
|
||||
//Debug.Log("right:" + searchTime + "," + curTargetDir + "," + nextTargetDir);
|
||||
Vector3 tmpPos1 = right[i];//from;
|
||||
Vector3 tmpPos2 = toPos;
|
||||
if (isFirstRight)
|
||||
{
|
||||
isFirstRight = false;
|
||||
oldPos = right[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpPos2 = oldPos;//right[i - 1];//;
|
||||
tmpPos1 = right[i];
|
||||
}
|
||||
_Dir _targetDir = getTargetDir(right[i], toPos);
|
||||
if (_targetDir == _Dir.left ||
|
||||
_targetDir == _Dir.right)
|
||||
{
|
||||
tmpPos1.z = 0;
|
||||
tmpPos2.z = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpPos1.x = 0;
|
||||
tmpPos2.x = 0;
|
||||
}
|
||||
|
||||
tmpPos1.y = 0;
|
||||
tmpPos2.y = 0;
|
||||
angle2 = Utl.getAngle(tmpPos1, tmpPos2);
|
||||
|
||||
|
||||
tmpVectorList2.Add(right[i]);
|
||||
searchTime++;
|
||||
rightResult = searchPathByRay(from, right[i], toPos, angle2, ref searchTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (leftResult != null && rightResult == null)
|
||||
{
|
||||
leftResult.Insert(0, left[i]);
|
||||
leftResult.Insert(0, from);
|
||||
vetorList = leftResult;
|
||||
break;
|
||||
}
|
||||
else if (leftResult == null && rightResult != null)
|
||||
{
|
||||
rightResult.Insert(0, right[i]);
|
||||
rightResult.Insert(0, from);
|
||||
vetorList = rightResult;
|
||||
break;
|
||||
}
|
||||
else if (leftResult != null && rightResult != null)
|
||||
{
|
||||
leftResult.Insert(0, left[i]);
|
||||
rightResult.Insert(0, right[i]);
|
||||
vetorList = getShortList(leftResult, rightResult);
|
||||
vetorList.Insert(0, from);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return vetorList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cans the reach.能否到达
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if reach was caned, <c>false</c> otherwise.</returns>
|
||||
/// <param name="from">From.</param>
|
||||
/// <param name="to">To.</param>
|
||||
public bool canReach(Vector3 from, Vector3 to, float endReachedDis)
|
||||
{
|
||||
Vector3 _to = to;
|
||||
_to.y = rayHeight;
|
||||
Vector3 dir = _to - from;
|
||||
float dis = Vector3.Distance(from, to) - endReachedDis;
|
||||
dis = dis < 0 ? 0 : dis;
|
||||
if (!Physics.Raycast(from, dir, dis, obstructMask))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the short list.取得最短路径
|
||||
/// </summary>
|
||||
/// <returns>The short list.</returns>
|
||||
/// <param name="list1">List1.</param>
|
||||
/// <param name="list2">List2.</param>
|
||||
public List<Vector3> getShortList(List<Vector3> list1, List<Vector3> list2)
|
||||
{
|
||||
int count = list1.Count;
|
||||
float dis1 = 0;
|
||||
float dis2 = 0;
|
||||
for (int i = 0; i < count - 1; i++)
|
||||
{
|
||||
dis1 += Vector3.Distance(list1[i], list1[i + 1]);
|
||||
}
|
||||
count = list2.Count;
|
||||
for (int i = 0; i < count - 1; i++)
|
||||
{
|
||||
dis2 += Vector3.Distance(list2[i], list2[i + 1]);
|
||||
}
|
||||
return dis1 > dis2 ? list2 : list1;
|
||||
}
|
||||
|
||||
public void filterPath(ref List<Vector3> list)
|
||||
{
|
||||
if (list == null || list.Count < 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Vector3 from = list[0];
|
||||
float dis = 0;
|
||||
int i = 2;
|
||||
while (i < list.Count)
|
||||
{
|
||||
dis = Vector3.Distance(from, list[i]);
|
||||
if (Physics.Raycast(from, list[i] - from, dis, obstructMask))
|
||||
{
|
||||
from = list[i - 1];
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
list.RemoveAt(i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//到目标点的方向
|
||||
public _Dir getTargetDir(Vector3 fromPos, Vector3 toPos)
|
||||
{
|
||||
Vector3 euAngle = Utl.getAngle(fromPos, toPos);
|
||||
float angle = euAngle.y;
|
||||
if (angle < 0)
|
||||
{
|
||||
angle = 360 + angle;
|
||||
}
|
||||
if ((angle >= 0 && angle <= 45) ||
|
||||
(angle >= 315 && angle <= 360))
|
||||
{
|
||||
return _Dir.up;
|
||||
}
|
||||
else if ((angle >= 45 && angle <= 135))
|
||||
{
|
||||
return _Dir.right;
|
||||
}
|
||||
else if ((angle >= 135 && angle <= 225))
|
||||
{
|
||||
return _Dir.bottom;
|
||||
}
|
||||
else if ((angle >= 225 && angle <= 315))
|
||||
{
|
||||
return _Dir.left;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("This angle not in switch case!!!! angle===" + angle);
|
||||
}
|
||||
return _Dir.up;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
float oldRayDis = 0;
|
||||
SearchDirs oldDirs = SearchDirs._8;
|
||||
float oldRayHeight = 0;
|
||||
Vector3 oldeulerAngles = Vector3.zero;
|
||||
Vector3 oldPosition = Vector3.zero;
|
||||
Matrix4x4 boundsMatrix;
|
||||
float nowTime = 0;
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawSphere(targetPos, 0.5f);
|
||||
Gizmos.color = Color.white;
|
||||
|
||||
if (!showPath) return;
|
||||
nowTime = Time.time;
|
||||
|
||||
// if(center == null) return;
|
||||
|
||||
// boundsMatrix.SetTRS (center.position, Quaternion.Euler (girdRotaion),new Vector3 (aspectRatio,1,1));
|
||||
// AstarPath.active.astarData.gridGraph.SetMatrix();
|
||||
// Gizmos.matrix = AstarPath.active.astarData.gridGraph.boundsMatrix;
|
||||
// Gizmos.matrix = boundsMatrix;
|
||||
Gizmos.color = Color.red;
|
||||
|
||||
//for (int i = 0; canLeftSearch && i < pointsDirLeft.Count; i++)
|
||||
//{
|
||||
// Gizmos.DrawWireCube(pointsDirLeft[i], Vector3.one * (0.04f + i * 0.005f));
|
||||
// Debug.DrawLine(originPosition, pointsDirLeft[i]);
|
||||
//}
|
||||
|
||||
//for (int i = 0; canRightSearch && i < pointsDirRight.Count; i++)
|
||||
//{
|
||||
// Gizmos.DrawWireCube(pointsDirRight[i], Vector3.one * (0.04f + i * 0.005f));
|
||||
// Debug.DrawLine(originPosition, pointsDirRight[i]);
|
||||
//}
|
||||
|
||||
List<Vector3> list = tmpVectorList1;// tmpVectorList1; //vectorList
|
||||
if (list != null && list.Count > 1)
|
||||
{
|
||||
int max = ((int)(nowTime - begainTime)) % list.Count;
|
||||
int i = 0;
|
||||
for (i = 0; i < list.Count - 1 && i <= max; i++)
|
||||
{
|
||||
Gizmos.DrawWireCube(list[i], Vector3.one * 0.06f);
|
||||
Debug.DrawLine(list[i], list[i + 1], Color.red);
|
||||
}
|
||||
Gizmos.DrawWireCube(list[i], Vector3.one * 0.06f);
|
||||
}
|
||||
|
||||
list = tmpVectorList2; //vectorList
|
||||
if (list != null && list.Count > 1)
|
||||
{
|
||||
int max = ((int)(nowTime - begainTime)) % list.Count;
|
||||
int i = 0;
|
||||
for (i = 0; i < list.Count - 1 && i <= max; i++)
|
||||
{
|
||||
Gizmos.DrawWireCube(list[i], Vector3.one * 0.06f);
|
||||
Debug.DrawLine(list[i], list[i + 1], Color.red);
|
||||
}
|
||||
Gizmos.DrawWireCube(list[i], Vector3.one * 0.06f);
|
||||
}
|
||||
|
||||
//List<object> list2 = tmpPointsList1; //vectorList
|
||||
//if (list2 != null && list2.Count > 1)
|
||||
//{
|
||||
// int max = ((int)(nowTime - begainTime)) % list2.Count;
|
||||
// int i = 0;
|
||||
// for (i = 0; i < list2.Count - 1 && i <= max; i++)
|
||||
// {
|
||||
// list = list2[i] as List<Vector3>;
|
||||
// for (int j = 0; canLeftSearch && j < list.Count; j++)
|
||||
// {
|
||||
// Gizmos.DrawWireCube(list[j], Vector3.one * (0.04f + j * 0.005f));
|
||||
// //Debug.DrawLine(originPosition, list[i]);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
list = pathList; //vectorList
|
||||
if (list != null && list.Count > 1)
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; i < list.Count - 1; i++)
|
||||
{
|
||||
// Gizmos.DrawWireCube(list[i], Vector3.one*0.04f);
|
||||
Debug.DrawLine(list[i], list[i + 1], Color.green);
|
||||
}
|
||||
Gizmos.DrawWireCube(list[i], Vector3.one * 0.04f);
|
||||
}
|
||||
// Gizmos.matrix = Matrix4x4.identity;
|
||||
|
||||
// Gizmos.matrix = Matrix4x4.identity;
|
||||
Gizmos.color = Color.white;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
11
Assets/CoolapeFrame/AIPath/Scripts/CLSeekerByRay.cs.meta
Normal file
11
Assets/CoolapeFrame/AIPath/Scripts/CLSeekerByRay.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e385878028fdd4116a91661dc28a0e9d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/CoolapeFrame/AIPath/Scripts/com.meta
Normal file
8
Assets/CoolapeFrame/AIPath/Scripts/com.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ceb713bbf74c445c28d18f452724585e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
104
Assets/CoolapeFrame/AIPath/Scripts/com/CLAIPathUtl.cs
Normal file
104
Assets/CoolapeFrame/AIPath/Scripts/com/CLAIPathUtl.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coolape
|
||||
{
|
||||
public static class CLAIPathUtl
|
||||
{
|
||||
/// <summary>
|
||||
/// Softens the path.软化路径
|
||||
/// </summary>
|
||||
/// <param name="list">List.路径列表</param>
|
||||
/// <param name="softenPathType">Soften path type.软化类型</param>
|
||||
/// <param name="slerpFactor">Soften factor.曲面差值次数</param>
|
||||
/// <param name="cellSize">Cell size.单元格大小</param>
|
||||
public static void softenPath(ref List<Vector3> list, SoftenPathType softenPathType, int slerpFactor, float cellSize)
|
||||
{
|
||||
if (list == null || list.Count < 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int i = 1;
|
||||
|
||||
float factor = 0.25f;
|
||||
float slerpOffset = 0;
|
||||
if (softenPathType == SoftenPathType.Slerp)
|
||||
{
|
||||
factor = 0.5f;
|
||||
slerpFactor = slerpFactor == 0 ? 1 : slerpFactor;
|
||||
slerpOffset = 1.0f / slerpFactor;
|
||||
}
|
||||
while (i < list.Count - 1)
|
||||
{
|
||||
Vector3 mid = list[i];
|
||||
Vector3 left = list[i - 1];
|
||||
Vector3 right = list[i + 1];
|
||||
|
||||
Vector3 angle1 = Utl.getAngle(mid, left);
|
||||
Vector3 angle2 = Utl.getAngle(mid, right);
|
||||
if (Mathf.Abs(Mathf.Abs(angle1.y - angle2.y) - 180) <= 20)
|
||||
{
|
||||
//基本在一条线上,直接跳过
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3 leftOffset = Vector3.zero;
|
||||
float leftDis = Vector3.Distance(mid, left);
|
||||
if (leftDis >= cellSize)
|
||||
{
|
||||
leftOffset = (left - mid).normalized * cellSize * factor;
|
||||
}
|
||||
else
|
||||
{
|
||||
leftOffset = (left - mid).normalized * leftDis * factor;
|
||||
}
|
||||
left = mid + leftOffset;
|
||||
|
||||
Vector3 rightOffset = Vector3.zero;
|
||||
float rightDis = Vector3.Distance(mid, right);
|
||||
if (rightDis >= cellSize)
|
||||
{
|
||||
rightOffset = (right - mid).normalized * cellSize * factor;
|
||||
}
|
||||
else
|
||||
{
|
||||
rightOffset = (right - mid).normalized * rightDis * factor;
|
||||
}
|
||||
right = mid + rightOffset;
|
||||
|
||||
Vector3 center = (left + right) / 2.0f;
|
||||
Vector3 mid2 = center + (center - mid).normalized * Vector3.Distance(center, mid) * 4f;
|
||||
|
||||
list.RemoveAt(i); //把硬转角的点去掉
|
||||
//接下来加入一些新的点
|
||||
list.Insert(i, left);
|
||||
i++;
|
||||
if (softenPathType == SoftenPathType.Slerp)
|
||||
{
|
||||
//加入球面插值的点
|
||||
Vector3 v1 = left - mid2;
|
||||
Vector3 v2 = right - mid2;
|
||||
for (int j = 0; j < slerpFactor; j++)
|
||||
{
|
||||
Vector3 pos = Vector3.Slerp(v1, v2, slerpOffset * j);
|
||||
list.Insert(i, (pos + mid2));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
list.Insert(i, right);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================
|
||||
//============================================
|
||||
//============================================
|
||||
public enum SoftenPathType
|
||||
{
|
||||
Line,
|
||||
Slerp
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/CoolapeFrame/AIPath/Scripts/com/CLAIPathUtl.cs.meta
Normal file
11
Assets/CoolapeFrame/AIPath/Scripts/com/CLAIPathUtl.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4d4492acf2c24246b54b1e8c52846fe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
96
Assets/CoolapeFrame/AIPath/Scripts/com/CLAStarNode.cs
Normal file
96
Assets/CoolapeFrame/AIPath/Scripts/com/CLAStarNode.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace Coolape
|
||||
{
|
||||
public class CLAStarNode
|
||||
{
|
||||
public CLAStarNode left;
|
||||
public CLAStarNode right;
|
||||
public CLAStarNode up;
|
||||
public CLAStarNode down;
|
||||
public CLAStarNode leftUp;
|
||||
public CLAStarNode leftDown;
|
||||
public CLAStarNode rightUp;
|
||||
public CLAStarNode rightDown;
|
||||
|
||||
public List<CLAStarNode> aroundList = new List<CLAStarNode>();
|
||||
public int index;
|
||||
public Vector3 position;
|
||||
// 是障碍格子
|
||||
public bool isObstruct = false;
|
||||
//父节点,需要一个key作缓存,以免同时有多个寻路时parent值会冲突
|
||||
Dictionary<string, CLAStarNode> parentNodesMap = new Dictionary<string, CLAStarNode>();
|
||||
|
||||
public CLAStarNode(int index, Vector3 pos)
|
||||
{
|
||||
this.index = index;
|
||||
this.position = pos;
|
||||
}
|
||||
|
||||
public void init(
|
||||
CLAStarNode left,
|
||||
CLAStarNode right,
|
||||
CLAStarNode up,
|
||||
CLAStarNode down,
|
||||
CLAStarNode leftUp,
|
||||
CLAStarNode leftDown,
|
||||
CLAStarNode rightUp,
|
||||
CLAStarNode rightDown)
|
||||
{
|
||||
aroundList.Clear();
|
||||
this.left = left;
|
||||
if(left != null) {
|
||||
aroundList.Add(left);
|
||||
}
|
||||
this.right = right;
|
||||
if (right != null)
|
||||
{
|
||||
aroundList.Add(right);
|
||||
}
|
||||
this.up = up;
|
||||
if (up != null)
|
||||
{
|
||||
aroundList.Add(up);
|
||||
}
|
||||
this.down = down;
|
||||
if (down != null)
|
||||
{
|
||||
aroundList.Add(down);
|
||||
}
|
||||
this.leftUp = leftUp;
|
||||
if (leftUp != null)
|
||||
{
|
||||
aroundList.Add(leftUp);
|
||||
}
|
||||
this.leftDown = leftDown;
|
||||
if (leftDown != null)
|
||||
{
|
||||
aroundList.Add(leftDown);
|
||||
}
|
||||
this.rightUp = rightUp;
|
||||
if (rightUp != null)
|
||||
{
|
||||
aroundList.Add(rightUp);
|
||||
}
|
||||
this.rightDown = rightDown;
|
||||
if (rightDown != null)
|
||||
{
|
||||
aroundList.Add(rightDown);
|
||||
}
|
||||
}
|
||||
|
||||
public void setParentNode(CLAStarNode preNode, string key)
|
||||
{
|
||||
parentNodesMap[key] = preNode;
|
||||
}
|
||||
public CLAStarNode getParentNode(string key)
|
||||
{
|
||||
CLAStarNode parent = null;
|
||||
if(parentNodesMap.TryGetValue(key, out parent)) {
|
||||
return parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/CoolapeFrame/AIPath/Scripts/com/CLAStarNode.cs.meta
Normal file
11
Assets/CoolapeFrame/AIPath/Scripts/com/CLAStarNode.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8085c87d606b547e29d32263db779eea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/CoolapeFrame/AIPath/Scripts/grid.meta
Normal file
9
Assets/CoolapeFrame/AIPath/Scripts/grid.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc43cd35cbe0a4d98854cbb83bbb79aa
|
||||
folderAsset: yes
|
||||
timeCreated: 1488938170
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
789
Assets/CoolapeFrame/AIPath/Scripts/grid/GridBase.cs
Normal file
789
Assets/CoolapeFrame/AIPath/Scripts/grid/GridBase.cs
Normal file
@@ -0,0 +1,789 @@
|
||||
#region Copyright
|
||||
// ******************************************************************************************
|
||||
//
|
||||
// SimplePath, Copyright © 2011, Alex Kring
|
||||
//
|
||||
// ******************************************************************************************
|
||||
#endregion
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Coolape
|
||||
{
|
||||
public class GridBase
|
||||
{
|
||||
#region Constants
|
||||
protected static readonly Vector3 kXAxis; // points in the directon of the positive X axis
|
||||
protected static readonly Vector3 kZAxis; // points in the direction of the positive Y axis
|
||||
private static readonly float kDepth; // used for intersection tests done in 3D.
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
protected int m_numberOfRows;
|
||||
protected int m_numberOfColumns;
|
||||
protected float m_cellSize;
|
||||
private Vector3 m_origin;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public float Width
|
||||
{
|
||||
get { return (m_numberOfColumns * m_cellSize); }
|
||||
}
|
||||
|
||||
public float Height
|
||||
{
|
||||
get { return (m_numberOfRows * m_cellSize); }
|
||||
}
|
||||
|
||||
public Vector3 Origin
|
||||
{
|
||||
get { return m_origin; }
|
||||
}
|
||||
|
||||
public int NumberOfCells
|
||||
{
|
||||
get { return m_numberOfRows * m_numberOfColumns; }
|
||||
}
|
||||
|
||||
public float Left
|
||||
{
|
||||
get { return Origin.x; }
|
||||
}
|
||||
|
||||
public float Right
|
||||
{
|
||||
get { return Origin.x + Width; }
|
||||
}
|
||||
|
||||
public float Top
|
||||
{
|
||||
get { return Origin.z + Height; }
|
||||
}
|
||||
|
||||
public float Bottom
|
||||
{
|
||||
get { return Origin.z; }
|
||||
}
|
||||
|
||||
public float CellSize
|
||||
{
|
||||
get { return m_cellSize; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
static GridBase()
|
||||
{
|
||||
kXAxis = new Vector3(1.0f, 0.0f, 0.0f);
|
||||
kZAxis = new Vector3(0.0f, 0.0f, 1.0f);
|
||||
kDepth = 1.0f;
|
||||
}
|
||||
|
||||
// Use this for initialization
|
||||
public void init(Vector3 origin, int numRows, int numCols, float cellSize)
|
||||
{
|
||||
m_origin = origin;
|
||||
m_numberOfRows = numRows;
|
||||
m_numberOfColumns = numCols;
|
||||
m_cellSize = cellSize;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
// public virtual void Update ()
|
||||
// {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public virtual void OnDrawGizmos()
|
||||
// {
|
||||
//
|
||||
// }
|
||||
|
||||
public static void DebugDraw(Vector3 origin, int numRows, int numCols, float cellSize, Color color)
|
||||
{
|
||||
float width = (numCols * cellSize);
|
||||
float height = (numRows * cellSize);
|
||||
|
||||
// Draw the horizontal grid lines
|
||||
for (int i = 0; i < numRows + 1; i++)
|
||||
{
|
||||
Vector3 startPos = origin + i * cellSize * kZAxis;
|
||||
Vector3 endPos = startPos + width * kXAxis;
|
||||
Debug.DrawLine(startPos, endPos, color);
|
||||
}
|
||||
|
||||
// Draw the vertial grid lines
|
||||
for (int i = 0; i < numCols + 1; i++)
|
||||
{
|
||||
Vector3 startPos = origin + i * cellSize * kXAxis;
|
||||
Vector3 endPos = startPos + height * kZAxis;
|
||||
Debug.DrawLine(startPos, endPos, color);
|
||||
}
|
||||
}
|
||||
|
||||
// pos is in world space coordinates. The returned position is also in world space coordinates.
|
||||
public Vector3 GetNearestCellCenter(Vector3 pos)
|
||||
{
|
||||
int index = GetCellIndex(pos);
|
||||
Vector3 cellPos = GetCellPosition(index);
|
||||
cellPos.x += (m_cellSize / 2.0f);
|
||||
cellPos.z += (m_cellSize / 2.0f);
|
||||
return cellPos;
|
||||
}
|
||||
|
||||
// returns a position in world space coordinates.
|
||||
public Vector3 GetCellCenter(int index)
|
||||
{
|
||||
Vector3 cellPosition = GetCellPosition(index);
|
||||
cellPosition.x += (m_cellSize / 2.0f);
|
||||
cellPosition.z += (m_cellSize / 2.0f);
|
||||
return cellPosition;
|
||||
}
|
||||
public Vector3 GetCellCenter(int col, int row)
|
||||
{
|
||||
return GetCellCenter(GetCellIndex(col, row));
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the lower left position of the grid cell at the passed tile index. The origin of the grid is at the lower left,
|
||||
/// so it uses a cartesian coordinate system.
|
||||
/// </summary>
|
||||
/// <param name="index">index to the grid cell to consider</param>
|
||||
/// <returns>Lower left position of the grid cell (origin position of the grid cell), in world space coordinates</returns>
|
||||
public Vector3 GetCellPosition(int index)
|
||||
{
|
||||
int row = GetRow(index);
|
||||
int col = GetColumn(index);
|
||||
float x = col * m_cellSize;
|
||||
float z = row * m_cellSize;
|
||||
Vector3 cellPosition = Origin + new Vector3(x, 0.0f, z);
|
||||
return cellPosition;
|
||||
}
|
||||
|
||||
// pass in world space coords. Get the tile index at the passed position
|
||||
public int GetCellIndex(Vector3 pos)
|
||||
{
|
||||
if (!IsInBounds(pos))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos -= Origin;
|
||||
|
||||
return GetCellIndex((int)(pos.x / m_cellSize), (int)(pos.z / m_cellSize));
|
||||
}
|
||||
|
||||
public int GetCellIndex(int col, int row)
|
||||
{
|
||||
return (row * m_numberOfColumns + col);
|
||||
}
|
||||
|
||||
// pass in world space coords. Get the tile index at the passed position, clamped to be within the grid.
|
||||
public int GetCellIndexClamped(Vector3 pos)
|
||||
{
|
||||
pos -= Origin;
|
||||
|
||||
int col = (int)(pos.x / m_cellSize);
|
||||
int row = (int)(pos.z / m_cellSize);
|
||||
|
||||
//make sure the position is in range.
|
||||
col = (int)Mathf.Clamp(col, 0, m_numberOfColumns - 1);
|
||||
row = (int)Mathf.Clamp(row, 0, m_numberOfRows - 1);
|
||||
|
||||
return (row * m_numberOfColumns + col);
|
||||
}
|
||||
|
||||
public Bounds GetCellBounds(int index)
|
||||
{
|
||||
Vector3 cellCenterPos = GetCellPosition(index);
|
||||
cellCenterPos.x += (m_cellSize / 2.0f);
|
||||
cellCenterPos.z += (m_cellSize / 2.0f);
|
||||
Bounds cellBounds = new Bounds(cellCenterPos, new Vector3(m_cellSize, kDepth, m_cellSize));
|
||||
return cellBounds;
|
||||
}
|
||||
|
||||
public Bounds GetGridBounds()
|
||||
{
|
||||
Vector3 gridCenter = Origin + (Width / 2.0f) * kXAxis + (Height / 2.0f) * kZAxis;
|
||||
Bounds gridBounds = new Bounds(gridCenter, new Vector3(Width, kDepth, Height));
|
||||
return gridBounds;
|
||||
}
|
||||
|
||||
public int GetRow(int index)
|
||||
{
|
||||
int row = index / m_numberOfColumns; //m_numberOfRows;
|
||||
return row;
|
||||
}
|
||||
|
||||
public int GetColumn(int index)
|
||||
{
|
||||
int col = index % m_numberOfColumns;
|
||||
return col;
|
||||
}
|
||||
public int GetX(int index)
|
||||
{
|
||||
return GetColumn(index);
|
||||
}
|
||||
|
||||
public int GetY(int index)
|
||||
{
|
||||
return GetRow(index);
|
||||
}
|
||||
|
||||
|
||||
public bool IsInBounds(int col, int row)
|
||||
{
|
||||
if (col < 0 || col >= m_numberOfColumns)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (row < 0 || row >= m_numberOfRows)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsInBounds(int index)
|
||||
{
|
||||
return (index >= 0 && index < NumberOfCells);
|
||||
}
|
||||
|
||||
// pass in world space coords
|
||||
public bool IsInBounds(Vector3 pos)
|
||||
{
|
||||
return (pos.x >= Left &&
|
||||
pos.x <= Right &&
|
||||
pos.z <= Top &&
|
||||
pos.z >= Bottom);
|
||||
}
|
||||
|
||||
|
||||
public int LeftIndex(int index)
|
||||
{
|
||||
int col = GetColumn(index);
|
||||
int row = GetRow(index);
|
||||
col = col - 1;
|
||||
if (IsInBounds(col, row))
|
||||
{
|
||||
return GetCellIndex(col, row);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int RightIndex(int index)
|
||||
{
|
||||
int col = GetColumn(index);
|
||||
int row = GetRow(index);
|
||||
col = col + 1;
|
||||
if (IsInBounds(col, row))
|
||||
{
|
||||
return GetCellIndex(col, row);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
public int UpIndex(int index)
|
||||
{
|
||||
int col = GetColumn(index);
|
||||
int row = GetRow(index);
|
||||
row = row + 1;
|
||||
if (IsInBounds(col, row))
|
||||
{
|
||||
return GetCellIndex(col, row);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int DownIndex(int index)
|
||||
{
|
||||
int col = GetColumn(index);
|
||||
int row = GetRow(index);
|
||||
row = row - 1;
|
||||
if (IsInBounds(col, row))
|
||||
{
|
||||
return GetCellIndex(col, row);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int LeftUpIndex(int index)
|
||||
{
|
||||
int col = GetColumn(index);
|
||||
int row = GetRow(index);
|
||||
col = col - 1;
|
||||
row = row + 1;
|
||||
if (IsInBounds(col, row))
|
||||
{
|
||||
return GetCellIndex(col, row);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int RightUpIndex(int index)
|
||||
{
|
||||
int col = GetColumn(index);
|
||||
int row = GetRow(index);
|
||||
col = col + 1;
|
||||
row = row + 1;
|
||||
if (IsInBounds(col, row))
|
||||
{
|
||||
return GetCellIndex(col, row);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int LeftDownIndex(int index)
|
||||
{
|
||||
int col = GetColumn(index);
|
||||
int row = GetRow(index);
|
||||
col = col - 1;
|
||||
row = row - 1;
|
||||
if (IsInBounds(col, row))
|
||||
{
|
||||
return GetCellIndex(col, row);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int RightDownIndex(int index)
|
||||
{
|
||||
int col = GetColumn(index);
|
||||
int row = GetRow(index);
|
||||
col = col + 1;
|
||||
row = row - 1;
|
||||
if (IsInBounds(col, row))
|
||||
{
|
||||
return GetCellIndex(col, row);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the circular cells.取得周围的cell的index
|
||||
/// </summary>
|
||||
/// <returns>The circular cells.</returns>
|
||||
/// <param name="centerPos">中心点 postion.</param>
|
||||
/// <param name="r">半径.</param>
|
||||
public List<int> getCircleCells(Vector3 centerPos, int r)
|
||||
{
|
||||
Dictionary<int, bool> map = new Dictionary<int, bool>();
|
||||
float l = Mathf.PI * 2 * r;
|
||||
int n = Mathf.CeilToInt(l / CellSize);
|
||||
float angel = 360.0f / n;
|
||||
Vector3 pos = Vector3.zero;
|
||||
int _index = 0;
|
||||
for (int i=0; i < n; i++) {
|
||||
pos = AngleEx.getCirclePointV3(centerPos, r, i * angel);
|
||||
_index = GetCellIndex(pos);
|
||||
if(_index >= 0 && !map.ContainsKey(_index))
|
||||
{
|
||||
map[_index] = true;
|
||||
}
|
||||
}
|
||||
List<int> ret = new List<int>();
|
||||
ret.AddRange(map.Keys);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the circular cells.取得周围的cell的index
|
||||
/// </summary>
|
||||
/// <returns>The circular cells.</returns>
|
||||
/// <param name="center">中心点index.</param>
|
||||
/// <param name="size">Size * Size的范围.</param>
|
||||
public List<int> getAroundCells(int center, int size)
|
||||
{
|
||||
List<int> ret = new List<int>();
|
||||
if (center < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
int half = size / 2;
|
||||
int numRows = m_numberOfColumns;// m_numberOfRows;
|
||||
if (size % 2 == 0)
|
||||
{
|
||||
int row = half;
|
||||
for (int i = 0; i < half; i++)
|
||||
{
|
||||
int tpindex = center - row * numRows - i;
|
||||
if (tpindex / numRows != (center - row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
|
||||
tpindex = center - i * numRows + half - 1;
|
||||
if (tpindex / numRows != (center - i * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
for (int i = 1; i < half; i++)
|
||||
{
|
||||
int tpindex = center - row * numRows + i;
|
||||
if (tpindex / numRows != (center - row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
|
||||
tpindex = center + i * numRows + half - 1;
|
||||
if (tpindex / numRows != (center + i * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
|
||||
row = half - 1;
|
||||
for (int i = 1; i <= half; i++)
|
||||
{
|
||||
int tpindex = center + row * numRows - i;
|
||||
if (tpindex / numRows != (center + row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
|
||||
tpindex = center - i * numRows - half;
|
||||
if (tpindex / numRows != (center - i * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < half - 1; i++)
|
||||
{
|
||||
int tpindex = center + row * numRows + i;
|
||||
if (tpindex / numRows != (center + row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
|
||||
tpindex = center + i * numRows - half;
|
||||
if (tpindex / numRows != (center + i * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int row = half;
|
||||
for (int i = 0; i < half; i++)
|
||||
{
|
||||
int tpindex = center - row * numRows - i;
|
||||
if (tpindex / numRows != (center - row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
|
||||
tpindex = center - i * numRows + half;
|
||||
if (tpindex / numRows != (center - i * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
for (int i = 1; i <= half; i++)
|
||||
{
|
||||
int tpindex = center - row * numRows + i;
|
||||
if (tpindex / numRows != (center - row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
|
||||
tpindex = center + i * numRows + half;
|
||||
if (tpindex / numRows != (center + i * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i <= half; i++)
|
||||
{
|
||||
int tpindex = center + row * numRows - i;
|
||||
if (tpindex / numRows != (center + row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
|
||||
tpindex = center - i * numRows - half;
|
||||
if (tpindex / numRows != (center - i * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < half; i++)
|
||||
{
|
||||
int tpindex = center + row * numRows + i;
|
||||
if (tpindex / numRows != (center + row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
|
||||
tpindex = center + i * numRows - half;
|
||||
if (tpindex / numRows != (center + i * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the own grids.根据中心点及占用格子size,取得占用格子index数,注意只有在长宽一样的情况时
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The own grids.
|
||||
/// </returns>
|
||||
/// <param name='center'>
|
||||
/// Center. 中心点index
|
||||
/// </param>
|
||||
/// <param name='size'>
|
||||
/// Size. Size * Size的范围
|
||||
/// </param>
|
||||
public List<int> getCells(int center, int size)
|
||||
{
|
||||
List<int> ret = new List<int>();
|
||||
if (center < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
int half = size / 2;
|
||||
int numRows = m_numberOfColumns;// m_numberOfRows;
|
||||
if (size % 2 == 0)
|
||||
{
|
||||
for (int row = 0; row <= half; row++)
|
||||
{
|
||||
for (int i = 1; i <= half; i++)
|
||||
{
|
||||
int tpindex = center - row * numRows - i;
|
||||
if (tpindex / numRows != (center - row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < half; i++)
|
||||
{
|
||||
int tpindex = center - row * numRows + i;
|
||||
if (tpindex / numRows != (center - row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int row = 1; row <= half - 1; row++)
|
||||
{
|
||||
for (int i = 1; i <= half; i++)
|
||||
{
|
||||
int tpindex = center + row * numRows - i;
|
||||
if (tpindex / numRows != (center + row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < half; i++)
|
||||
{
|
||||
int tpindex = center + row * numRows + i;
|
||||
if (tpindex / numRows != (center + row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int row = 0; row <= half; row++)
|
||||
{
|
||||
for (int i = 0; i <= half; i++)
|
||||
{
|
||||
int tpindex = center - row * numRows - i;
|
||||
if (tpindex / numRows != (center - row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i <= half; i++)
|
||||
{
|
||||
int tpindex = center - row * numRows + i;
|
||||
if (tpindex / numRows != (center - row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int row = 1; row <= half; row++)
|
||||
{
|
||||
for (int i = 0; i <= half; i++)
|
||||
{
|
||||
int tpindex = center + row * numRows - i;
|
||||
if (tpindex / numRows != (center + row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i <= half; i++)
|
||||
{
|
||||
int tpindex = center + row * numRows + i;
|
||||
if (tpindex / numRows != (center + row * numRows) / numRows)
|
||||
{
|
||||
tpindex = -1;
|
||||
}
|
||||
|
||||
if (IsInBounds(tpindex))
|
||||
{
|
||||
ret.Add(tpindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/CoolapeFrame/AIPath/Scripts/grid/GridBase.cs.meta
Normal file
11
Assets/CoolapeFrame/AIPath/Scripts/grid/GridBase.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9f0ba7d64f69429c9e16487b3fd35c8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user