Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / role / enemy / Enemy.cs
  1.  
  2. using System;
  3. using Config;
  4. using Godot;
  5. using NnormalState;
  6.  
  7. /// <summary>
  8. /// 基础敌人
  9. /// </summary>
  10. [Tool]
  11. public partial class Enemy : Role
  12. {
  13. /// <summary>
  14. /// 目标是否在视野内
  15. /// </summary>
  16. public bool TargetInView { get; set; } = true;
  17. /// <summary>
  18. /// 敌人身上的状态机控制器
  19. /// </summary>
  20. public StateController<Enemy, AiStateEnum> StateController { get; private set; }
  21.  
  22. /// <summary>
  23. /// 视野半径, 单位像素, 发现玩家后改视野范围可以穿墙
  24. /// </summary>
  25. public float ViewRange { get; set; } = 250;
  26.  
  27. /// <summary>
  28. /// 发现玩家后的视野半径
  29. /// </summary>
  30. public float TailAfterViewRange { get; set; } = 400;
  31.  
  32. /// <summary>
  33. /// 背后的视野半径, 单位像素
  34. /// </summary>
  35. public float BackViewRange { get; set; } = 50;
  36.  
  37. /// <summary>
  38. /// 视野检测射线, 朝玩家打射线, 检测是否碰到墙
  39. /// </summary>
  40. [Export, ExportFillNode]
  41. public RayCast2D ViewRay { get; private set; }
  42.  
  43. /// <summary>
  44. /// 导航代理
  45. /// </summary>
  46. [Export, ExportFillNode]
  47. public NavigationAgent2D NavigationAgent2D { get; private set; }
  48.  
  49. /// <summary>
  50. /// 导航代理中点
  51. /// </summary>
  52. [Export, ExportFillNode]
  53. public Marker2D NavigationPoint { get; private set; }
  54. /// <summary>
  55. /// 开火位置
  56. /// </summary>
  57. [Export, ExportFillNode]
  58. public Marker2D FirePoint { get; private set; }
  59.  
  60. /// <summary>
  61. /// Ai攻击状态, 调用 Attack() 函数后会刷新
  62. /// </summary>
  63. public AiAttackState AttackState { get; private set; }
  64.  
  65. /// <summary>
  66. /// 攻击时间间隔
  67. /// </summary>
  68. public float AttackInterval { get; set; } = 3;
  69.  
  70. /// <summary>
  71. /// 锁定目标需要消耗的时间
  72. /// </summary>
  73. public float LockingTime { get; set; } = 2;
  74. /// <summary>
  75. /// 当前敌人所看向的对象, 也就是枪口指向的对象
  76. /// </summary>
  77. public ActivityObject LookTarget { get; set; }
  78. //锁定目标时间
  79. private float _lockTargetTime = 0;
  80. //攻击冷却计时器
  81. private float _attackTimer = 0;
  82.  
  83. public override void OnInit()
  84. {
  85. base.OnInit();
  86. IsAi = true;
  87. StateController = AddComponent<StateController<Enemy, AiStateEnum>>();
  88.  
  89. AttackLayer = PhysicsLayer.Wall | PhysicsLayer.Player;
  90. EnemyLayer = PhysicsLayer.Player;
  91. Camp = CampEnum.Camp2;
  92.  
  93. RoleState.MoveSpeed = 20;
  94.  
  95. MaxHp = 20;
  96. Hp = 20;
  97. StateController.Register(new AiNormalState());
  98. StateController.Register(new AiTailAfterState());
  99. StateController.Register(new AiFollowUpState());
  100. StateController.ChangeState(AiStateEnum.AiNormal);
  101. }
  102.  
  103. public override void EnterTree()
  104. {
  105. if (!World.Enemy_InstanceList.Contains(this))
  106. {
  107. World.Enemy_InstanceList.Add(this);
  108. }
  109. }
  110.  
  111. public override void ExitTree()
  112. {
  113. World.Enemy_InstanceList.Remove(this);
  114. }
  115.  
  116. public override void Attack()
  117. {
  118. if (_attackTimer > 0) //开火间隙
  119. {
  120. AttackState = AiAttackState.AttackInterval;
  121. }
  122. else if (GetLockRemainderTime() > 0) //锁定目标时间
  123. {
  124. AttackState = AiAttackState.LockingTime;
  125. }
  126. else //正常攻击
  127. {
  128. AttackState = AiAttackState.Attack;
  129. _attackTimer = AttackInterval;
  130. EnemyAttack();
  131. }
  132. }
  133.  
  134. /// <summary>
  135. /// 敌人发动攻击
  136. /// </summary>
  137. public virtual void EnemyAttack()
  138. {
  139. Debug.Log("触发攻击");
  140. FireManager.ShootBullet(this, ConvertRotation(Position.AngleTo(LookPosition)), ExcelConfig.BulletBase_Map["0006"]);
  141. // for (int i = 0; i < 100; i++)
  142. // {
  143. // FireManager.ShootBullet(this, ConvertRotation(Mathf.DegToRad(i * 3.6f)), ExcelConfig.BulletBase_List[0]);
  144. // }
  145. }
  146.  
  147. protected override void Process(float delta)
  148. {
  149. base.Process(delta);
  150. if (IsDie)
  151. {
  152. return;
  153. }
  154. //看向目标
  155. if (LookTarget != null)
  156. {
  157. var pos = LookTarget.Position;
  158. LookPosition = pos;
  159. //脸的朝向
  160. var gPos = Position;
  161. if (pos.X > gPos.X && Face == FaceDirection.Left)
  162. {
  163. Face = FaceDirection.Right;
  164. }
  165. else if (pos.X < gPos.X && Face == FaceDirection.Right)
  166. {
  167. Face = FaceDirection.Left;
  168. }
  169. }
  170.  
  171. if (_attackTimer > 0)
  172. {
  173. _attackTimer -= delta;
  174. }
  175. //目标在视野内的时间
  176. var currState = StateController.CurrState;
  177. if (currState == AiStateEnum.AiSurround || currState == AiStateEnum.AiFollowUp)
  178. {
  179. if (_attackTimer <= 0) //必须在可以开火时记录时间
  180. {
  181. _lockTargetTime += delta;
  182. }
  183. else
  184. {
  185. _lockTargetTime = 0;
  186. }
  187. }
  188. else
  189. {
  190. _lockTargetTime = 0;
  191. }
  192. }
  193.  
  194. protected override void OnHit(int damage, bool realHarm)
  195. {
  196. //受到伤害
  197. var state = StateController.CurrState;
  198. if (state == AiStateEnum.AiNormal || state == AiStateEnum.AiLeaveFor) //|| state == AiStateEnum.AiProbe
  199. {
  200. StateController.ChangeState(AiStateEnum.AiTailAfter);
  201. }
  202. }
  203. protected override void OnDie()
  204. {
  205. var effPos = Position + new Vector2(0, -Altitude);
  206. //血液特效
  207. var blood = ObjectManager.GetPoolItem<AutoDestroyParticles>(ResourcePath.prefab_effect_enemy_EnemyBloodEffect_tscn);
  208. blood.Position = effPos - new Vector2(0, 12);
  209. blood.AddToActivityRoot(RoomLayerEnum.NormalLayer);
  210. blood.PlayEffect();
  211.  
  212. //创建敌人碎片
  213. var count = Utils.Random.RandomRangeInt(3, 6);
  214. for (var i = 0; i < count; i++)
  215. {
  216. var debris = Create(Ids.Id_effect0001);
  217. debris.PutDown(effPos, RoomLayerEnum.NormalLayer);
  218. debris.InheritVelocity(this);
  219. }
  220. //派发敌人死亡信号
  221. EventManager.EmitEvent(EventEnum.OnEnemyDie, this);
  222. Destroy();
  223. }
  224. /// <summary>
  225. /// 检查是否能切换到 AiStateEnum.AiLeaveFor 状态
  226. /// </summary>
  227. public bool CanChangeLeaveFor()
  228. {
  229. if (!World.Enemy_IsFindTarget)
  230. {
  231. return false;
  232. }
  233.  
  234. var currState = StateController.CurrState;
  235. if (currState == AiStateEnum.AiNormal)// || currState == AiStateEnum.AiProbe)
  236. {
  237. //判断是否在同一个房间内
  238. return World.Enemy_FindTargetAffiliationSet.Contains(AffiliationArea);
  239. }
  240. return false;
  241. }
  242. /// <summary>
  243. /// 返回目标点是否在视野范围内
  244. /// </summary>
  245. public bool IsInViewRange(Vector2 target)
  246. {
  247. var isForward = IsPositionInForward(target);
  248. if (isForward)
  249. {
  250. if (GlobalPosition.DistanceSquaredTo(target) <= ViewRange * ViewRange) //没有超出视野半径
  251. {
  252. return true;
  253. }
  254. }
  255.  
  256. return false;
  257. }
  258.  
  259. /// <summary>
  260. /// 返回目标点是否在跟随状态下的视野半径内
  261. /// </summary>
  262. public bool IsInTailAfterViewRange(Vector2 target)
  263. {
  264. var isForward = IsPositionInForward(target);
  265. if (isForward)
  266. {
  267. if (GlobalPosition.DistanceSquaredTo(target) <= TailAfterViewRange * TailAfterViewRange) //没有超出视野半径
  268. {
  269. return true;
  270. }
  271. }
  272.  
  273. return false;
  274. }
  275.  
  276. /// <summary>
  277. /// 调用视野检测, 如果被墙壁和其它物体遮挡, 则返回被挡住视野的物体对象, 视野无阻则返回 null
  278. /// </summary>
  279. public bool TestViewRayCast(Vector2 target)
  280. {
  281. ViewRay.Enabled = true;
  282. ViewRay.TargetPosition = ViewRay.ToLocal(target);
  283. ViewRay.ForceRaycastUpdate();
  284. return ViewRay.IsColliding();
  285. }
  286.  
  287. /// <summary>
  288. /// 调用视野检测完毕后, 需要调用 TestViewRayCastOver() 来关闭视野检测射线
  289. /// </summary>
  290. public void TestViewRayCastOver()
  291. {
  292. ViewRay.Enabled = false;
  293. }
  294. /// <summary>
  295. /// 获取锁定目标的时间
  296. /// </summary>
  297. public float GetLockTime()
  298. {
  299. return _lockTargetTime;
  300. }
  301.  
  302. /// <summary>
  303. /// 获取锁定目标的剩余时间
  304. /// </summary>
  305. public float GetLockRemainderTime()
  306. {
  307. return LockingTime - _lockTargetTime;
  308. }
  309. /// <summary>
  310. /// 强制设置锁定目标时间
  311. /// </summary>
  312. public void SetLockTargetTime(float time)
  313. {
  314. _lockTargetTime = time;
  315. }
  316. /// <summary>
  317. /// 获取攻击范围
  318. /// </summary>
  319. /// <param name="weight">从最小到最大距离的过渡量, 0 - 1, 默认 0.5</param>
  320. public float GetAttackRange(float weight = 0.5f)
  321. {
  322. return 200;
  323. }
  324.  
  325. public override float GetFirePointAltitude()
  326. {
  327. return -AnimatedSprite.Position.Y - FirePoint.Position.Y;
  328. }
  329.  
  330. public override void LookTargetPosition(Vector2 pos)
  331. {
  332. LookTarget = null;
  333. base.LookTargetPosition(pos);
  334. }
  335. }