#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)); } /// /// 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. /// /// index to the grid cell to consider /// Lower left position of the grid cell (origin position of the grid cell), in world space coordinates 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; } } /// /// Gets the circular cells.取得周围的cell的index /// /// The circular cells. /// 中心点 postion. /// 半径. public List getCircleCells(Vector3 centerPos, int r) { Dictionary map = new Dictionary(); 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 ret = new List(); ret.AddRange(map.Keys); return ret; } /// /// Gets the circular cells.取得周围的cell的index /// /// The circular cells. /// 中心点index. /// Size * Size的范围. public List getAroundCells(int center, int size) { List ret = new List(); 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; } /// /// Gets the own grids.根据中心点及占用格子size,取得占用格子index数,注意只有在长宽一样的情况时 /// /// /// The own grids. /// /// /// Center. 中心点index /// /// /// Size. Size * Size的范围 /// public List getCells(int center, int size) { List ret = new List(); 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; } } }