Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / InfiniteGrid.cs
@小李xl 小李xl on 18 Jan 2024 6 KB TileMap编辑器绘制组合
  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. _isDirty = true;
  97. return value.Remove(y);
  98. }
  99.  
  100. return false;
  101. }
  102. /// <summary>
  103. /// 往一个区域中填充指定的数据
  104. /// </summary>
  105. /// <param name="pos">起点位置</param>
  106. /// <param name="size">区域大小</param>
  107. /// <param name="data">数据</param>
  108. public void SetRect(Vector2I pos, Vector2I size, T data)
  109. {
  110. var x = pos.X;
  111. var y = pos.Y;
  112. for (var i = 0; i < size.X; i++)
  113. {
  114. for (var j = 0; j < size.Y; j++)
  115. {
  116. if (_map.TryGetValue(x + i, out var value))
  117. {
  118. value[y + j] = data;
  119. }
  120. else
  121. {
  122. value = new Dictionary<int, T>();
  123. value.Add(y + j, data);
  124. _map.Add(x + i, value);
  125. _isDirty = true;
  126. }
  127. }
  128. }
  129. }
  130.  
  131. /// <summary>
  132. /// 移除指定区域数据
  133. /// </summary>
  134. /// <param name="pos">起点位置</param>
  135. /// <param name="size">区域大小</param>
  136. public void RemoveRect(Vector2I pos, Vector2I size)
  137. {
  138. var x = pos.X;
  139. var y = pos.Y;
  140. for (var i = 0; i < size.X; i++)
  141. {
  142. for (var j = 0; j < size.Y; j++)
  143. {
  144. if (_map.TryGetValue(x + i, out var value))
  145. {
  146. value.Remove(y + j);
  147. if (value.Count == 0)
  148. {
  149. _map.Remove(x + i);
  150. _isDirty = true;
  151. }
  152. }
  153. }
  154. }
  155. }
  156.  
  157. /// <summary>
  158. /// 清除所有数据
  159. /// </summary>
  160. public void Clear()
  161. {
  162. _map.Clear();
  163. _isDirty = true;
  164. }
  165. /// <summary>
  166. /// 检测矩形区域内是否与其他数据有碰撞
  167. /// </summary>
  168. /// <param name="pos">起点位置</param>
  169. /// <param name="size">区域大小</param>
  170. public bool RectCollision(Vector2I pos, Vector2I size)
  171. {
  172. var x = pos.X;
  173. var y = pos.Y;
  174. var w = size.X;
  175. var h = size.Y;
  176. //先判断四个角
  177. if (Contains(x, y) || Contains(x + w - 1, y) || Contains(x, y + h - 1) || Contains(x + w - 1, y + h - 1))
  178. {
  179. return true;
  180. }
  181.  
  182. //逐个点判断
  183. for (int i = 1; i < w; i++)
  184. {
  185. for (int j = 0; j < h; j++)
  186. {
  187. if (Contains(x + i, y + j))
  188. {
  189. return true;
  190. }
  191. }
  192. }
  193.  
  194. return false;
  195. }
  196.  
  197. /// <summary>
  198. /// 遍历网格数据, 回调返回 false 则停止遍历
  199. /// </summary>
  200. public void ForEach(EachGridCallback cb)
  201. {
  202. foreach (var pair1 in _map)
  203. {
  204. foreach (var pair2 in pair1.Value)
  205. {
  206. if (!cb(pair1.Key, pair2.Key, pair2.Value))
  207. {
  208. return;
  209. }
  210. }
  211. }
  212. }
  213.  
  214. /// <summary>
  215. /// 获取网格的包围矩形
  216. /// </summary>
  217. public Rect2I GetRect()
  218. {
  219. if (!_isDirty)
  220. {
  221. return _rect;
  222. }
  223.  
  224. _isDirty = false;
  225.  
  226. var flag = false;
  227. var minX = int.MaxValue;
  228. var minY = int.MaxValue;
  229. var maxX = int.MinValue;
  230. var maxY = int.MinValue;
  231. foreach (var pair1 in _map)
  232. {
  233. var x = pair1.Key;
  234. foreach (var pair2 in pair1.Value)
  235. {
  236. var y = pair2.Key;
  237. minX = Mathf.Min(x, minX);
  238. minY = Mathf.Min(y, minY);
  239. maxX = Mathf.Max(x, maxX);
  240. maxY = Mathf.Max(y, maxY);
  241. flag = true;
  242. }
  243. }
  244.  
  245. if (!flag)
  246. {
  247. return new Rect2I();
  248. }
  249.  
  250. _rect = new Rect2I(minX, minY, maxX - minX + 1, maxY - minY + 1);
  251. return _rect;
  252. }
  253. }