Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / AffiliationArea.cs
@小李xl 小李xl on 3 Nov 2023 8 KB 优化可互动物体
  1.  
  2. using System;
  3. using System.Collections.Generic;
  4. using Godot;
  5.  
  6. /// <summary>
  7. /// 房间归属区域
  8. /// </summary>
  9. public partial class AffiliationArea : Area2D, IDestroy
  10. {
  11. public bool IsDestroyed { get; private set; }
  12.  
  13. /// <summary>
  14. /// 当前实例所属房间
  15. /// </summary>
  16. public RoomInfo RoomInfo;
  17. /// <summary>
  18. /// 当前归属区域包含的所有物体对象, 物体进入另一个区域时才会从该集合中移除
  19. /// </summary>
  20. private readonly HashSet<ActivityObject> _includeItems = new HashSet<ActivityObject>();
  21.  
  22. /// <summary>
  23. /// 已经进入 AffiliationArea 所在范围内的物体, 物体一旦离开该区域就会立刻从该集合中删除
  24. /// </summary>
  25. private readonly HashSet<ActivityObject> _enterItems = new HashSet<ActivityObject>();
  26. /// <summary>
  27. /// 玩家是否是第一次进入
  28. /// </summary>
  29. public bool IsFirstEnterFlag { get; private set; } = true;
  30.  
  31. /// <summary>
  32. /// 静态渲染精灵根节点, 用于放置sprite
  33. /// </summary>
  34. public AffiliationSpriteRoot SpriteRoot { get; private set; }
  35.  
  36. private bool _init = false;
  37. private Vector2 _initSize;
  38. private RectangleShape2D _shape;
  39. /// <summary>
  40. /// 根据矩形区域初始化归属区域
  41. /// </summary>
  42. public void Init(RoomInfo roomInfo, Rect2I rect2)
  43. {
  44. if (_init)
  45. {
  46. return;
  47. }
  48.  
  49. _init = true;
  50.  
  51. _initSize = rect2.Size;
  52. RoomInfo = roomInfo;
  53. SpriteRoot = new AffiliationSpriteRoot(this);
  54. SpriteRoot.Name = "SpriteRoot";
  55. World.Current.StaticSpriteRoot.AddChild(SpriteRoot);
  56.  
  57. var collisionShape = new CollisionShape2D();
  58. collisionShape.GlobalPosition = rect2.Position + rect2.Size / 2;
  59. var shape = new RectangleShape2D();
  60. _shape = shape;
  61. shape.Size = rect2.Size;
  62. collisionShape.Shape = shape;
  63. AddChild(collisionShape);
  64. _Init();
  65. }
  66.  
  67. private void _Init()
  68. {
  69. Monitoring = true;
  70. Monitorable = false;
  71. CollisionLayer = PhysicsLayer.None;
  72. CollisionMask = PhysicsLayer.Prop | PhysicsLayer.Player | PhysicsLayer.Enemy | PhysicsLayer.Debris | PhysicsLayer.Throwing;
  73.  
  74. BodyEntered += OnBodyEntered;
  75. BodyExited += OnBodyExited;
  76. }
  77.  
  78. /// <summary>
  79. /// 将物体添加到当前所属区域中
  80. /// </summary>
  81. public void InsertItem(ActivityObject activityObject)
  82. {
  83. if (activityObject.AffiliationArea == this)
  84. {
  85. return;
  86. }
  87.  
  88. if (activityObject.AffiliationArea != null)
  89. {
  90. activityObject.AffiliationArea._includeItems.Remove(activityObject);
  91. }
  92. activityObject.AffiliationArea = this;
  93. _includeItems.Add(activityObject);
  94.  
  95. //如果是玩家
  96. if (activityObject == Player.Current)
  97. {
  98. OnPlayerInsertRoom();
  99. }
  100. }
  101.  
  102. /// <summary>
  103. /// 将物体从当前所属区域移除
  104. /// </summary>
  105. public void RemoveItem(ActivityObject activityObject)
  106. {
  107. if (activityObject.AffiliationArea == null)
  108. {
  109. return;
  110. }
  111. activityObject.AffiliationArea = null;
  112. _includeItems.Remove(activityObject);
  113. }
  114.  
  115. /// <summary>
  116. /// 获取该区域中物体的总数
  117. /// </summary>
  118. public int GetIncludeItemsCount()
  119. {
  120. return _includeItems.Count;
  121. }
  122.  
  123. /// <summary>
  124. /// 统计符合条件的数量
  125. /// </summary>
  126. /// <param name="handler">操作函数, 返回是否满足要求</param>
  127. public int FindIncludeItemsCount(Func<ActivityObject, bool> handler)
  128. {
  129. var count = 0;
  130. foreach (var activityObject in _includeItems)
  131. {
  132. if (!activityObject.IsDestroyed && handler(activityObject))
  133. {
  134. count++;
  135. }
  136. }
  137. return count;
  138. }
  139.  
  140. /// <summary>
  141. /// 查询所有符合条件的对象并返回
  142. /// </summary>
  143. /// <param name="handler">操作函数, 返回是否满足要求</param>
  144. public ActivityObject[] FindIncludeItems(Func<ActivityObject, bool> handler)
  145. {
  146. var list = new List<ActivityObject>();
  147. foreach (var activityObject in _includeItems)
  148. {
  149. if (!activityObject.IsDestroyed && handler(activityObject))
  150. {
  151. list.Add(activityObject);
  152. }
  153. }
  154. return list.ToArray();
  155. }
  156.  
  157. /// <summary>
  158. /// 检查是否有符合条件的对象
  159. /// </summary>
  160. /// <param name="handler">操作函数, 返回是否满足要求</param>
  161. public bool ExistIncludeItem(Func<ActivityObject, bool> handler)
  162. {
  163. foreach (var activityObject in _includeItems)
  164. {
  165. if (!activityObject.IsDestroyed && handler(activityObject))
  166. {
  167. return true;
  168. }
  169. }
  170.  
  171. return false;
  172. }
  173. /// <summary>
  174. /// 获取进入该区域中物体的总数
  175. /// </summary>
  176. public int GetEnterItemsCount()
  177. {
  178. return _enterItems.Count;
  179. }
  180. /// <summary>
  181. /// 统计进入该区域且符合条件的数量
  182. /// </summary>
  183. /// <param name="handler">操作函数, 返回是否满足要求</param>
  184. public int FindEnterItemsCount(Func<ActivityObject, bool> handler)
  185. {
  186. var count = 0;
  187. foreach (var activityObject in _enterItems)
  188. {
  189. if (!activityObject.IsDestroyed && handler(activityObject))
  190. {
  191. count++;
  192. }
  193. }
  194. return count;
  195. }
  196. /// <summary>
  197. /// 查询所有进入该区域且符合条件的对象并返回
  198. /// </summary>
  199. /// <param name="handler">操作函数, 返回是否满足要求</param>
  200. public ActivityObject[] FindEnterItems(Func<ActivityObject, bool> handler)
  201. {
  202. var list = new List<ActivityObject>();
  203. foreach (var activityObject in _enterItems)
  204. {
  205. if (!activityObject.IsDestroyed && handler(activityObject))
  206. {
  207. list.Add(activityObject);
  208. }
  209. }
  210. return list.ToArray();
  211. }
  212.  
  213. /// <summary>
  214. /// 检查是否有进入该区域且符合条件的对象
  215. /// </summary>
  216. /// <param name="handler">操作函数, 返回是否满足要求</param>
  217. public bool ExistEnterItem(Func<ActivityObject, bool> handler)
  218. {
  219. foreach (var activityObject in _enterItems)
  220. {
  221. if (!activityObject.IsDestroyed && handler(activityObject))
  222. {
  223. return true;
  224. }
  225. }
  226.  
  227. return false;
  228. }
  229.  
  230. /// <summary>
  231. /// 返回物体是否进入了该区域
  232. /// </summary>
  233. public bool IsEnter(ActivityObject activityObject)
  234. {
  235. return _enterItems.Contains(activityObject);
  236. }
  237. private void OnBodyEntered(Node2D body)
  238. {
  239. if (body is ActivityObject activityObject)
  240. {
  241. _enterItems.Add(activityObject);
  242. //注意需要延时调用
  243. CallDeferred(nameof(InsertItem), activityObject);
  244. }
  245. }
  246. private void OnBodyExited(Node2D body)
  247. {
  248. if (body is ActivityObject activityObject)
  249. {
  250. _enterItems.Remove(activityObject);
  251. }
  252. }
  253.  
  254. //玩家进入房间
  255. private void OnPlayerInsertRoom()
  256. {
  257. if (IsFirstEnterFlag)
  258. {
  259. EventManager.EmitEvent(EventEnum.OnPlayerFirstEnterRoom, RoomInfo);
  260. }
  261. EventManager.EmitEvent(EventEnum.OnPlayerEnterRoom, RoomInfo);
  262. IsFirstEnterFlag = false;
  263. }
  264.  
  265. public void Destroy()
  266. {
  267. if (IsDestroyed)
  268. {
  269. return;
  270. }
  271.  
  272. IsDestroyed = true;
  273. QueueFree();
  274. _includeItems.Clear();
  275. _enterItems.Clear();
  276. if (SpriteRoot != null)
  277. {
  278. SpriteRoot.Destroy();
  279. }
  280. }
  281.  
  282. /// <summary>
  283. /// 在初始区域的基础上扩展区域, size为扩展大小
  284. /// </summary>
  285. public void ExtendedRegion(Vector2 size)
  286. {
  287. _shape.Size = _initSize + size;
  288. }
  289.  
  290. /// <summary>
  291. /// 将区域还原到初始大小
  292. /// </summary>
  293. public void RestoreRegion()
  294. {
  295. _shape.Size = _initSize;
  296. }
  297. }