Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / role / Role.cs
@小李xl 小李xl on 12 Nov 2022 12 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. /// <summary>
  140. /// 角色身上的状态机
  141. /// </summary>
  142. public StateController<Role> StateController { get; }
  143. //初始缩放
  144. private Vector2 _startScale;
  145. //所有角色碰撞的道具
  146. private readonly List<ActivityObject> _interactiveItemList = new List<ActivityObject>();
  147.  
  148. private CheckInteractiveResult _tempResultData;
  149.  
  150. /// <summary>
  151. /// 可以互动的道具
  152. /// </summary>
  153. protected ActivityObject InteractiveItem { get; private set; }
  154.  
  155. /// <summary>
  156. /// 当血量改变时调用
  157. /// </summary>
  158. protected virtual void OnChangeHp(int hp)
  159. {
  160. }
  161.  
  162. /// <summary>
  163. /// 当最大血量改变时调用
  164. /// </summary>
  165. protected virtual void OnChangeMaxHp(int maxHp)
  166. {
  167. }
  168. /// <summary>
  169. /// 护盾值改变时调用
  170. /// </summary>
  171. protected virtual void OnChangeShield(int shield)
  172. {
  173. }
  174.  
  175. /// <summary>
  176. /// 最大护盾值改变时调用
  177. /// </summary>
  178. protected virtual void OnChangeMaxShield(int maxShield)
  179. {
  180. }
  181.  
  182. /// <summary>
  183. /// 当受伤时调用
  184. /// </summary>
  185. /// <param name="damage">受到的伤害</param>
  186. protected virtual void OnHit(int damage)
  187. {
  188. }
  189.  
  190. /// <summary>
  191. /// 当可互动的物体改变时调用, result 参数为 null 表示变为不可互动
  192. /// </summary>
  193. /// <param name="result">检测是否可互动时的返回值</param>
  194. protected virtual void ChangeInteractiveItem(CheckInteractiveResult result)
  195. {
  196. }
  197.  
  198. /// <summary>
  199. /// 死亡时调用
  200. /// </summary>
  201. protected virtual void OnDie()
  202. {
  203. }
  204. public Role() : this(ResourcePath.prefab_role_Role_tscn)
  205. {
  206. }
  207. public Role(string scenePath) : base(scenePath)
  208. {
  209. Holster = new Holster(this);
  210. StateController = new StateController<Role>();
  211. AddComponent(StateController);
  212. }
  213. public override void _Ready()
  214. {
  215. base._Ready();
  216. AnimationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
  217. _startScale = Scale;
  218. MountPoint = GetNode<MountRotation>("MountPoint");
  219. MountPoint.Master = this;
  220. BackMountPoint = GetNode<Position2D>("BackMountPoint");
  221. //即将删除
  222. if (OverrideTexture != null)
  223. {
  224. // 更改纹理
  225. ChangeFrameTexture(AnimatorNames.Idle, AnimatedSprite);
  226. ChangeFrameTexture(AnimatorNames.Run, AnimatedSprite);
  227. ChangeFrameTexture(AnimatorNames.ReverseRun, AnimatedSprite);
  228. }
  229. Face = FaceDirection.Right;
  230.  
  231. //连接互动物体信号
  232. InteractiveArea = GetNode<Area2D>("InteractiveArea");
  233. InteractiveArea.Connect("area_entered", this, nameof(_OnPropsEnter));
  234. InteractiveArea.Connect("area_exited", this, nameof(_OnPropsExit));
  235. }
  236.  
  237. public override void _Process(float delta)
  238. {
  239. base._Process(delta);
  240. //看向目标
  241. if (LookTarget != null)
  242. {
  243. Vector2 pos = LookTarget.GlobalPosition;
  244. //脸的朝向
  245. var gPos = GlobalPosition;
  246. if (pos.x > gPos.x && Face == FaceDirection.Left)
  247. {
  248. Face = FaceDirection.Right;
  249. }
  250. else if (pos.x < gPos.x && Face == FaceDirection.Right)
  251. {
  252. Face = FaceDirection.Left;
  253. }
  254. //枪口跟随目标
  255. MountPoint.SetLookAt(pos);
  256. }
  257. //检查可互动的道具
  258. bool findFlag = false;
  259. for (int i = 0; i < _interactiveItemList.Count; i++)
  260. {
  261. var item = _interactiveItemList[i];
  262. if (item == null)
  263. {
  264. _interactiveItemList.RemoveAt(i--);
  265. }
  266. else
  267. {
  268. //找到可互动的道具了
  269. if (!findFlag)
  270. {
  271. var result = item.CheckInteractive(this);
  272. if (result.CanInteractive) //可以互动
  273. {
  274. findFlag = true;
  275. if (InteractiveItem != item) //更改互动物体
  276. {
  277. InteractiveItem = item;
  278. ChangeInteractiveItem(result);
  279. }
  280. else if (result.ShowIcon != _tempResultData.ShowIcon) //切换状态
  281. {
  282. ChangeInteractiveItem(result);
  283. }
  284. }
  285. _tempResultData = result;
  286. }
  287. }
  288. }
  289. //没有可互动的道具
  290. if (!findFlag && InteractiveItem != null)
  291. {
  292. InteractiveItem = null;
  293. ChangeInteractiveItem(null);
  294. }
  295. }
  296.  
  297. /// <summary>
  298. /// 判断指定坐标是否在角色视野方向
  299. /// </summary>
  300. public bool IsPositionInForward(Vector2 pos)
  301. {
  302. var gps = GlobalPosition;
  303. return (Face == FaceDirection.Left && pos.x <= gps.x) ||
  304. (Face == FaceDirection.Right && pos.x >= gps.x);
  305. }
  306.  
  307. /// <summary>
  308. /// 计算角色移动
  309. /// </summary>
  310. public virtual void CalcMove(float delta)
  311. {
  312. if (EnableMove && Velocity != Vector2.Zero)
  313. {
  314. Velocity = MoveAndSlide(Velocity);
  315. }
  316. }
  317.  
  318. /// <summary>
  319. /// 拾起一个武器, 并且切换到这个武器
  320. /// </summary>
  321. /// <param name="weapon">武器对象</param>
  322. public virtual void PickUpWeapon(Weapon weapon)
  323. {
  324. if (Holster.PickupWeapon(weapon) != -1)
  325. {
  326. //从可互动队列中移除
  327. _interactiveItemList.Remove(weapon);
  328. }
  329. }
  330.  
  331. /// <summary>
  332. /// 切换到下一个武器
  333. /// </summary>
  334. public virtual void ExchangeNext()
  335. {
  336. Holster.ExchangeNext();
  337. }
  338.  
  339. /// <summary>
  340. /// 切换到上一个武器
  341. /// </summary>
  342. public virtual void ExchangePrev()
  343. {
  344. Holster.ExchangePrev();
  345. }
  346.  
  347. /// <summary>
  348. /// 扔掉当前使用的武器, 切换到上一个武器
  349. /// </summary>
  350. public virtual void ThrowWeapon()
  351. {
  352. var weapon = Holster.RemoveWeapon(Holster.ActiveIndex);
  353. //播放抛出效果
  354. if (weapon != null)
  355. {
  356. weapon.ThrowWeapon(this);
  357. }
  358. }
  359.  
  360. /// <summary>
  361. /// 返回是否存在可互动的物体
  362. /// </summary>
  363. public bool HasInteractive()
  364. {
  365. return InteractiveItem != null;
  366. }
  367.  
  368. /// <summary>
  369. /// 触发与碰撞的物体互动, 并返回与其互动的物体
  370. /// </summary>
  371. public ActivityObject TriggerInteractive()
  372. {
  373. if (HasInteractive())
  374. {
  375. var item = InteractiveItem;
  376. item.Interactive(this);
  377. return item;
  378. }
  379. return null;
  380. }
  381.  
  382. /// <summary>
  383. /// 触发换弹
  384. /// </summary>
  385. public virtual void Reload()
  386. {
  387. if (Holster.ActiveWeapon != null)
  388. {
  389. Holster.ActiveWeapon.Reload();
  390. }
  391. }
  392.  
  393. /// <summary>
  394. /// 触发攻击
  395. /// </summary>
  396. public virtual void Attack()
  397. {
  398. if (Holster.ActiveWeapon != null)
  399. {
  400. Holster.ActiveWeapon.Trigger();
  401. }
  402. }
  403.  
  404. /// <summary>
  405. /// 受到伤害
  406. /// </summary>
  407. /// <param name="damage">伤害的量</param>
  408. public virtual void Hit(int damage)
  409. {
  410. Hp -= damage;
  411. AnimationPlayer.Stop();
  412. AnimationPlayer.Play("hit");
  413. OnHit(damage);
  414. }
  415.  
  416. /// <summary>
  417. /// 设置脸的朝向
  418. /// </summary>
  419. private void SetFace(FaceDirection face)
  420. {
  421. if (_face != face)
  422. {
  423. _face = face;
  424. if (face == FaceDirection.Right)
  425. {
  426. RotationDegrees = 0;
  427. Scale = _startScale;
  428. }
  429. else
  430. {
  431. RotationDegrees = 180;
  432. Scale = new Vector2(_startScale.x, -_startScale.y);
  433. }
  434. }
  435. }
  436.  
  437. /// <summary>
  438. /// 更改指定动画的纹理, 即将删除
  439. /// </summary>
  440. [Obsolete]
  441. private void ChangeFrameTexture(string anim, AnimatedSprite animatedSprite)
  442. {
  443. SpriteFrames spriteFrames = animatedSprite.Frames;
  444. if (spriteFrames != null)
  445. {
  446. int count = spriteFrames.GetFrameCount(anim);
  447. for (int i = 0; i < count; i++)
  448. {
  449. AtlasTexture temp = spriteFrames.GetFrame(anim, i) as AtlasTexture;
  450. temp.Atlas = OverrideTexture;
  451. }
  452. }
  453. }
  454.  
  455. /// <summary>
  456. /// 连接信号: InteractiveArea.area_entered
  457. /// 与物体碰撞
  458. /// </summary>
  459. private void _OnPropsEnter(Area2D other)
  460. {
  461. ActivityObject propObject = other.AsActivityObject();
  462. if (propObject != null)
  463. {
  464. if (!_interactiveItemList.Contains(propObject))
  465. {
  466. _interactiveItemList.Add(propObject);
  467. }
  468. }
  469. }
  470.  
  471. /// <summary>
  472. /// 连接信号: InteractiveArea.area_exited
  473. /// 物体离开碰撞区域
  474. /// </summary>
  475. private void _OnPropsExit(Area2D other)
  476. {
  477. ActivityObject propObject = other.AsActivityObject();
  478. if (propObject != null)
  479. {
  480. if (_interactiveItemList.Contains(propObject))
  481. {
  482. _interactiveItemList.Remove(propObject);
  483. }
  484. if (InteractiveItem == propObject)
  485. {
  486. InteractiveItem = null;
  487. ChangeInteractiveItem(null);
  488. }
  489. }
  490. }
  491. }