using XericLibrary.Runtime.MacroLibrary; using XericLibrary.Runtime.Type; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Runtime.CompilerServices; using UnityEngine; using UnityEngine.UIElements; namespace XericLibrary.Runtime.MacroLibrary { public class NeighborGrid : WeaklyObject, IEnumerable>> { #region 字段属性 private Vector3 position; private Vector3 cellSize; private Vector3Int numCells; private int maxNeighbor = 8; public Vector3 Position { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => position; } public Vector3 CellSize { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => cellSize; } public Vector3Int NumCells { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => numCells; } internal System.Random random = new System.Random(); private int NeighborRandomIndex { get => random.Next(maxNeighbor); } /// /// 网格系统存储地 /// private Dictionary> grid = new Dictionary>(); /// /// 网格的总尺寸 /// public Vector3 Fullsize { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => cellSize.Mul(numCells); } /// /// 此网格系统转为盒体范围 /// public Bounds GridBounds { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Bounds(position, Fullsize / 2); [MethodImpl(MethodImplOptions.AggressiveInlining)] set { position = value.center; cellSize = (value.size * 2).Div(numCells); } } #endregion #region 构造 /// /// 临近网格 /// /// 网格原点坐标 /// 网格晶格尺寸 /// 网格总尺寸 /// 单个晶格内最大邻居数量 public NeighborGrid(Vector3 position, Vector3 cellSize, Vector3 fullSize, int maxNeighbor = 8) { this.position = position; this.cellSize = cellSize; this.numCells = fullSize.Div(cellSize).FloorToInt().Max(Vector3Int.one); this.maxNeighbor = maxNeighbor; Debug.Log($"原点:{position}, 晶格尺寸{cellSize}, 数量:{numCells}"); } #endregion #region 类内类 /// /// 网格索引 /// public struct NeighborGridIndex { #region 字段属性 private NeighborGrid grid; private NeighborGridSpace drivenSpace; private object drivenIndex; #endregion #region 构造 public NeighborGridIndex(NeighborGrid grid) { this.grid = grid; drivenSpace = (NeighborGridSpace)(-1); drivenIndex = null; } #endregion #region 方法 /// /// 获取为 世界空间 /// /// public Vector3 GetDrivenAsWorld() { DrivenTransformTo(NeighborGridSpace.World); return (Vector3)drivenIndex; } /// /// 获取为 网格系统本地坐标空间 /// /// public Vector3 GetDrivenAsSimulation() { DrivenTransformTo(NeighborGridSpace.Simulation); return (Vector3)drivenIndex; } /// /// 获取为 网格系统本地单位空间 /// /// public Vector3 GetDrivenAsUnit() { DrivenTransformTo(NeighborGridSpace.Unit); return (Vector3)drivenIndex; } /// /// 获取为 三维索引 /// /// public Vector3Int GetDrivenAsIndex() { DrivenTransformTo(NeighborGridSpace.Index); return (Vector3Int)drivenIndex; } /// /// 获取为 线性索引 /// /// public int GetDrivenAsLinear() { DrivenTransformTo(NeighborGridSpace.Linear); return (int)drivenIndex; } /// /// 设置为 世界空间 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public NeighborGridIndex SetDrivenAsWorld(Vector3 world) { drivenIndex = world; drivenSpace = NeighborGridSpace.World; return this; } /// /// 设置为 网格系统本地坐标空间 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public NeighborGridIndex SetDrivenAsSimulation(Vector3 simulation) { drivenIndex = simulation; drivenSpace = NeighborGridSpace.Simulation; return this; } /// /// 设置为 网格系统本地单位空间 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public NeighborGridIndex SetDrivenAsUnit(Vector3 unit) { drivenIndex = unit; drivenSpace = NeighborGridSpace.Unit; return this; } /// /// 设置为 三维索引 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public NeighborGridIndex SetDrivenAsIndex(Vector3Int index) { drivenIndex = index; drivenSpace = NeighborGridSpace.Index; return this; } /// /// 设置为 线性索引 /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public NeighborGridIndex SetDrivenAsLinear(int linear) { drivenIndex = linear; drivenSpace = NeighborGridSpace.Linear; return this; } /// /// 转换当前索引到目标空间 /// /// public NeighborGridIndex DrivenTransformTo(NeighborGridSpace targetSpace) { switch(targetSpace) { case NeighborGridSpace.World: TransformToWorld(); break; case NeighborGridSpace.Simulation: TransformToSimulation(); break; case NeighborGridSpace.Unit: TransformToUnit(); break; case NeighborGridSpace.Index: TransformToIndex(); break; case NeighborGridSpace.Linear: TransformToLiear(); break; default: throw new System.Exception("转换空间是无效的"); } return this; } /// /// 将当前的目标转换到世界空间 /// private void TransformToWorld() { switch(drivenSpace) { case NeighborGridSpace.World: drivenSpace = NeighborGridSpace.World; break; case NeighborGridSpace.Simulation: drivenIndex = grid.SimulationToWorld((Vector3)drivenIndex); goto case NeighborGridSpace.World; case NeighborGridSpace.Unit: drivenIndex = grid.UnitToSimulation((Vector3)drivenIndex); goto case NeighborGridSpace.Simulation; case NeighborGridSpace.Index: drivenIndex = grid.IndexToUnit((Vector3Int)drivenIndex); goto case NeighborGridSpace.Unit; case NeighborGridSpace.Linear: drivenIndex = grid.LinearToIndex((int)drivenIndex); goto case NeighborGridSpace.Index; default: throw new System.Exception("转换空间是无效的"); } } /// /// 将当前的目标转换到本地空间 /// private void TransformToSimulation() { switch(drivenSpace) { case NeighborGridSpace.World: drivenIndex = grid.WorldToSimulation((Vector3)drivenIndex); goto case NeighborGridSpace.Simulation; case NeighborGridSpace.Simulation: drivenSpace = NeighborGridSpace.Simulation; break; case NeighborGridSpace.Unit: drivenIndex = grid.UnitToSimulation((Vector3)drivenIndex); goto case NeighborGridSpace.Simulation; case NeighborGridSpace.Index: drivenIndex = grid.IndexToUnit((Vector3Int)drivenIndex); goto case NeighborGridSpace.Unit; case NeighborGridSpace.Linear: drivenIndex = grid.LinearToIndex((int)drivenIndex); goto case NeighborGridSpace.Index; default: throw new System.Exception("转换空间是无效的"); } } /// /// 将当前的目标转换到单位空间 /// private void TransformToUnit() { switch(drivenSpace) { case NeighborGridSpace.World: drivenIndex = grid.WorldToSimulation((Vector3)drivenIndex); goto case NeighborGridSpace.Simulation; case NeighborGridSpace.Simulation: drivenIndex = grid.SimulationToUnit((Vector3)drivenIndex); goto case NeighborGridSpace.Unit; case NeighborGridSpace.Unit: drivenSpace = NeighborGridSpace.Unit; break; case NeighborGridSpace.Index: drivenIndex = grid.IndexToUnit((Vector3Int)drivenIndex); goto case NeighborGridSpace.Unit; case NeighborGridSpace.Linear: drivenIndex = grid.LinearToIndex((int)drivenIndex); goto case NeighborGridSpace.Index; default: throw new System.Exception("转换空间是无效的"); } } /// /// 将当前的目标转换到三维索引 /// private void TransformToIndex() { switch(drivenSpace) { case NeighborGridSpace.World: drivenIndex = grid.WorldToSimulation((Vector3)drivenIndex); goto case NeighborGridSpace.Simulation; case NeighborGridSpace.Simulation: drivenIndex = grid.SimulationToUnit((Vector3)drivenIndex); goto case NeighborGridSpace.Unit; case NeighborGridSpace.Unit: drivenIndex = grid.UnitToIndex((Vector3)drivenIndex); goto case NeighborGridSpace.Index; case NeighborGridSpace.Index: drivenSpace = NeighborGridSpace.Index; break; case NeighborGridSpace.Linear: drivenIndex = grid.LinearToIndex((int)drivenIndex); goto case NeighborGridSpace.Index; default: throw new System.Exception("转换空间是无效的"); } } /// /// 将当前的目标转换到线性索引 /// private void TransformToLiear() { switch(drivenSpace) { case NeighborGridSpace.World: drivenIndex = grid.WorldToSimulation((Vector3)drivenIndex); goto case NeighborGridSpace.Simulation; case NeighborGridSpace.Simulation: drivenIndex = grid.SimulationToUnit((Vector3)drivenIndex); goto case NeighborGridSpace.Unit; case NeighborGridSpace.Unit: drivenIndex = grid.UnitToIndex((Vector3)drivenIndex); goto case NeighborGridSpace.Index; case NeighborGridSpace.Index: drivenIndex = grid.IndexToLinear((Vector3Int)drivenIndex); break; case NeighborGridSpace.Linear: drivenSpace = NeighborGridSpace.Linear; break; default: throw new System.Exception("转换空间是无效的"); } } #endregion } /// /// 临近网络空间枚举 /// public enum NeighborGridSpace { World, Simulation, Unit, Index, Linear } #endregion #region 索引变换 /// /// 世界空间 变换为 网格系统本地坐标空间 /// /// 项目的世界空间坐标 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 WorldToSimulation(Vector3 world) => world - position - (-Fullsize / 2); /// /// 网格系统本地坐标空间 变换为 世界空间 /// /// 项目的世界空间坐标 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 SimulationToWorld(Vector3 simulation) => simulation + position + (-Fullsize / 2); /// /// 网格系统本地坐标空间 变换为 网格系统本地单位空间 /// /// 网格系统本地坐标空间 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 SimulationToUnit(Vector3 simulation) => simulation.Div(Fullsize); /// /// 网格系统本地坐标空间 变换为 网格系统本地单位空间 /// /// 网格系统本地坐标空间 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 UnitToSimulation(Vector3 unit) => unit.Mul(Fullsize); /// /// 网格系统本地单位空间 变换为 三维索引 /// /// 网格系统本地单位空间 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3Int UnitToIndex(Vector3 unit) => unit.IsInUnit() ? unit.Mul(numCells).FloorToInt() : MacroMath.Vector3Int_Negate; /// /// 三维索引 变换为 网格系统本地单位空间 /// /// 三维索引 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 IndexToUnit(Vector3Int index) { if(index.IsValid()) { Vector3 unit = ((Vector3)index).Div(numCells); unit.x = numCells.x == 1 && unit.x <= 0 ? .5f : unit.x; unit.y = numCells.y == 1 && unit.y <= 0 ? .5f : unit.y; unit.z = numCells.z == 1 && unit.z <= 0 ? .5f : unit.z; return unit; } return MacroMath.Vector3Int_Negate; } /// /// 网格系统本地单位空间 变换为 线性索引 /// /// 网格系统本地坐标空间 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public int UnitToLinear(Vector3 unit) { if(unit.IsInUnit()) { return IndexToLinear(UnitToIndex(unit)); } return -1; } /// /// 三维索引 变换为 线性索引 /// /// 三维索引 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public int IndexToLinear(Vector3Int index) { if(index.IsValid() && index.IsInIndexRange(numCells)) { return (int)(index.x + (index.y * numCells.x) + (index.z * numCells.y * numCells.x)); } return -1; } /// /// 根据线性索引获取网格中索引偏移量 /// /// 线性索引 /// 边长 /// public Vector3Int LinearToGridIndex(int linear, int side) { return new Vector3Int(linear % side, linear / side, linear / side.Quad()); } /// /// 线性索引 变换为 三维索引 /// /// 线性索引 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3Int LinearToIndex(int linear) { int z = linear / (numCells.x * numCells.y); int y = (linear - (z * numCells.x * numCells.y)) / numCells.x; int x = linear - (z * numCells.x * numCells.y) - (y * numCells.x); return new Vector3Int(x, y, z); } /// /// 线性索引 变换为 网格系统本地单位空间 /// /// 线性索引 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 LinearToUnit(int linear) { Debug.Log($"线性转索引空间{LinearToIndex(linear)},再转单位"); return IndexToUnit(LinearToIndex(linear)); } #endregion #region 增删查 /// /// 清空网格 /// public void Clean() { grid.Clear(); } /// /// 在给定索引处添加一个项目 /// /// 索引 /// 返回是否添加成功 [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Insert(int linear, T obj) { if(linear < 0) return false; if(grid.ContainsKey(linear)) { int index = grid[linear].IndexOf(obj); if(index < 0) { grid[linear].Add(obj); return true; } return false; } else { grid.Add(linear, new List { obj }); return true; } } /// /// 移除给定索引处的项目 /// /// 索引 /// 项目 /// 返回是否移除成功 [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Remove(int linear, T obj) { if(grid.ContainsKey(linear)) { bool resualt = grid[linear].Remove(obj); if(grid[linear].Count <= 0) grid.Remove(linear); return resualt; } return false; } /// /// 移除给定索引下所有项目 /// /// 索引 /// 返回是否移除成功 [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Remove(int linear) { if(grid[linear] is not null) { grid[linear].Clear(); } } /// /// 查询给定索引处是否存在项目 /// /// 索引 /// 项目 /// 返回项目是否存在 [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Contains(int linear, T obj) { if(grid[linear] is not null) { return grid[linear].Contains(obj); } return false; } /// /// 忽略限制获取所有的邻居 /// /// 警告:潜在的高性能开销 /// /// /// /// public bool GetAllNeighbor(int linear, out List values) { return grid.TryGetValue(linear, out values); } /// /// 获取允许范围内的邻居 /// /// 所在位置的索引 /// public IEnumerable GetNeighbor(int linear) { int startIndex = NeighborRandomIndex; int count = grid[linear].Count; for(int i = 0; i < maxNeighbor; i++) { yield return grid[linear][(startIndex + i) % count]; } } /// /// 获取半径内所有允许的邻居 /// /// 所在位置的索引 /// 检查的范围 /// public IEnumerable GetNeighbor(int linear, int radius) { int side = radius * 2 + 1; int length = side.Cubic(); Vector3Int index = LinearToIndex(linear); index = index.Sub(radius); for(int i = 0; i < length; i++) { var neighbor = GetNeighbor(IndexToLinear(index + LinearToGridIndex(i, side))) .GetEnumerator(); while(neighbor.MoveNext()) { yield return neighbor.Current; } } } #endregion #region 实现 public IEnumerator>> GetEnumerator() { foreach(var list in grid) { yield return list; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion } }