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