Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / role / Role.cs
  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. /// <summary>
  208. /// 角色看向的坐标
  209. /// </summary>
  210. public Vector2 LookPosition { get; protected set; }
  211. //初始缩放
  212. private Vector2 _startScale;
  213. //当前可互动的物体
  214. private CheckInteractiveResult _currentResultData;
  215. private uint _currentLayer;
  216. //闪烁计时器
  217. private float _flashingInvincibleTimer = -1;
  218. //闪烁状态
  219. private bool _flashingInvincibleFlag = false;
  220. //闪烁动画协程id
  221. private long _invincibleFlashingId = -1;
  222. //护盾恢复计时器
  223. private float _shieldRecoveryTimer = 0;
  224.  
  225. /// <summary>
  226. /// 当血量改变时调用
  227. /// </summary>
  228. protected virtual void OnChangeHp(int hp)
  229. {
  230. }
  231.  
  232. /// <summary>
  233. /// 当最大血量改变时调用
  234. /// </summary>
  235. protected virtual void OnChangeMaxHp(int maxHp)
  236. {
  237. }
  238. /// <summary>
  239. /// 护盾值改变时调用
  240. /// </summary>
  241. protected virtual void OnChangeShield(int shield)
  242. {
  243. }
  244.  
  245. /// <summary>
  246. /// 最大护盾值改变时调用
  247. /// </summary>
  248. protected virtual void OnChangeMaxShield(int maxShield)
  249. {
  250. }
  251.  
  252. /// <summary>
  253. /// 当护盾被破坏时调用
  254. /// </summary>
  255. protected virtual void OnShieldDestroy()
  256. {
  257. }
  258.  
  259. /// <summary>
  260. /// 当受伤时调用
  261. /// </summary>
  262. /// <param name="damage">受到的伤害</param>
  263. /// <param name="realHarm">是否受到真实伤害, 如果为false, 则表示该伤害被互动格挡掉了</param>
  264. protected virtual void OnHit(int damage, bool realHarm)
  265. {
  266. }
  267.  
  268. /// <summary>
  269. /// 受到伤害时调用, 用于改变受到的伤害值
  270. /// </summary>
  271. /// <param name="damage">受到的伤害</param>
  272. protected virtual int OnHandlerHurt(int damage)
  273. {
  274. return damage;
  275. }
  276. /// <summary>
  277. /// 当可互动的物体改变时调用, result 参数为 null 表示变为不可互动
  278. /// </summary>
  279. /// <param name="prev">上一个互动的物体</param>
  280. /// <param name="result">当前物体, 检测是否可互动时的返回值</param>
  281. protected virtual void ChangeInteractiveItem(CheckInteractiveResult prev, CheckInteractiveResult result)
  282. {
  283. }
  284.  
  285. /// <summary>
  286. /// 死亡时调用
  287. /// </summary>
  288. protected virtual void OnDie()
  289. {
  290. }
  291. /// <summary>
  292. /// 当拾起某个主动道具时调用
  293. /// </summary>
  294. protected virtual void OnPickUpActiveProp(ActiveProp activeProp)
  295. {
  296. }
  297.  
  298. /// <summary>
  299. /// 当移除某个主动道具时调用
  300. /// </summary>
  301. protected virtual void OnRemoveActiveProp(ActiveProp activeProp)
  302. {
  303. }
  304. /// <summary>
  305. /// 当切换到某个主动道具时调用
  306. /// </summary>
  307. protected virtual void OnExchangeActiveProp(ActiveProp activeProp)
  308. {
  309. }
  310. /// <summary>
  311. /// 当拾起某个被动道具时调用
  312. /// </summary>
  313. protected virtual void OnPickUpBuffProp(BuffProp buffProp)
  314. {
  315. }
  316.  
  317. /// <summary>
  318. /// 当移除某个被动道具时调用
  319. /// </summary>
  320. protected virtual void OnRemoveBuffProp(BuffProp buffProp)
  321. {
  322. }
  323. /// <summary>
  324. /// 触发攻击
  325. /// </summary>
  326. public virtual void Attack()
  327. {
  328. }
  329. public override void OnInit()
  330. {
  331. ActivePropsPack = AddComponent<Package<ActiveProp, Role>>();
  332. ActivePropsPack.SetCapacity(1);
  333. _startScale = Scale;
  334. HurtArea.CollisionLayer = CollisionLayer;
  335. HurtArea.CollisionMask = 0;
  336. _currentLayer = HurtArea.CollisionLayer;
  337. Face = FaceDirection.Right;
  338. //连接互动物体信号
  339. InteractiveArea.BodyEntered += _OnPropsEnter;
  340. InteractiveArea.BodyExited += _OnPropsExit;
  341. }
  342.  
  343. protected override void Process(float delta)
  344. {
  345. //检查可互动的物体
  346. bool findFlag = false;
  347. for (int i = 0; i < InteractiveItemList.Count; i++)
  348. {
  349. var item = InteractiveItemList[i];
  350. if (item == null || item.IsDestroyed)
  351. {
  352. InteractiveItemList.RemoveAt(i--);
  353. }
  354. else if (!item.IsThrowing)
  355. {
  356. //找到可互动的物体了
  357. if (!findFlag)
  358. {
  359. var result = item.CheckInteractive(this);
  360. var prev = _currentResultData;
  361. _currentResultData = result;
  362. if (result.CanInteractive) //可以互动
  363. {
  364. findFlag = true;
  365. if (InteractiveItem != item) //更改互动物体
  366. {
  367. InteractiveItem = item;
  368. ChangeInteractiveItem(prev, result);
  369. }
  370. else if (result.Type != _currentResultData.Type) //切换状态
  371. {
  372. ChangeInteractiveItem(prev, result);
  373. }
  374. }
  375. }
  376. }
  377. }
  378. //没有可互动的物体
  379. if (!findFlag && InteractiveItem != null)
  380. {
  381. var prev = _currentResultData;
  382. _currentResultData = null;
  383. InteractiveItem = null;
  384. ChangeInteractiveItem(prev, null);
  385. }
  386.  
  387. //无敌状态, 播放闪烁动画
  388. if (Invincible)
  389. {
  390. _flashingInvincibleTimer -= delta;
  391. if (_flashingInvincibleTimer <= 0)
  392. {
  393. _flashingInvincibleTimer = 0.15f;
  394. if (_flashingInvincibleFlag)
  395. {
  396. _flashingInvincibleFlag = false;
  397. SetBlendModulate(new Color(1, 1, 1, 0.7f));
  398. }
  399. else
  400. {
  401. _flashingInvincibleFlag = true;
  402. SetBlendModulate(new Color(1, 1, 1, 0));
  403. }
  404. }
  405.  
  406. _shieldRecoveryTimer = 0;
  407. }
  408. else //恢复护盾
  409. {
  410. if (Shield < MaxShield)
  411. {
  412. _shieldRecoveryTimer += delta;
  413. if (_shieldRecoveryTimer >= RoleState.ShieldRecoveryTime) //时间到, 恢复
  414. {
  415. Shield++;
  416. _shieldRecoveryTimer = 0;
  417. }
  418. }
  419. else
  420. {
  421. _shieldRecoveryTimer = 0;
  422. }
  423. }
  424.  
  425. //被动道具更新
  426. if (BuffPropPack.Count > 0)
  427. {
  428. var buffProps = BuffPropPack.ToArray();
  429. foreach (var prop in buffProps)
  430. {
  431. if (!prop.IsDestroyed)
  432. {
  433. prop.PackProcess(delta);
  434. }
  435. }
  436. }
  437. //主动道具调用更新
  438. var props = ActivePropsPack.ItemSlot;
  439. if (props.Length > 0)
  440. {
  441. props = (ActiveProp[])props.Clone();
  442. foreach (var prop in props)
  443. {
  444. if (prop != null && !prop.IsDestroyed)
  445. {
  446. prop.PackProcess(delta);
  447. }
  448. }
  449. }
  450. }
  451. /// <summary>
  452. /// 初始化瞄准辅助线
  453. /// </summary>
  454. public void InitSubLine()
  455. {
  456. if (SubLine != null)
  457. {
  458. return;
  459. }
  460.  
  461. SubLine = AddComponent<SubLine>();
  462. }
  463. /// <summary>
  464. /// 是否是满血
  465. /// </summary>
  466. public bool IsHpFull()
  467. {
  468. return Hp >= MaxHp;
  469. }
  470. /// <summary>
  471. /// 获取当前角色的中心点坐标
  472. /// </summary>
  473. public virtual Vector2 GetCenterPosition()
  474. {
  475. return AnimatedSprite.GlobalPosition;
  476. }
  477. /// <summary>
  478. /// 使角色看向指定的坐标的方向
  479. /// </summary>
  480. public virtual void LookTargetPosition(Vector2 pos)
  481. {
  482. LookPosition = pos;
  483. //脸的朝向
  484. var gPos = Position;
  485. if (pos.X > gPos.X && Face == FaceDirection.Left)
  486. {
  487. Face = FaceDirection.Right;
  488. }
  489. else if (pos.X < gPos.X && Face == FaceDirection.Right)
  490. {
  491. Face = FaceDirection.Left;
  492. }
  493. }
  494. /// <summary>
  495. /// 判断指定坐标是否在角色视野方向
  496. /// </summary>
  497. public bool IsPositionInForward(Vector2 pos)
  498. {
  499. var gps = GlobalPosition;
  500. return (Face == FaceDirection.Left && pos.X <= gps.X) ||
  501. (Face == FaceDirection.Right && pos.X >= gps.X);
  502. }
  503. /// <summary>
  504. /// 拾起主动道具, 返回是否成功拾起, 如果不想立刻切换到该道具, exchange 请传 false
  505. /// </summary>
  506. /// <param name="activeProp">主动道具对象</param>
  507. /// <param name="exchange">是否立即切换到该道具, 默认 true </param>
  508. public bool PickUpActiveProp(ActiveProp activeProp, bool exchange = true)
  509. {
  510. if (ActivePropsPack.PickupItem(activeProp, exchange) != -1)
  511. {
  512. //从可互动队列中移除
  513. InteractiveItemList.Remove(activeProp);
  514. OnPickUpActiveProp(activeProp);
  515. return true;
  516. }
  517.  
  518. return false;
  519. }
  520. /// <summary>
  521. /// 扔掉当前使用的道具
  522. /// </summary>
  523. public void ThrowActiveProp()
  524. {
  525. ThrowActiveProp(ActivePropsPack.ActiveIndex);
  526. }
  527. /// <summary>
  528. /// 扔掉指定位置上的主动道具
  529. /// </summary>
  530. public void ThrowActiveProp(int index)
  531. {
  532. var activeProp = ActivePropsPack.GetItem(index);
  533. if (activeProp == null)
  534. {
  535. return;
  536. }
  537.  
  538. ActivePropsPack.RemoveItem(index);
  539. OnRemoveActiveProp(activeProp);
  540. //播放抛出效果
  541. activeProp.ThrowProp(this, GlobalPosition);
  542. }
  543.  
  544. /// <summary>
  545. /// 拾起被动道具, 返回是否成功拾起
  546. /// </summary>
  547. /// <param name="buffProp">被动道具对象</param>
  548. public bool PickUpBuffProp(BuffProp buffProp)
  549. {
  550. if (BuffPropPack.Contains(buffProp))
  551. {
  552. Debug.LogError("被动道具已经在背包中了!");
  553. return false;
  554. }
  555. BuffPropPack.Add(buffProp);
  556. buffProp.Master = this;
  557. OnPickUpBuffProp(buffProp);
  558. buffProp.OnPickUpItem();
  559. return true;
  560. }
  561.  
  562. /// <summary>
  563. /// 扔掉指定的被动道具
  564. /// </summary>
  565. /// <param name="buffProp"></param>
  566. public void ThrowBuffProp(BuffProp buffProp)
  567. {
  568. var index = BuffPropPack.IndexOf(buffProp);
  569. if (index < 0)
  570. {
  571. Debug.LogError("当前道具不在角色背包中!");
  572. return;
  573. }
  574. ThrowBuffProp(index);
  575. }
  576. /// <summary>
  577. /// 扔掉指定位置上的被动道具
  578. /// </summary>
  579. public void ThrowBuffProp(int index)
  580. {
  581. if (index < 0 || index >= BuffPropPack.Count)
  582. {
  583. return;
  584. }
  585.  
  586. var buffProp = BuffPropPack[index];
  587. BuffPropPack.RemoveAt(index);
  588. buffProp.OnRemoveItem();
  589. OnRemoveBuffProp(buffProp);
  590. buffProp.Master = null;
  591. //播放抛出效果
  592. buffProp.ThrowProp(this, GlobalPosition);
  593. }
  594. /// <summary>
  595. /// 返回是否存在可互动的物体
  596. /// </summary>
  597. public bool HasInteractive()
  598. {
  599. return InteractiveItem != null;
  600. }
  601.  
  602. /// <summary>
  603. /// 触发与碰撞的物体互动, 并返回与其互动的物体
  604. /// </summary>
  605. public ActivityObject TriggerInteractive()
  606. {
  607. if (HasInteractive())
  608. {
  609. var item = InteractiveItem;
  610. item.Interactive(this);
  611. return item;
  612. }
  613.  
  614. return null;
  615. }
  616. /// <summary>
  617. /// 触发使用道具
  618. /// </summary>
  619. public virtual void UseActiveProp()
  620. {
  621. var activeItem = ActivePropsPack.ActiveItem;
  622. if (activeItem != null)
  623. {
  624. activeItem.Use();
  625. }
  626. }
  627.  
  628. /// <summary>
  629. /// 受到伤害, 如果是在碰撞信号处理函数中调用该函数, 请使用 CallDeferred 来延时调用, 否则很有可能导致报错
  630. /// </summary>
  631. /// <param name="damage">伤害的量</param>
  632. /// <param name="angle">伤害角度(弧度制)</param>
  633. public virtual void Hurt(int damage, float angle)
  634. {
  635. //受伤闪烁, 无敌状态
  636. if (Invincible)
  637. {
  638. return;
  639. }
  640. //计算真正受到的伤害
  641. damage = OnHandlerHurt(damage);
  642. var flag = Shield > 0;
  643. if (flag)
  644. {
  645. Shield -= damage;
  646. }
  647. else
  648. {
  649. damage = RoleState.CalcHurtDamage(damage);
  650. if (damage > 0)
  651. {
  652. Hp -= damage;
  653. }
  654. //播放血液效果
  655. // var packedScene = ResourceManager.Load<PackedScene>(ResourcePath.prefab_effect_Blood_tscn);
  656. // var blood = packedScene.Instance<Blood>();
  657. // blood.GlobalPosition = GlobalPosition;
  658. // blood.Rotation = angle;
  659. // GameApplication.Instance.Node3D.GetRoot().AddChild(blood);
  660. }
  661. OnHit(damage, !flag);
  662.  
  663. //受伤特效
  664. PlayHitAnimation();
  665. //死亡判定
  666. if (Hp <= 0)
  667. {
  668. //死亡
  669. if (!IsDie)
  670. {
  671. IsDie = true;
  672. OnDie();
  673. }
  674. }
  675. }
  676.  
  677. /// <summary>
  678. /// 播放无敌状态闪烁动画
  679. /// </summary>
  680. /// <param name="time">持续时间</param>
  681. public void PlayInvincibleFlashing(float time)
  682. {
  683. Invincible = true;
  684. if (_invincibleFlashingId >= 0) //上一个还没结束
  685. {
  686. StopCoroutine(_invincibleFlashingId);
  687. }
  688.  
  689. _invincibleFlashingId = StartCoroutine(RunInvincibleFlashing(time));
  690. }
  691.  
  692. /// <summary>
  693. /// 停止无敌状态闪烁动画
  694. /// </summary>
  695. public void StopInvincibleFlashing()
  696. {
  697. Invincible = false;
  698. if (_invincibleFlashingId >= 0)
  699. {
  700. StopCoroutine(_invincibleFlashingId);
  701. _invincibleFlashingId = -1;
  702. }
  703. }
  704.  
  705. private IEnumerator RunInvincibleFlashing(float time)
  706. {
  707. yield return new WaitForSeconds(time);
  708. _invincibleFlashingId = -1;
  709. Invincible = false;
  710. }
  711.  
  712. /// <summary>
  713. /// 设置脸的朝向
  714. /// </summary>
  715. private void SetFace(FaceDirection face)
  716. {
  717. if (_face != face)
  718. {
  719. _face = face;
  720. if (face == FaceDirection.Right)
  721. {
  722. RotationDegrees = 0;
  723. Scale = _startScale;
  724. }
  725. else
  726. {
  727. RotationDegrees = 180;
  728. Scale = new Vector2(_startScale.X, -_startScale.Y);
  729. }
  730. }
  731. }
  732. /// <summary>
  733. /// 连接信号: InteractiveArea.BodyEntered
  734. /// 与物体碰撞
  735. /// </summary>
  736. private void _OnPropsEnter(Node2D other)
  737. {
  738. if (other is ActivityObject propObject && !propObject.CollisionWithMask(PhysicsLayer.OnHand))
  739. {
  740. if (!InteractiveItemList.Contains(propObject))
  741. {
  742. InteractiveItemList.Add(propObject);
  743. }
  744. }
  745. }
  746.  
  747. /// <summary>
  748. /// 连接信号: InteractiveArea.BodyExited
  749. /// 物体离开碰撞区域
  750. /// </summary>
  751. private void _OnPropsExit(Node2D other)
  752. {
  753. if (other is ActivityObject propObject)
  754. {
  755. if (InteractiveItemList.Contains(propObject))
  756. {
  757. InteractiveItemList.Remove(propObject);
  758. }
  759. if (InteractiveItem == propObject)
  760. {
  761. var prev = _currentResultData;
  762. _currentResultData = null;
  763. InteractiveItem = null;
  764. ChangeInteractiveItem(prev, null);
  765. }
  766. }
  767. }
  768. /// <summary>
  769. /// 返回当前角色是否是玩家
  770. /// </summary>
  771. public bool IsPlayer()
  772. {
  773. return this == Player.Current;
  774. }
  775. /// <summary>
  776. /// 是否是玩家的敌人
  777. /// </summary>
  778. public bool IsEnemyWithPlayer()
  779. {
  780. return CollisionWithMask(Player.Current.EnemyLayer);
  781. }
  782.  
  783. /// <summary>
  784. /// 将 Role 子节点的旋转角度转换为正常的旋转角度<br/>
  785. /// 因为 Role 受到 Face 影响, 会出现转向动作, 所以需要该函数来转换旋转角度
  786. /// </summary>
  787. /// <param name="rotation">角度, 弧度制</param>
  788. public float ConvertRotation(float rotation)
  789. {
  790. if (Face == FaceDirection.Right)
  791. {
  792. return rotation;
  793. }
  794.  
  795. return Mathf.Pi - rotation;
  796. }
  797.  
  798. /// <summary>
  799. /// 获取开火点高度
  800. /// </summary>
  801. public virtual float GetFirePointAltitude()
  802. {
  803. return -AnimatedSprite.Position.Y;
  804. }
  805. protected override void OnDestroy()
  806. {
  807. //销毁道具
  808. foreach (var buffProp in BuffPropPack)
  809. {
  810. buffProp.Destroy();
  811. }
  812. BuffPropPack.Clear();
  813. ActivePropsPack.Destroy();
  814. }
  815. }