Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / InfiniteGrid.cs
@小李xl 小李xl on 17 Feb 2024 6 KB 2格高墙壁, 开发中
  1.  
  2. using System.Collections.Generic;
  3. using Godot;
  4.  
  5. /// <summary>
  6. /// 无限大的网格数据结构, 通过 x 和 y 存储数据
  7. /// </summary>
  8. public class InfiniteGrid<T>
  9. {
  10. /// <summary>
  11. /// 遍历网格数据回调
  12. /// </summary>
  13. public delegate bool EachGridCallback(int x, int y, T data);
  14.  
  15. private bool _isDirty = false;
  16. private Rect2I _rect = new Rect2I();
  17. private readonly Dictionary<int, Dictionary<int, T>> _map = new Dictionary<int, Dictionary<int, T>>();
  18.  
  19. /// <summary>
  20. /// 返回指定xy位置是否存在数据
  21. /// </summary>
  22. public bool Contains(int x, int y)
  23. {
  24. if (_map.TryGetValue(x, out var value))
  25. {
  26. return value.ContainsKey(y);
  27. }
  28.  
  29. return false;
  30. }
  31. /// <summary>
  32. /// 返回指定xy位置是否有数据
  33. /// </summary>
  34. public bool Contains(Vector2I pos)
  35. {
  36. return Contains(pos.X, pos.Y);
  37. }
  38.  
  39. /// <summary>
  40. /// 设置指定xy位置的数据
  41. /// </summary>
  42. public void Set(int x, int y, T data)
  43. {
  44. if (_map.TryGetValue(x, out var value))
  45. {
  46. value[y] = data;
  47. }
  48. else
  49. {
  50. value = new Dictionary<int, T>();
  51. value.Add(y, data);
  52. _map.Add(x, value);
  53. _isDirty = true;
  54. }
  55. }
  56.  
  57. /// <summary>
  58. /// 设置指定坐标的数据
  59. /// </summary>
  60. public void Set(Vector2I pos, T data)
  61. {
  62. Set(pos.X, pos.Y, data);
  63. }
  64.  
  65. /// <summary>
  66. /// 获取指定xy位置的数据
  67. /// </summary>
  68. public T Get(int x, int y)
  69. {
  70. if (_map.TryGetValue(x, out var value))
  71. {
  72. if (value.TryGetValue(y, out var v))
  73. {
  74. return v;
  75. }
  76. }
  77.  
  78. return default;
  79. }
  80.  
  81. /// <summary>
  82. /// 获取指定坐标的数据
  83. /// </summary>
  84. public T Get(Vector2I pos)
  85. {
  86. return Get(pos.X, pos.Y);
  87. }
  88.  
  89. /// <summary>
  90. /// 移除指定xy位置存储的数据
  91. /// </summary>
  92. public bool Remove(int x, int y)
  93. {
  94. if (_map.TryGetValue(x, out var value))
  95. {
  96. if (value.Remove(y))
  97. {
  98. _isDirty = true;
  99. return true;
  100. }
  101. }
  102.  
  103. return false;
  104. }
  105. /// <summary>
  106. /// 往一个区域中填充指定的数据
  107. /// </summary>
  108. /// <param name="pos">起点位置</param>
  109. /// <param name="size">区域大小</param>
  110. /// <param name="data">数据</param>
  111. public void SetRect(Vector2I pos, Vector2I size, T data)
  112. {
  113. var x = pos.X;
  114. var y = pos.Y;
  115. for (var i = 0; i < size.X; i++)
  116. {
  117. for (var j = 0; j < size.Y; j++)
  118. {
  119. if (_map.TryGetValue(x + i, out var value))
  120. {
  121. value[y + j] = data;
  122. }
  123. else
  124. {
  125. value = new Dictionary<int, T>();
  126. value.Add(y + j, data);
  127. _map.Add(x + i, value);
  128. _isDirty = true;
  129. }
  130. }
  131. }
  132. }
  133.  
  134. /// <summary>
  135. /// 移除指定区域数据
  136. /// </summary>
  137. /// <param name="pos">起点位置</param>
  138. /// <param name="size">区域大小</param>
  139. public void RemoveRect(Vector2I pos, Vector2I size)
  140. {
  141. var x = pos.X;
  142. var y = pos.Y;
  143. for (var i = 0; i < size.X; i++)
  144. {
  145. for (var j = 0; j < size.Y; j++)
  146. {
  147. if (_map.TryGetValue(x + i, out var value))
  148. {
  149. if (value.Remove(y + j))
  150. {
  151. _isDirty = true;
  152. }
  153.  
  154. if (value.Count == 0)
  155. {
  156. _map.Remove(x + i);
  157. }
  158. }
  159. }
  160. }
  161. }
  162.  
  163. /// <summary>
  164. /// 清除所有数据
  165. /// </summary>
  166. public void Clear()
  167. {
  168. _map.Clear();
  169. _isDirty = true;
  170. }
  171. /// <summary>
  172. /// 检测矩形区域内是否与其他数据有碰撞
  173. /// </summary>
  174. /// <param name="pos">起点位置</param>
  175. /// <param name="size">区域大小</param>
  176. public bool RectCollision(Vector2I pos, Vector2I size)
  177. {
  178. var x = pos.X;
  179. var y = pos.Y;
  180. var w = size.X;
  181. var h = size.Y;
  182. //先判断四个角
  183. if (Contains(x, y) || Contains(x + w - 1, y) || Contains(x, y + h - 1) || Contains(x + w - 1, y + h - 1))
  184. {
  185. return true;
  186. }
  187.  
  188. //逐个点判断
  189. for (int i = 1; i < w; i++)
  190. {
  191. for (int j = 0; j < h; j++)
  192. {
  193. if (Contains(x + i, y + j))
  194. {
  195. return true;
  196. }
  197. }
  198. }
  199.  
  200. return false;
  201. }
  202.  
  203. /// <summary>
  204. /// 遍历网格数据, 回调返回 false 则停止遍历
  205. /// </summary>
  206. public void ForEach(EachGridCallback cb)
  207. {
  208. foreach (var pair1 in _map)
  209. {
  210. foreach (var pair2 in pair1.Value)
  211. {
  212. if (!cb(pair1.Key, pair2.Key, pair2.Value))
  213. {
  214. return;
  215. }
  216. }
  217. }
  218. }
  219.  
  220. /// <summary>
  221. /// 获取网格的包围矩形
  222. /// </summary>
  223. public Rect2I GetRect()
  224. {
  225. if (!_isDirty)
  226. {
  227. return _rect;
  228. }
  229.  
  230. _isDirty = false;
  231.  
  232. var flag = false;
  233. var minX = int.MaxValue;
  234. var minY = int.MaxValue;
  235. var maxX = int.MinValue;
  236. var maxY = int.MinValue;
  237. foreach (var pair1 in _map)
  238. {
  239. var x = pair1.Key;
  240. foreach (var pair2 in pair1.Value)
  241. {
  242. var y = pair2.Key;
  243. minX = Mathf.Min(x, minX);
  244. minY = Mathf.Min(y, minY);
  245. maxX = Mathf.Max(x, maxX);
  246. maxY = Mathf.Max(y, maxY);
  247. flag = true;
  248. }
  249. }
  250.  
  251. if (!flag)
  252. {
  253. return new Rect2I();
  254. }
  255.  
  256. _rect = new Rect2I(minX, minY, maxX - minX + 1, maxY - minY + 1);
  257. return _rect;
  258. }
  259. }