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