This commit is contained in:
2020-07-04 14:41:25 +08:00
parent 70c346d2c1
commit a8f02e4da5
3748 changed files with 587372 additions and 0 deletions

View 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.新加入nodelist的最后一位是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());
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7f586ea662f494e128cefbccf74c0bbc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 26e01a5dc8c554427b335736a19173a2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e385878028fdd4116a91661dc28a0e9d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ceb713bbf74c445c28d18f452724585e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d4d4492acf2c24246b54b1e8c52846fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8085c87d606b547e29d32263db779eea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: bc43cd35cbe0a4d98854cbb83bbb79aa
folderAsset: yes
timeCreated: 1488938170
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a9f0ba7d64f69429c9e16487b3fd35c8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: