Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / role / Role.cs
@小李xl 小李xl on 10 Nov 2023 21 KB 更改角色模板继承关系
  1.  
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using Godot;
  5.  
  6. /// <summary>
  7. /// 角色基类
  8. /// </summary>
  9. public abstract partial class Role : ActivityObject
  10. {
  11. /// <summary>
  12. /// 是否是 Ai
  13. /// </summary>
  14. public bool IsAi { get; protected set; } = false;
  15.  
  16. /// <summary>
  17. /// 角色属性
  18. /// </summary>
  19. public RoleState RoleState { get; } = new RoleState();
  20. /// <summary>
  21. /// 默认攻击对象层级
  22. /// </summary>
  23. public const uint DefaultAttackLayer = PhysicsLayer.Player | PhysicsLayer.Enemy | PhysicsLayer.Wall;
  24. /// <summary>
  25. /// 伤害区域
  26. /// </summary>
  27. [Export, ExportFillNode]
  28. public Area2D HurtArea { get; set; }
  29. /// <summary>
  30. /// 伤害区域碰撞器
  31. /// </summary>
  32. [Export, ExportFillNode]
  33. public CollisionShape2D HurtCollision { get; set; }
  34.  
  35. /// <summary>
  36. /// 所属阵营
  37. /// </summary>
  38. public CampEnum Camp;
  39.  
  40. /// <summary>
  41. /// 攻击目标的碰撞器所属层级, 数据源自于: <see cref="PhysicsLayer"/>
  42. /// </summary>
  43. public uint AttackLayer { get; set; } = PhysicsLayer.Wall;
  44. /// <summary>
  45. /// 该角色敌对目标的碰撞器所属层级, 数据源自于: <see cref="PhysicsLayer"/>
  46. /// </summary>
  47. public uint EnemyLayer { get; set; } = PhysicsLayer.Enemy;
  48.  
  49. /// <summary>
  50. /// 携带的被动道具列表
  51. /// </summary>
  52. public List<BuffProp> BuffPropPack { get; } = new List<BuffProp>();
  53.  
  54. /// <summary>
  55. /// 携带的主动道具包裹
  56. /// </summary>
  57. public Package<ActiveProp, Role> ActivePropsPack { get; private set; }
  58. /// <summary>
  59. /// 互动碰撞区域
  60. /// </summary>
  61. [Export, ExportFillNode]
  62. public Area2D InteractiveArea { get; set; }
  63. /// <summary>
  64. /// 互动区域碰撞器
  65. /// </summary>
  66. [Export, ExportFillNode]
  67. public CollisionShape2D InteractiveCollision { get; set; }
  68. /// <summary>
  69. /// 脸的朝向
  70. /// </summary>
  71. public FaceDirection Face { get => _face; set => SetFace(value); }
  72. private FaceDirection _face;
  73.  
  74. /// <summary>
  75. /// 是否死亡
  76. /// </summary>
  77. public bool IsDie { get; private set; }
  78. /// <summary>
  79. /// 血量
  80. /// </summary>
  81. public int Hp
  82. {
  83. get => _hp;
  84. set
  85. {
  86. int temp = _hp;
  87. _hp = Mathf.Clamp(value, 0, _maxHp);
  88. if (temp != _hp)
  89. {
  90. OnChangeHp(_hp);
  91. }
  92. }
  93. }
  94. private int _hp = 20;
  95.  
  96. /// <summary>
  97. /// 最大血量
  98. /// </summary>
  99. public int MaxHp
  100. {
  101. get => _maxHp;
  102. set
  103. {
  104. int temp = _maxHp;
  105. _maxHp = value;
  106. //最大血量值改变
  107. if (temp != _maxHp)
  108. {
  109. OnChangeMaxHp(_maxHp);
  110. }
  111. //调整血量
  112. if (Hp > _maxHp)
  113. {
  114. Hp = _maxHp;
  115. }
  116. }
  117. }
  118. private int _maxHp = 20;
  119. /// <summary>
  120. /// 当前护盾值
  121. /// </summary>
  122. public int Shield
  123. {
  124. get => _shield;
  125. set
  126. {
  127. int temp = _shield;
  128. _shield = value;
  129. //护盾被破坏
  130. if (temp > 0 && _shield <= 0 && _maxShield > 0)
  131. {
  132. OnShieldDestroy();
  133. }
  134. //护盾值改变
  135. if (temp != _shield)
  136. {
  137. OnChangeShield(_shield);
  138. }
  139. }
  140. }
  141. private int _shield = 0;
  142.  
  143. /// <summary>
  144. /// 最大护盾值
  145. /// </summary>
  146. public int MaxShield
  147. {
  148. get => _maxShield;
  149. set
  150. {
  151. int temp = _maxShield;
  152. _maxShield = value;
  153. //最大护盾值改变
  154. if (temp != _maxShield)
  155. {
  156. OnChangeMaxShield(_maxShield);
  157. }
  158. //调整护盾值
  159. if (Shield > _maxShield)
  160. {
  161. Shield = _maxShield;
  162. }
  163. }
  164. }
  165. private int _maxShield = 0;
  166.  
  167. /// <summary>
  168. /// 无敌状态
  169. /// </summary>
  170. public bool Invincible
  171. {
  172. get => _invincible;
  173. set
  174. {
  175. if (_invincible != value)
  176. {
  177. if (value) //无敌状态
  178. {
  179. HurtArea.CollisionLayer = _currentLayer;
  180. _flashingInvincibleTimer = -1;
  181. _flashingInvincibleFlag = false;
  182. }
  183. else //正常状态
  184. {
  185. HurtArea.CollisionLayer = _currentLayer;
  186. SetBlendModulate(new Color(1, 1, 1, 1));
  187. }
  188. }
  189.  
  190. _invincible = value;
  191. }
  192. }
  193.  
  194. private bool _invincible = false;
  195. /// <summary>
  196. /// 当前可以互动的物体
  197. /// </summary>
  198. public ActivityObject InteractiveItem { get; private set; }
  199. /// <summary>
  200. /// 瞄准辅助线, 需要手动调用 InitSubLine() 初始化
  201. /// </summary>
  202. public SubLine SubLine { get; private set; }
  203. /// <summary>
  204. /// 所有角色碰撞的物体
  205. /// </summary>
  206. public List<ActivityObject> InteractiveItemList { get; } = new List<ActivityObject>();
  207. //初始缩放
  208. private Vector2 _startScale;
  209. //当前可互动的物体
  210. private CheckInteractiveResult _currentResultData;
  211. private uint _currentLayer;
  212. //闪烁计时器
  213. private float _flashingInvincibleTimer = -1;
  214. //闪烁状态
  215. private bool _flashingInvincibleFlag = false;
  216. //闪烁动画协程id
  217. private long _invincibleFlashingId = -1;
  218. //护盾恢复计时器
  219. private float _shieldRecoveryTimer = 0;
  220.  
  221. /// <summary>
  222. /// 当血量改变时调用
  223. /// </summary>
  224. protected virtual void OnChangeHp(int hp)
  225. {
  226. }
  227.  
  228. /// <summary>
  229. /// 当最大血量改变时调用
  230. /// </summary>
  231. protected virtual void OnChangeMaxHp(int maxHp)
  232. {
  233. }
  234. /// <summary>
  235. /// 护盾值改变时调用
  236. /// </summary>
  237. protected virtual void OnChangeShield(int shield)
  238. {
  239. }
  240.  
  241. /// <summary>
  242. /// 最大护盾值改变时调用
  243. /// </summary>
  244. protected virtual void OnChangeMaxShield(int maxShield)
  245. {
  246. }
  247.  
  248. /// <summary>
  249. /// 当护盾被破坏时调用
  250. /// </summary>
  251. protected virtual void OnShieldDestroy()
  252. {
  253. }
  254.  
  255. /// <summary>
  256. /// 当受伤时调用
  257. /// </summary>
  258. /// <param name="damage">受到的伤害</param>
  259. /// <param name="realHarm">是否受到真实伤害, 如果为false, 则表示该伤害被互动格挡掉了</param>
  260. protected virtual void OnHit(int damage, bool realHarm)
  261. {
  262. }
  263.  
  264. /// <summary>
  265. /// 受到伤害时调用, 用于改变受到的伤害值
  266. /// </summary>
  267. /// <param name="damage">受到的伤害</param>
  268. protected virtual int OnHandlerHurt(int damage)
  269. {
  270. return damage;
  271. }
  272. /// <summary>
  273. /// 当可互动的物体改变时调用, result 参数为 null 表示变为不可互动
  274. /// </summary>
  275. /// <param name="prev">上一个互动的物体</param>
  276. /// <param name="result">当前物体, 检测是否可互动时的返回值</param>
  277. protected virtual void ChangeInteractiveItem(CheckInteractiveResult prev, CheckInteractiveResult result)
  278. {
  279. }
  280.  
  281. /// <summary>
  282. /// 死亡时调用
  283. /// </summary>
  284. protected virtual void OnDie()
  285. {
  286. }
  287. /// <summary>
  288. /// 当拾起某个主动道具时调用
  289. /// </summary>
  290. protected virtual void OnPickUpActiveProp(ActiveProp activeProp)
  291. {
  292. }
  293.  
  294. /// <summary>
  295. /// 当移除某个主动道具时调用
  296. /// </summary>
  297. protected virtual void OnRemoveActiveProp(ActiveProp activeProp)
  298. {
  299. }
  300. /// <summary>
  301. /// 当切换到某个主动道具时调用
  302. /// </summary>
  303. protected virtual void OnExchangeActiveProp(ActiveProp activeProp)
  304. {
  305. }
  306. /// <summary>
  307. /// 当拾起某个被动道具时调用
  308. /// </summary>
  309. protected virtual void OnPickUpBuffProp(BuffProp buffProp)
  310. {
  311. }
  312.  
  313. /// <summary>
  314. /// 当移除某个被动道具时调用
  315. /// </summary>
  316. protected virtual void OnRemoveBuffProp(BuffProp buffProp)
  317. {
  318. }
  319. /// <summary>
  320. /// 触发攻击
  321. /// </summary>
  322. public virtual void Attack()
  323. {
  324. }
  325. public override void OnInit()
  326. {
  327. ActivePropsPack = AddComponent<Package<ActiveProp, Role>>();
  328. ActivePropsPack.SetCapacity(1);
  329. _startScale = Scale;
  330. HurtArea.CollisionLayer = CollisionLayer;
  331. HurtArea.CollisionMask = 0;
  332. _currentLayer = HurtArea.CollisionLayer;
  333. Face = FaceDirection.Right;
  334. //连接互动物体信号
  335. InteractiveArea.BodyEntered += _OnPropsEnter;
  336. InteractiveArea.BodyExited += _OnPropsExit;
  337. }
  338.  
  339. protected override void Process(float delta)
  340. {
  341. //检查可互动的物体
  342. bool findFlag = false;
  343. for (int i = 0; i < InteractiveItemList.Count; i++)
  344. {
  345. var item = InteractiveItemList[i];
  346. if (item == null || item.IsDestroyed)
  347. {
  348. InteractiveItemList.RemoveAt(i--);
  349. }
  350. else if (!item.IsThrowing)
  351. {
  352. //找到可互动的物体了
  353. if (!findFlag)
  354. {
  355. var result = item.CheckInteractive(this);
  356. var prev = _currentResultData;
  357. _currentResultData = result;
  358. if (result.CanInteractive) //可以互动
  359. {
  360. findFlag = true;
  361. if (InteractiveItem != item) //更改互动物体
  362. {
  363. InteractiveItem = item;
  364. ChangeInteractiveItem(prev, result);
  365. }
  366. else if (result.Type != _currentResultData.Type) //切换状态
  367. {
  368. ChangeInteractiveItem(prev, result);
  369. }
  370. }
  371. }
  372. }
  373. }
  374. //没有可互动的物体
  375. if (!findFlag && InteractiveItem != null)
  376. {
  377. var prev = _currentResultData;
  378. _currentResultData = null;
  379. InteractiveItem = null;
  380. ChangeInteractiveItem(prev, null);
  381. }
  382.  
  383. //无敌状态, 播放闪烁动画
  384. if (Invincible)
  385. {
  386. _flashingInvincibleTimer -= delta;
  387. if (_flashingInvincibleTimer <= 0)
  388. {
  389. _flashingInvincibleTimer = 0.15f;
  390. if (_flashingInvincibleFlag)
  391. {
  392. _flashingInvincibleFlag = false;
  393. SetBlendModulate(new Color(1, 1, 1, 0.7f));
  394. }
  395. else
  396. {
  397. _flashingInvincibleFlag = true;
  398. SetBlendModulate(new Color(1, 1, 1, 0));
  399. }
  400. }
  401.  
  402. _shieldRecoveryTimer = 0;
  403. }
  404. else //恢复护盾
  405. {
  406. if (Shield < MaxShield)
  407. {
  408. _shieldRecoveryTimer += delta;
  409. if (_shieldRecoveryTimer >= RoleState.ShieldRecoveryTime) //时间到, 恢复
  410. {
  411. Shield++;
  412. _shieldRecoveryTimer = 0;
  413. }
  414. }
  415. else
  416. {
  417. _shieldRecoveryTimer = 0;
  418. }
  419. }
  420.  
  421. //被动道具更新
  422. if (BuffPropPack.Count > 0)
  423. {
  424. var buffProps = BuffPropPack.ToArray();
  425. foreach (var prop in buffProps)
  426. {
  427. if (!prop.IsDestroyed)
  428. {
  429. prop.PackProcess(delta);
  430. }
  431. }
  432. }
  433. //主动道具调用更新
  434. var props = ActivePropsPack.ItemSlot;
  435. if (props.Length > 0)
  436. {
  437. props = (ActiveProp[])props.Clone();
  438. foreach (var prop in props)
  439. {
  440. if (prop != null && !prop.IsDestroyed)
  441. {
  442. prop.PackProcess(delta);
  443. }
  444. }
  445. }
  446. }
  447. /// <summary>
  448. /// 初始化瞄准辅助线
  449. /// </summary>
  450. public void InitSubLine()
  451. {
  452. if (SubLine != null)
  453. {
  454. return;
  455. }
  456.  
  457. SubLine = AddComponent<SubLine>();
  458. }
  459. /// <summary>
  460. /// 是否是满血
  461. /// </summary>
  462. public bool IsHpFull()
  463. {
  464. return Hp >= MaxHp;
  465. }
  466. /// <summary>
  467. /// 获取当前角色的中心点坐标
  468. /// </summary>
  469. public virtual Vector2 GetCenterPosition()
  470. {
  471. return AnimatedSprite.GlobalPosition;
  472. }
  473. /// <summary>
  474. /// 使角色看向指定的坐标的方向
  475. /// </summary>
  476. public virtual void LookTargetPosition(Vector2 pos)
  477. {
  478. //脸的朝向
  479. var gPos = GlobalPosition;
  480. if (pos.X > gPos.X && Face == FaceDirection.Left)
  481. {
  482. Face = FaceDirection.Right;
  483. }
  484. else if (pos.X < gPos.X && Face == FaceDirection.Right)
  485. {
  486. Face = FaceDirection.Left;
  487. }
  488. }
  489. /// <summary>
  490. /// 判断指定坐标是否在角色视野方向
  491. /// </summary>
  492. public bool IsPositionInForward(Vector2 pos)
  493. {
  494. var gps = GlobalPosition;
  495. return (Face == FaceDirection.Left && pos.X <= gps.X) ||
  496. (Face == FaceDirection.Right && pos.X >= gps.X);
  497. }
  498. /// <summary>
  499. /// 拾起主动道具, 返回是否成功拾起, 如果不想立刻切换到该道具, exchange 请传 false
  500. /// </summary>
  501. /// <param name="activeProp">主动道具对象</param>
  502. /// <param name="exchange">是否立即切换到该道具, 默认 true </param>
  503. public bool PickUpActiveProp(ActiveProp activeProp, bool exchange = true)
  504. {
  505. if (ActivePropsPack.PickupItem(activeProp, exchange) != -1)
  506. {
  507. //从可互动队列中移除
  508. InteractiveItemList.Remove(activeProp);
  509. OnPickUpActiveProp(activeProp);
  510. return true;
  511. }
  512.  
  513. return false;
  514. }
  515. /// <summary>
  516. /// 扔掉当前使用的道具
  517. /// </summary>
  518. public void ThrowActiveProp()
  519. {
  520. ThrowActiveProp(ActivePropsPack.ActiveIndex);
  521. }
  522. /// <summary>
  523. /// 扔掉指定位置上的主动道具
  524. /// </summary>
  525. public void ThrowActiveProp(int index)
  526. {
  527. var activeProp = ActivePropsPack.GetItem(index);
  528. if (activeProp == null)
  529. {
  530. return;
  531. }
  532.  
  533. ActivePropsPack.RemoveItem(index);
  534. OnRemoveActiveProp(activeProp);
  535. //播放抛出效果
  536. activeProp.ThrowProp(this, GlobalPosition);
  537. }
  538.  
  539. /// <summary>
  540. /// 拾起被动道具, 返回是否成功拾起
  541. /// </summary>
  542. /// <param name="buffProp">被动道具对象</param>
  543. public bool PickUpBuffProp(BuffProp buffProp)
  544. {
  545. if (BuffPropPack.Contains(buffProp))
  546. {
  547. Debug.LogError("被动道具已经在背包中了!");
  548. return false;
  549. }
  550. BuffPropPack.Add(buffProp);
  551. buffProp.Master = this;
  552. OnPickUpBuffProp(buffProp);
  553. buffProp.OnPickUpItem();
  554. return true;
  555. }
  556.  
  557. /// <summary>
  558. /// 扔掉指定的被动道具
  559. /// </summary>
  560. /// <param name="buffProp"></param>
  561. public void ThrowBuffProp(BuffProp buffProp)
  562. {
  563. var index = BuffPropPack.IndexOf(buffProp);
  564. if (index < 0)
  565. {
  566. Debug.LogError("当前道具不在角色背包中!");
  567. return;
  568. }
  569. ThrowBuffProp(index);
  570. }
  571. /// <summary>
  572. /// 扔掉指定位置上的被动道具
  573. /// </summary>
  574. public void ThrowBuffProp(int index)
  575. {
  576. if (index < 0 || index >= BuffPropPack.Count)
  577. {
  578. return;
  579. }
  580.  
  581. var buffProp = BuffPropPack[index];
  582. BuffPropPack.RemoveAt(index);
  583. buffProp.OnRemoveItem();
  584. OnRemoveBuffProp(buffProp);
  585. buffProp.Master = null;
  586. //播放抛出效果
  587. buffProp.ThrowProp(this, GlobalPosition);
  588. }
  589. /// <summary>
  590. /// 返回是否存在可互动的物体
  591. /// </summary>
  592. public bool HasInteractive()
  593. {
  594. return InteractiveItem != null;
  595. }
  596.  
  597. /// <summary>
  598. /// 触发与碰撞的物体互动, 并返回与其互动的物体
  599. /// </summary>
  600. public ActivityObject TriggerInteractive()
  601. {
  602. if (HasInteractive())
  603. {
  604. var item = InteractiveItem;
  605. item.Interactive(this);
  606. return item;
  607. }
  608.  
  609. return null;
  610. }
  611. /// <summary>
  612. /// 触发使用道具
  613. /// </summary>
  614. public virtual void UseActiveProp()
  615. {
  616. var activeItem = ActivePropsPack.ActiveItem;
  617. if (activeItem != null)
  618. {
  619. activeItem.Use();
  620. }
  621. }
  622.  
  623. /// <summary>
  624. /// 受到伤害, 如果是在碰撞信号处理函数中调用该函数, 请使用 CallDeferred 来延时调用, 否则很有可能导致报错
  625. /// </summary>
  626. /// <param name="damage">伤害的量</param>
  627. /// <param name="angle">伤害角度(弧度制)</param>
  628. public virtual void Hurt(int damage, float angle)
  629. {
  630. //受伤闪烁, 无敌状态
  631. if (Invincible)
  632. {
  633. return;
  634. }
  635. //计算真正受到的伤害
  636. damage = OnHandlerHurt(damage);
  637. var flag = Shield > 0;
  638. if (flag)
  639. {
  640. Shield -= damage;
  641. }
  642. else
  643. {
  644. damage = RoleState.CalcHurtDamage(damage);
  645. if (damage > 0)
  646. {
  647. Hp -= damage;
  648. }
  649. //播放血液效果
  650. // var packedScene = ResourceManager.Load<PackedScene>(ResourcePath.prefab_effect_Blood_tscn);
  651. // var blood = packedScene.Instance<Blood>();
  652. // blood.GlobalPosition = GlobalPosition;
  653. // blood.Rotation = angle;
  654. // GameApplication.Instance.Node3D.GetRoot().AddChild(blood);
  655. }
  656. OnHit(damage, !flag);
  657.  
  658. //受伤特效
  659. PlayHitAnimation();
  660. //死亡判定
  661. if (Hp <= 0)
  662. {
  663. //死亡
  664. if (!IsDie)
  665. {
  666. IsDie = true;
  667. OnDie();
  668. }
  669. }
  670. }
  671.  
  672. /// <summary>
  673. /// 播放无敌状态闪烁动画
  674. /// </summary>
  675. /// <param name="time">持续时间</param>
  676. public void PlayInvincibleFlashing(float time)
  677. {
  678. Invincible = true;
  679. if (_invincibleFlashingId >= 0) //上一个还没结束
  680. {
  681. StopCoroutine(_invincibleFlashingId);
  682. }
  683.  
  684. _invincibleFlashingId = StartCoroutine(RunInvincibleFlashing(time));
  685. }
  686.  
  687. /// <summary>
  688. /// 停止无敌状态闪烁动画
  689. /// </summary>
  690. public void StopInvincibleFlashing()
  691. {
  692. Invincible = false;
  693. if (_invincibleFlashingId >= 0)
  694. {
  695. StopCoroutine(_invincibleFlashingId);
  696. _invincibleFlashingId = -1;
  697. }
  698. }
  699.  
  700. private IEnumerator RunInvincibleFlashing(float time)
  701. {
  702. yield return new WaitForSeconds(time);
  703. _invincibleFlashingId = -1;
  704. Invincible = false;
  705. }
  706.  
  707. /// <summary>
  708. /// 设置脸的朝向
  709. /// </summary>
  710. private void SetFace(FaceDirection face)
  711. {
  712. if (_face != face)
  713. {
  714. _face = face;
  715. if (face == FaceDirection.Right)
  716. {
  717. RotationDegrees = 0;
  718. Scale = _startScale;
  719. }
  720. else
  721. {
  722. RotationDegrees = 180;
  723. Scale = new Vector2(_startScale.X, -_startScale.Y);
  724. }
  725. }
  726. }
  727. /// <summary>
  728. /// 连接信号: InteractiveArea.BodyEntered
  729. /// 与物体碰撞
  730. /// </summary>
  731. private void _OnPropsEnter(Node2D other)
  732. {
  733. if (other is ActivityObject propObject && !propObject.CollisionWithMask(PhysicsLayer.OnHand))
  734. {
  735. if (!InteractiveItemList.Contains(propObject))
  736. {
  737. InteractiveItemList.Add(propObject);
  738. }
  739. }
  740. }
  741.  
  742. /// <summary>
  743. /// 连接信号: InteractiveArea.BodyExited
  744. /// 物体离开碰撞区域
  745. /// </summary>
  746. private void _OnPropsExit(Node2D other)
  747. {
  748. if (other is ActivityObject propObject)
  749. {
  750. if (InteractiveItemList.Contains(propObject))
  751. {
  752. InteractiveItemList.Remove(propObject);
  753. }
  754. if (InteractiveItem == propObject)
  755. {
  756. var prev = _currentResultData;
  757. _currentResultData = null;
  758. InteractiveItem = null;
  759. ChangeInteractiveItem(prev, null);
  760. }
  761. }
  762. }
  763. /// <summary>
  764. /// 返回当前角色是否是玩家
  765. /// </summary>
  766. public bool IsPlayer()
  767. {
  768. return this == Player.Current;
  769. }
  770. /// <summary>
  771. /// 是否是玩家的敌人
  772. /// </summary>
  773. public bool IsEnemyWithPlayer()
  774. {
  775. return CollisionWithMask(Player.Current.EnemyLayer);
  776. }
  777.  
  778. /// <summary>
  779. /// 将 Role 子节点的旋转角度转换为正常的旋转角度<br/>
  780. /// 因为 Role 受到 Face 影响, 会出现转向动作, 所以需要该函数来转换旋转角度
  781. /// </summary>
  782. /// <param name="rotation">角度, 弧度制</param>
  783. public float ConvertRotation(float rotation)
  784. {
  785. if (Face == FaceDirection.Right)
  786. {
  787. return rotation;
  788. }
  789.  
  790. return Mathf.Pi - rotation;
  791. }
  792.  
  793. protected override void OnDestroy()
  794. {
  795. //销毁道具
  796. foreach (var buffProp in BuffPropPack)
  797. {
  798. buffProp.Destroy();
  799. }
  800. BuffPropPack.Clear();
  801. ActivePropsPack.Destroy();
  802. }
  803. }