Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / package / Package.cs
@小李xl 小李xl on 18 Nov 2023 11 KB 优化状态机
  1. using System;
  2. using System.Collections.Generic;
  3.  
  4. /// <summary>
  5. /// 物体背包类
  6. /// </summary>
  7. public class Package<T, S> : Component<S> where T : ActivityObject, IPackageItem<S> where S : Role
  8. {
  9. /// <summary>
  10. /// 当前使用对象改变时回调
  11. /// </summary>
  12. public event Action<T> ChangeActiveItemEvent;
  13.  
  14. /// <summary>
  15. /// 当前使用的物体对象
  16. /// </summary>
  17. public T ActiveItem
  18. {
  19. get => _activeItem;
  20. set
  21. {
  22. if (value != _activeItem)
  23. {
  24. _activeItem = value;
  25. if (ChangeActiveItemEvent != null)
  26. {
  27. ChangeActiveItemEvent(value);
  28. }
  29. }
  30. }
  31. }
  32.  
  33. private T _activeItem;
  34.  
  35. /// <summary>
  36. /// 当前使用的物体的索引
  37. /// </summary>
  38. public int ActiveIndex { get; private set; } = 0;
  39.  
  40. /// <summary>
  41. /// 物体背包容量
  42. /// </summary>
  43. public int Capacity { get; private set; } = 0;
  44.  
  45. /// <summary>
  46. /// 物体插槽
  47. /// </summary>
  48. public T[] ItemSlot { get; private set; }
  49.  
  50. /// <summary>
  51. /// 修改物体背包容量
  52. /// </summary>
  53. public void SetCapacity(int capacity)
  54. {
  55. if (capacity < 0)
  56. {
  57. capacity = 0;
  58. }
  59.  
  60. if (capacity == Capacity)
  61. {
  62. return;
  63. }
  64.  
  65. if (ItemSlot == null)
  66. {
  67. ItemSlot = new T[capacity];
  68. }
  69. else if (ItemSlot.Length > capacity) //删减格子
  70. {
  71. var newArray = new T[capacity];
  72. for (var i = 0; i < ItemSlot.Length; i++)
  73. {
  74. var packageItem = ItemSlot[i];
  75. if (i < capacity)
  76. {
  77. newArray[i] = packageItem;
  78. }
  79. else if (packageItem != null) //溢出的item
  80. {
  81. packageItem.OnOverflowItem();
  82. packageItem.Master = null;
  83. packageItem.PackageIndex = -1;
  84. }
  85. }
  86.  
  87. ItemSlot = newArray;
  88. }
  89. else //添加格子
  90. {
  91. var newArray = new T[capacity];
  92. for (var i = 0; i < ItemSlot.Length; i++)
  93. {
  94. newArray[i] = ItemSlot[i];
  95. }
  96. ItemSlot = newArray;
  97. }
  98. Capacity = capacity;
  99. }
  100.  
  101. /// <summary>
  102. /// 返回当前物体背包是否是空的
  103. /// </summary>
  104. public bool IsEmpty()
  105. {
  106. for (var i = 0; i < ItemSlot.Length; i++)
  107. {
  108. if (ItemSlot[i] != null)
  109. {
  110. return false;
  111. }
  112. }
  113.  
  114. return true;
  115. }
  116. /// <summary>
  117. /// 返回当前物体背包是否还有空位
  118. /// </summary>
  119. public bool HasVacancy()
  120. {
  121. for (var i = 0; i < ItemSlot.Length; i++)
  122. {
  123. if (ItemSlot[i] == null)
  124. {
  125. return true;
  126. }
  127. }
  128.  
  129. return false;
  130. }
  131.  
  132. /// <summary>
  133. /// 根据索引获取物体
  134. /// </summary>
  135. public T GetItem(int index)
  136. {
  137. if (index < 0 || index >= ItemSlot.Length)
  138. {
  139. return null;
  140. }
  141. return ItemSlot[index];
  142. }
  143.  
  144. /// <summary>
  145. /// 根据物体id查找物体背包中该物体所在的位置, 如果没有, 则返回 -1
  146. /// </summary>
  147. /// <param name="id">物体id</param>
  148. public int FindIndex(string id)
  149. {
  150. for (var i = 0; i < ItemSlot.Length; i++)
  151. {
  152. var item = ItemSlot[i];
  153. if (item != null && item.ActivityBase.Id == id)
  154. {
  155. return i;
  156. }
  157. }
  158. return -1;
  159. }
  160.  
  161. /// <summary>
  162. /// 通过回调函数查询物体在物体背包中的位置, 如果没有, 则返回 -1
  163. /// </summary>
  164. public int FindIndex(Func<T, int, bool> handler)
  165. {
  166. for (var i = 0; i < ItemSlot.Length; i++)
  167. {
  168. var item = ItemSlot[i];
  169. if (item != null && handler(item, i))
  170. {
  171. return i;
  172. }
  173. }
  174. return -1;
  175. }
  176.  
  177. /// <summary>
  178. /// 遍历所有物体
  179. /// </summary>
  180. public void ForEach(Action<T, int> handler)
  181. {
  182. for (var i = 0; i < ItemSlot.Length; i++)
  183. {
  184. var item = ItemSlot[i];
  185. if (item != null)
  186. {
  187. handler(item, i);
  188. }
  189. }
  190. }
  191.  
  192. /// <summary>
  193. /// 从物体背包中移除所有物体, 并返回
  194. /// </summary>
  195. public T[] GetAndClearItem()
  196. {
  197. var items = new List<T>();
  198. for (var i = 0; i < ItemSlot.Length; i++)
  199. {
  200. var item = ItemSlot[i];
  201. if (item != null)
  202. {
  203. //触发移除物体
  204. item.OnRemoveItem();
  205. item.Master = null;
  206. item.PackageIndex = -1;
  207.  
  208. items.Add(item);
  209. ItemSlot[i] = null;
  210. }
  211. }
  212.  
  213. return items.ToArray();
  214. }
  215.  
  216. /// <summary>
  217. /// 拾起物体, 存入物体背包中, 返回存放在物体背包的位置, 如果容不下这个物体, 则会返回 -1
  218. /// </summary>
  219. /// <param name="item">物体对象</param>
  220. /// <param name="exchange">是否立即切换到该物体, 默认 true </param>
  221. public int PickupItem(T item, bool exchange = true)
  222. {
  223. //已经被拾起了
  224. if (item.Master != null)
  225. {
  226. return -1;
  227. }
  228. for (var i = 0; i < ItemSlot.Length; i++)
  229. {
  230. var tempItem = ItemSlot[i];
  231. if (tempItem == null)
  232. {
  233. ItemSlot[i] = item;
  234. item.Master = Master;
  235. item.PackageIndex = i;
  236. item.OnPickUpItem();
  237. if (exchange)
  238. {
  239. ExchangeByIndex(i);
  240. }
  241.  
  242. return i;
  243. }
  244. }
  245. return -1;
  246. }
  247.  
  248. /// <summary>
  249. /// 移除指定位置的物体, 并返回这个物体对象, 如果移除正在使用的这个物体, 则会自动切换到上一个物体
  250. /// </summary>
  251. /// <param name="index">所在物体背包的位置索引</param>
  252. public T RemoveItem(int index)
  253. {
  254. if (index < 0 || index >= ItemSlot.Length)
  255. {
  256. return null;
  257. }
  258. var item = ItemSlot[index];
  259. if (item == null)
  260. {
  261. return null;
  262. }
  263. ItemSlot[index] = null;
  264.  
  265. //如果是当前手持的物体, 就需要调用切换物体操作
  266. if (index == ActiveIndex)
  267. {
  268. //没有其他物体了
  269. if (ExchangePrev(true) == index)
  270. {
  271. ActiveIndex = 0;
  272. ActiveItem = null;
  273. }
  274. }
  275. //移除物体
  276. item.OnRemoveItem();
  277. item.Master = null;
  278. item.PackageIndex = -1;
  279. // item.GetParent().RemoveChild(item);
  280. // item.Remove();
  281. return item;
  282. }
  283.  
  284. /// <summary>
  285. /// 移除指定位置的物体, 并返回这个物体对象, 如果移除正在使用的这个物体, 则会自动切换到上一个物体
  286. /// </summary>
  287. public T RemoveItem(T item)
  288. {
  289. return RemoveItem(IndexOf(item));
  290. }
  291.  
  292. /// <summary>
  293. /// 切换到上一个物体
  294. /// </summary>
  295. public int ExchangePrev()
  296. {
  297. return ExchangePrev(false);
  298. }
  299. private int ExchangePrev(bool removeFlag)
  300. {
  301. var index = ActiveIndex - 1;
  302. do
  303. {
  304. if (index < 0)
  305. {
  306. index = ItemSlot.Length - 1;
  307. }
  308. if (ExchangeByIndex(index, removeFlag))
  309. {
  310. return index;
  311. }
  312. } while (index-- != ActiveIndex);
  313. return -1;
  314. }
  315.  
  316. /// <summary>
  317. /// 切换到下一个物体,
  318. /// </summary>
  319. public int ExchangeNext()
  320. {
  321. var index = ActiveIndex + 1;
  322. do
  323. {
  324. if (index >= ItemSlot.Length)
  325. {
  326. index = 0;
  327. }
  328. if (ExchangeByIndex(index))
  329. {
  330. return index;
  331. }
  332. } while (index++ != ActiveIndex);
  333. return -1;
  334. }
  335.  
  336. /// <summary>
  337. /// 切换到指定索引的物体
  338. /// </summary>
  339. public bool ExchangeByIndex(int index)
  340. {
  341. return ExchangeByIndex(index, false);
  342. }
  343.  
  344. private bool ExchangeByIndex(int index, bool removeFlag)
  345. {
  346. if (index == ActiveIndex && ActiveItem != null) return true;
  347. if (index < 0 || index > ItemSlot.Length) return false;
  348. var item = ItemSlot[index];
  349. if (item == null) return false;
  350.  
  351. //将上一个物体放到背后
  352. if (!removeFlag && ActiveItem != null)
  353. {
  354. //收起物体
  355. ActiveItem.OnConcealItem();
  356. }
  357.  
  358. //切换物体
  359. ActiveItem = item;
  360. ActiveIndex = index;
  361. ActiveItem.OnActiveItem();
  362. return true;
  363. }
  364.  
  365. /// <summary>
  366. /// 返回背包中是否有指定物体
  367. /// </summary>
  368. public bool Contains(T item)
  369. {
  370. if (ItemSlot == null)
  371. {
  372. return false;
  373. }
  374.  
  375. foreach (var packageItem in ItemSlot)
  376. {
  377. if (packageItem == item)
  378. {
  379. return true;
  380. }
  381. }
  382.  
  383. return false;
  384. }
  385.  
  386. /// <summary>
  387. /// 返回指定物体在当前背包中的索引, 如果不在背包中, 则返回 -1
  388. /// </summary>
  389. public int IndexOf(T item)
  390. {
  391. if (ItemSlot == null)
  392. {
  393. return -1;
  394. }
  395.  
  396. for (var i = 0; i < ItemSlot.Length; i++)
  397. {
  398. var packageItem = ItemSlot[i];
  399. if (packageItem == item)
  400. {
  401. return i;
  402. }
  403. }
  404.  
  405. return -1;
  406. }
  407.  
  408. /// <summary>
  409. /// 返回指定 id 的物体在背包中的索引, 如果不在背包中, 则返回 -1
  410. /// </summary>
  411. public int IndexOfByItemId(string itemId)
  412. {
  413. if (ItemSlot == null)
  414. {
  415. return -1;
  416. }
  417.  
  418. for (var i = 0; i < ItemSlot.Length; i++)
  419. {
  420. var packageItem = ItemSlot[i];
  421. if (packageItem != null && packageItem.ActivityBase.Id == itemId)
  422. {
  423. return i;
  424. }
  425. }
  426.  
  427. return -1;
  428. }
  429.  
  430. /// <summary>
  431. /// 获取背包中指定 id 的物体, 如果有多个相同 id 的物体, 则返回第一个匹配的物体
  432. /// </summary>
  433. public T GetItemById(string itemId)
  434. {
  435. if (ItemSlot == null)
  436. {
  437. return null;
  438. }
  439.  
  440. for (var i = 0; i < ItemSlot.Length; i++)
  441. {
  442. var packageItem = ItemSlot[i];
  443. if (packageItem != null && packageItem.ActivityBase.Id == itemId)
  444. {
  445. return packageItem;
  446. }
  447. }
  448.  
  449. return null;
  450. }
  451. public override void OnDestroy()
  452. {
  453. for (var i = 0; i < ItemSlot.Length; i++)
  454. {
  455. var activityObject = ItemSlot[i];
  456. if (activityObject != null)
  457. {
  458. activityObject.Destroy();
  459. ItemSlot[i] = null;
  460. }
  461. }
  462. }
  463. }