Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / role / Role.cs
@小李xl 小李xl on 24 Nov 2022 13 KB 敌人身上添加更多武器
  1. using System;
  2. using System.Collections.Generic;
  3. using Godot;
  4.  
  5. /// <summary>
  6. /// 角色基类
  7. /// </summary>
  8. public abstract class Role : ActivityObject
  9. {
  10. /// <summary>
  11. /// 默认攻击对象层级
  12. /// </summary>
  13. public const uint DefaultAttackLayer = PhysicsLayer.Player | PhysicsLayer.Enemy | PhysicsLayer.Wall | PhysicsLayer.Props;
  14. /// <summary>
  15. /// 动画播放器
  16. /// </summary>
  17. public AnimationPlayer AnimationPlayer { get; private set; }
  18. /// <summary>
  19. /// 重写的纹理, 即将删除, 请直接更改 AnimatedSprite.Frames
  20. /// </summary>
  21. [Obsolete]
  22. public Texture OverrideTexture { get; protected set; }
  23.  
  24. /// <summary>
  25. /// 移动速度
  26. /// </summary>
  27. public float MoveSpeed = 120f;
  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<object> PropsPack { get; } = new List<object>();
  43.  
  44. /// <summary>
  45. /// 角色携带的枪套
  46. /// </summary>
  47. public Holster Holster { get; }
  48.  
  49. /// <summary>
  50. /// 武器挂载点
  51. /// </summary>
  52. public MountRotation MountPoint { get; private set; }
  53. /// <summary>
  54. /// 背后武器的挂载点
  55. /// </summary>
  56. public Position2D BackMountPoint { get; private set; }
  57.  
  58. /// <summary>
  59. /// 互动碰撞区域
  60. /// </summary>
  61. public Area2D InteractiveArea { get; private set; }
  62. /// <summary>
  63. /// 脸的朝向
  64. /// </summary>
  65. public FaceDirection Face { get => _face; set => SetFace(value); }
  66. private FaceDirection _face;
  67.  
  68. /// <summary>
  69. /// 是否启用角色移动, 如果禁用, 那么调用 CalcMove() 将不再有任何效果
  70. /// </summary>
  71. public bool EnableMove { get; set; } = true;
  72. /// <summary>
  73. /// 移动速度, 通过调用 CalcMove() 函数来移动
  74. /// </summary>
  75. public Vector2 Velocity { get; set; } = Vector2.Zero;
  76. /// <summary>
  77. /// 血量
  78. /// </summary>
  79. public int Hp
  80. {
  81. get => _hp;
  82. protected set
  83. {
  84. int temp = _hp;
  85. _hp = value;
  86. if (temp != _hp) OnChangeHp(_hp);
  87. }
  88. }
  89. private int _hp = 0;
  90.  
  91. /// <summary>
  92. /// 最大血量
  93. /// </summary>
  94. public int MaxHp
  95. {
  96. get => _maxHp;
  97. protected set
  98. {
  99. int temp = _maxHp;
  100. _maxHp = value;
  101. if (temp != _maxHp) OnChangeMaxHp(_maxHp);
  102. }
  103. }
  104. private int _maxHp = 0;
  105. /// <summary>
  106. /// 当前护盾值
  107. /// </summary>
  108. public int Shield
  109. {
  110. get => _shield;
  111. protected set
  112. {
  113. int temp = _shield;
  114. _shield = value;
  115. if (temp != _shield) OnChangeShield(_shield);
  116. }
  117. }
  118. private int _shield = 0;
  119.  
  120. /// <summary>
  121. /// 最大护盾值
  122. /// </summary>
  123. public int MaxShield
  124. {
  125. get => _maxShield;
  126. protected set
  127. {
  128. int temp = _maxShield;
  129. _maxShield = value;
  130. if (temp != _maxShield) OnChangeMaxShield(_maxShield);
  131. }
  132. }
  133. private int _maxShield = 0;
  134.  
  135. /// <summary>
  136. /// 当前角色所看向的对象, 也就是枪口指向的对象
  137. /// </summary>
  138. public ActivityObject LookTarget { get; set; }
  139.  
  140. //初始缩放
  141. private Vector2 _startScale;
  142. //所有角色碰撞的道具
  143. private readonly List<ActivityObject> _interactiveItemList = new List<ActivityObject>();
  144.  
  145. private CheckInteractiveResult _tempResultData;
  146.  
  147. /// <summary>
  148. /// 可以互动的道具
  149. /// </summary>
  150. protected ActivityObject InteractiveItem { get; private set; }
  151.  
  152. /// <summary>
  153. /// 当血量改变时调用
  154. /// </summary>
  155. protected virtual void OnChangeHp(int hp)
  156. {
  157. }
  158.  
  159. /// <summary>
  160. /// 当最大血量改变时调用
  161. /// </summary>
  162. protected virtual void OnChangeMaxHp(int maxHp)
  163. {
  164. }
  165. /// <summary>
  166. /// 护盾值改变时调用
  167. /// </summary>
  168. protected virtual void OnChangeShield(int shield)
  169. {
  170. }
  171.  
  172. /// <summary>
  173. /// 最大护盾值改变时调用
  174. /// </summary>
  175. protected virtual void OnChangeMaxShield(int maxShield)
  176. {
  177. }
  178.  
  179. /// <summary>
  180. /// 当受伤时调用
  181. /// </summary>
  182. /// <param name="damage">受到的伤害</param>
  183. protected virtual void OnHit(int damage)
  184. {
  185. }
  186.  
  187. /// <summary>
  188. /// 当可互动的物体改变时调用, result 参数为 null 表示变为不可互动
  189. /// </summary>
  190. /// <param name="result">检测是否可互动时的返回值</param>
  191. protected virtual void ChangeInteractiveItem(CheckInteractiveResult result)
  192. {
  193. }
  194.  
  195. /// <summary>
  196. /// 死亡时调用
  197. /// </summary>
  198. protected virtual void OnDie()
  199. {
  200. }
  201. public Role() : this(ResourcePath.prefab_role_Role_tscn)
  202. {
  203. }
  204. public Role(string scenePath) : base(scenePath)
  205. {
  206. Holster = new Holster(this);
  207. }
  208. public override void _Ready()
  209. {
  210. base._Ready();
  211. AnimationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
  212. _startScale = Scale;
  213. MountPoint = GetNode<MountRotation>("MountPoint");
  214. MountPoint.Master = this;
  215. BackMountPoint = GetNode<Position2D>("BackMountPoint");
  216. //即将删除
  217. if (OverrideTexture != null)
  218. {
  219. // 更改纹理
  220. ChangeFrameTexture(AnimatorNames.Idle, AnimatedSprite);
  221. ChangeFrameTexture(AnimatorNames.Run, AnimatedSprite);
  222. ChangeFrameTexture(AnimatorNames.ReverseRun, AnimatedSprite);
  223. }
  224. Face = FaceDirection.Right;
  225.  
  226. //连接互动物体信号
  227. InteractiveArea = GetNode<Area2D>("InteractiveArea");
  228. InteractiveArea.Connect("area_entered", this, nameof(_OnPropsEnter));
  229. InteractiveArea.Connect("area_exited", this, nameof(_OnPropsExit));
  230. }
  231.  
  232. public override void _Process(float delta)
  233. {
  234. base._Process(delta);
  235. //看向目标
  236. if (LookTarget != null)
  237. {
  238. Vector2 pos = LookTarget.GlobalPosition;
  239. //脸的朝向
  240. var gPos = GlobalPosition;
  241. if (pos.x > gPos.x && Face == FaceDirection.Left)
  242. {
  243. Face = FaceDirection.Right;
  244. }
  245. else if (pos.x < gPos.x && Face == FaceDirection.Right)
  246. {
  247. Face = FaceDirection.Left;
  248. }
  249. //枪口跟随目标
  250. MountPoint.SetLookAt(pos);
  251. }
  252. //检查可互动的道具
  253. bool findFlag = false;
  254. for (int i = 0; i < _interactiveItemList.Count; i++)
  255. {
  256. var item = _interactiveItemList[i];
  257. if (item == null)
  258. {
  259. _interactiveItemList.RemoveAt(i--);
  260. }
  261. else
  262. {
  263. //找到可互动的道具了
  264. if (!findFlag)
  265. {
  266. var result = item.CheckInteractive(this);
  267. if (result.CanInteractive) //可以互动
  268. {
  269. findFlag = true;
  270. if (InteractiveItem != item) //更改互动物体
  271. {
  272. InteractiveItem = item;
  273. ChangeInteractiveItem(result);
  274. }
  275. else if (result.ShowIcon != _tempResultData.ShowIcon) //切换状态
  276. {
  277. ChangeInteractiveItem(result);
  278. }
  279. }
  280. _tempResultData = result;
  281. }
  282. }
  283. }
  284. //没有可互动的道具
  285. if (!findFlag && InteractiveItem != null)
  286. {
  287. InteractiveItem = null;
  288. ChangeInteractiveItem(null);
  289. }
  290. }
  291.  
  292. /// <summary>
  293. /// 使角色看向指定的坐标,
  294. /// 注意, 调用该函数会清空 LookTarget, 因为拥有 LookTarget 时也会每帧更新玩家视野位置
  295. /// </summary>
  296. /// <param name="pos"></param>
  297. public void LookTargetPosition(Vector2 pos)
  298. {
  299. LookTarget = null;
  300. //脸的朝向
  301. var gPos = GlobalPosition;
  302. if (pos.x > gPos.x && Face == FaceDirection.Left)
  303. {
  304. Face = FaceDirection.Right;
  305. }
  306. else if (pos.x < gPos.x && Face == FaceDirection.Right)
  307. {
  308. Face = FaceDirection.Left;
  309. }
  310. //枪口跟随目标
  311. MountPoint.SetLookAt(pos);
  312. }
  313. /// <summary>
  314. /// 判断指定坐标是否在角色视野方向
  315. /// </summary>
  316. public bool IsPositionInForward(Vector2 pos)
  317. {
  318. var gps = GlobalPosition;
  319. return (Face == FaceDirection.Left && pos.x <= gps.x) ||
  320. (Face == FaceDirection.Right && pos.x >= gps.x);
  321. }
  322.  
  323. /// <summary>
  324. /// 计算角色移动
  325. /// </summary>
  326. public virtual void CalcMove(float delta)
  327. {
  328. if (EnableMove && Velocity != Vector2.Zero)
  329. {
  330. Velocity = MoveAndSlide(Velocity);
  331. }
  332. }
  333.  
  334. /// <summary>
  335. /// 拾起一个武器, 并且切换到这个武器, 返回是否成功拾取
  336. /// </summary>
  337. /// <param name="weapon">武器对象</param>
  338. public virtual bool PickUpWeapon(Weapon weapon)
  339. {
  340. if (Holster.PickupWeapon(weapon) != -1)
  341. {
  342. //从可互动队列中移除
  343. _interactiveItemList.Remove(weapon);
  344. return true;
  345. }
  346.  
  347. return false;
  348. }
  349.  
  350. /// <summary>
  351. /// 切换到下一个武器
  352. /// </summary>
  353. public virtual void ExchangeNext()
  354. {
  355. Holster.ExchangeNext();
  356. }
  357.  
  358. /// <summary>
  359. /// 切换到上一个武器
  360. /// </summary>
  361. public virtual void ExchangePrev()
  362. {
  363. Holster.ExchangePrev();
  364. }
  365.  
  366. /// <summary>
  367. /// 扔掉当前使用的武器, 切换到上一个武器
  368. /// </summary>
  369. public virtual void ThrowWeapon()
  370. {
  371. var weapon = Holster.RemoveWeapon(Holster.ActiveIndex);
  372. //播放抛出效果
  373. if (weapon != null)
  374. {
  375. weapon.ThrowWeapon(this);
  376. }
  377. }
  378.  
  379. /// <summary>
  380. /// 返回是否存在可互动的物体
  381. /// </summary>
  382. public bool HasInteractive()
  383. {
  384. return InteractiveItem != null;
  385. }
  386.  
  387. /// <summary>
  388. /// 触发与碰撞的物体互动, 并返回与其互动的物体
  389. /// </summary>
  390. public ActivityObject TriggerInteractive()
  391. {
  392. if (HasInteractive())
  393. {
  394. var item = InteractiveItem;
  395. item.Interactive(this);
  396. return item;
  397. }
  398. return null;
  399. }
  400.  
  401. /// <summary>
  402. /// 触发换弹
  403. /// </summary>
  404. public virtual void Reload()
  405. {
  406. if (Holster.ActiveWeapon != null)
  407. {
  408. Holster.ActiveWeapon.Reload();
  409. }
  410. }
  411.  
  412. /// <summary>
  413. /// 触发攻击
  414. /// </summary>
  415. public virtual void Attack()
  416. {
  417. if (Holster.ActiveWeapon != null)
  418. {
  419. Holster.ActiveWeapon.Trigger();
  420. }
  421. }
  422.  
  423. /// <summary>
  424. /// 受到伤害
  425. /// </summary>
  426. /// <param name="damage">伤害的量</param>
  427. public virtual void Hurt(int damage)
  428. {
  429. Hp -= damage;
  430. AnimationPlayer.Stop();
  431. AnimationPlayer.Play("hit");
  432. OnHit(damage);
  433. }
  434.  
  435. /// <summary>
  436. /// 设置脸的朝向
  437. /// </summary>
  438. private void SetFace(FaceDirection face)
  439. {
  440. if (_face != face)
  441. {
  442. _face = face;
  443. if (face == FaceDirection.Right)
  444. {
  445. RotationDegrees = 0;
  446. Scale = _startScale;
  447. }
  448. else
  449. {
  450. RotationDegrees = 180;
  451. Scale = new Vector2(_startScale.x, -_startScale.y);
  452. }
  453. }
  454. }
  455.  
  456. /// <summary>
  457. /// 更改指定动画的纹理, 即将删除
  458. /// </summary>
  459. [Obsolete]
  460. private void ChangeFrameTexture(string anim, AnimatedSprite animatedSprite)
  461. {
  462. SpriteFrames spriteFrames = animatedSprite.Frames;
  463. if (spriteFrames != null)
  464. {
  465. int count = spriteFrames.GetFrameCount(anim);
  466. for (int i = 0; i < count; i++)
  467. {
  468. AtlasTexture temp = spriteFrames.GetFrame(anim, i) as AtlasTexture;
  469. temp.Atlas = OverrideTexture;
  470. }
  471. }
  472. }
  473.  
  474. /// <summary>
  475. /// 连接信号: InteractiveArea.area_entered
  476. /// 与物体碰撞
  477. /// </summary>
  478. private void _OnPropsEnter(Area2D other)
  479. {
  480. ActivityObject propObject = other.AsActivityObject();
  481. if (propObject != null)
  482. {
  483. if (!_interactiveItemList.Contains(propObject))
  484. {
  485. _interactiveItemList.Add(propObject);
  486. }
  487. }
  488. }
  489.  
  490. /// <summary>
  491. /// 连接信号: InteractiveArea.area_exited
  492. /// 物体离开碰撞区域
  493. /// </summary>
  494. private void _OnPropsExit(Area2D other)
  495. {
  496. ActivityObject propObject = other.AsActivityObject();
  497. if (propObject != null)
  498. {
  499. if (_interactiveItemList.Contains(propObject))
  500. {
  501. _interactiveItemList.Remove(propObject);
  502. }
  503. if (InteractiveItem == propObject)
  504. {
  505. InteractiveItem = null;
  506. ChangeInteractiveItem(null);
  507. }
  508. }
  509. }
  510. }