Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / role / PathSign.cs
@小李xl 小李xl on 25 Nov 2022 7 KB 临时提交 (还有报错)
  1.  
  2. using Godot;
  3.  
  4. /// <summary>
  5. /// 寻路标记, 记录下Role移动过的位置, 用于Ai寻路
  6. /// </summary>
  7. public class PathSign : Node2D, IDestroy
  8. {
  9. public bool IsDestroyed { get; private set; }
  10.  
  11. /// <summary>
  12. /// 当前标记在整个链上的索引
  13. /// </summary>
  14. public int Index { get; }
  15.  
  16. /// <summary>
  17. /// 监视的对象
  18. /// </summary>
  19. public Role Target { get; }
  20. /// <summary>
  21. /// 视野半径
  22. /// </summary>
  23. public float ViewRadius { get; }
  24.  
  25. /// <summary>
  26. /// 射线对象
  27. /// </summary>
  28. public RayCast2D RayCast { get; }
  29. /// <summary>
  30. /// 连接的下一个 PathSign
  31. /// </summary>
  32. public PathSign Next { get; set; }
  33.  
  34. /// <summary>
  35. /// 是否启用标记路径, 如果禁用, 将会清空所有标记
  36. /// </summary>
  37. public bool Enable
  38. {
  39. get => _enable;
  40. set
  41. {
  42. if (_enable && !value && Next != null)
  43. {
  44. Next.Destroy();
  45. Next = null;
  46. }
  47.  
  48. if (!value)
  49. {
  50. _isInRange = false;
  51. _isCollision = false;
  52. _targetPos = Vector2.Zero;
  53. _isDiscoverTarget = false;
  54. }
  55. _enable = value;
  56. }
  57. }
  58.  
  59. /// <summary>
  60. /// 目标出现过的位置
  61. /// </summary>
  62. public Vector2 TargetPosition
  63. {
  64. get => _targetPos;
  65. set => _targetPos = value;
  66. }
  67.  
  68. //是否发现过目标
  69. private bool _isDiscoverTarget = false;
  70. //目标在视野范围内出现过的位置
  71. private Vector2 _targetPos;
  72. //射线是否碰撞到目标
  73. private bool _isCollision;
  74. //目标是否在范围内
  75. private bool _isInRange;
  76. //是否启用
  77. private bool _enable = false;
  78.  
  79. /// <summary>
  80. /// 创建标记
  81. /// </summary>
  82. /// <param name="root">挂载节点</param>
  83. /// <param name="viewRadius">视野半径</param>
  84. /// <param name="target">监视对象</param>
  85. public PathSign(Node2D root, float viewRadius, Role target) : this(root, Vector2.Zero, viewRadius, target, 0)
  86. {
  87. }
  88.  
  89. private PathSign(Node2D root, Vector2 pos, float viewRadius, Role target, int index)
  90. {
  91. Index = index;
  92. Target = target;
  93. ViewRadius = viewRadius;
  94. root.AddChild(this);
  95. Position = pos;
  96.  
  97. //目前只检测墙壁碰撞
  98. RayCast = new RayCast2D();
  99. RayCast.CollisionMask = PhysicsLayer.Wall;
  100. AddChild(RayCast);
  101.  
  102. //绘制箭头
  103. if (GameApplication.Instance.Debug)
  104. {
  105. var sprite = new Sprite();
  106. sprite.Texture = ResourceManager.Load<Texture>(ResourcePath.resource_effects_debug_arrows_png);
  107. sprite.Position = new Vector2(0, -sprite.Texture.GetHeight() * 0.5f);
  108. AddChild(sprite);
  109. }
  110. }
  111.  
  112. public override void _Process(float delta)
  113. {
  114. base._Process(delta);
  115. if (GameApplication.Instance.Debug)
  116. {
  117. Update();
  118. }
  119. }
  120.  
  121. public override void _PhysicsProcess(float delta)
  122. {
  123. if (!_enable)
  124. {
  125. return;
  126. }
  127. //监视目标
  128. var nowTargetPos = Target.GlobalPosition;
  129. var distanceSquared = GlobalPosition.DistanceSquaredTo(nowTargetPos);
  130. var nowIsInRange = distanceSquared <= ViewRadius * ViewRadius;
  131.  
  132. if (nowIsInRange) //在视野范围内
  133. {
  134. var isCollision = Detect(nowTargetPos);
  135.  
  136. if (isCollision) //碰到墙
  137. {
  138. if (_isInRange && !_isCollision && Next == null) //如果上一帧就在视野内, 才能创建新的折点
  139. {
  140. var distance = Mathf.Sqrt(distanceSquared);
  141. Next = new PathSign(GameApplication.Instance.Room.GetRoot(false), _targetPos, ViewRadius - distance, Target, Index + 1);
  142. Next._targetPos = nowTargetPos;
  143. Next.Enable = true;
  144. }
  145. }
  146. else //没有碰到墙
  147. {
  148. if (Next != null)
  149. {
  150. Next.Destroy();
  151. Next = null;
  152. }
  153. _targetPos = nowTargetPos;
  154. _isDiscoverTarget = true;
  155. }
  156. _isCollision = isCollision;
  157. }
  158. else
  159. {
  160. _isCollision = false;
  161. }
  162.  
  163. _isInRange = nowIsInRange;
  164. }
  165.  
  166. /// <summary>
  167. /// 检测射线是否碰到墙壁
  168. /// </summary>
  169. /// <returns></returns>
  170. private bool Detect(Vector2 pos)
  171. {
  172. RayCast.Enabled = true;
  173. RayCast.CastTo = RayCast.ToLocal(pos);
  174. RayCast.ForceRaycastUpdate();
  175.  
  176. var flag = RayCast.IsColliding();
  177. RayCast.Enabled = false;
  178. return flag;
  179. }
  180.  
  181. public void Destroy()
  182. {
  183. if (IsDestroyed)
  184. {
  185. return;
  186. }
  187.  
  188. IsDestroyed = true;
  189.  
  190. if (Next != null)
  191. {
  192. Next.Destroy();
  193. }
  194.  
  195. QueueFree();
  196. }
  197.  
  198. public override void _Draw()
  199. {
  200. if (GameApplication.Instance.Debug && _isDiscoverTarget)
  201. {
  202. if (Next != null)
  203. {
  204. DrawLine(Vector2.Zero, ToLocal(Next.GlobalPosition), Colors.Blue);
  205. }
  206. else if (_isInRange && !_isCollision)
  207. {
  208. var pos = ToLocal(_targetPos);
  209. DrawString(ResourceManager.Load<Font>(ResourcePath.resource_font_cn_font_12_tres), new Vector2(-6, 12), (ViewRadius - GlobalPosition.DistanceTo(_targetPos)).ToString());
  210. DrawLine(Vector2.Zero, pos, Colors.Red);
  211. }
  212. else
  213. {
  214. var pos = ToLocal(_targetPos);
  215. DrawString(ResourceManager.Load<Font>(ResourcePath.resource_font_cn_font_12_tres), new Vector2(-6, 12), "0");
  216. DrawLine(Vector2.Zero, pos, Colors.Yellow);
  217. }
  218. }
  219. }
  220. }
  221.  
  222. #region 备份代码
  223. /*
  224. 第一个绑定在Role身上的点, 需要每一帧更新
  225. if (Master.PathSign.Enable)
  226. {
  227. var targetSign = master.PathSign;
  228. var enemyPos = master.GlobalPosition;
  229. if (targetSign.Next == null)
  230. {
  231. var targetPosition = targetSign.TargetPosition;
  232.  
  233. if (enemyPos.DistanceSquaredTo(targetPosition) <=
  234. master.Velocity.LengthSquared() * delta) //移动到下一个节点了, 还是没有找到目标, 变为第二状态
  235. {
  236. StateController.ChangeStateLate(AIStateEnum.AINormal);
  237. }
  238. else //继续移动
  239. {
  240. master.LookTargetPosition(targetPosition);
  241. master.AnimatedSprite.Animation = AnimatorNames.Run;
  242. master.Velocity = (targetPosition - enemyPos).Normalized() * master.MoveSpeed;
  243. master.CalcMove(delta);
  244. }
  245. }
  246. else
  247. {
  248. var nextPos = targetSign.Next.GlobalPosition;
  249.  
  250. if (enemyPos.DistanceSquaredTo(nextPos) <=
  251. master.Velocity.LengthSquared() * delta) //已经移动到下一个节点了, 删除下一个节点, 后面的接上
  252. {
  253. var nextNext = targetSign.Next.Next;
  254. var tempPos = targetSign.Next.TargetPosition;
  255. targetSign.Next.Next = null;
  256. targetSign.Next.Destroy();
  257. targetSign.Next = nextNext;
  258.  
  259. if (nextNext != null) //下一个点继续移动
  260. {
  261. nextPos = nextNext.GlobalPosition;
  262. master.LookTargetPosition(nextPos);
  263. master.AnimatedSprite.Animation = AnimatorNames.Run;
  264. master.Velocity = (nextPos - enemyPos).Normalized() * master.MoveSpeed;
  265. master.CalcMove(delta);
  266. }
  267. else
  268. {
  269. targetSign.TargetPosition = tempPos;
  270. }
  271. }
  272. else //继续移动
  273. {
  274. master.LookTargetPosition(nextPos);
  275. master.AnimatedSprite.Animation = AnimatorNames.Run;
  276. master.Velocity = (nextPos - enemyPos).Normalized() * master.MoveSpeed;
  277. master.CalcMove(delta);
  278. }
  279. }
  280. }
  281.  
  282. */
  283. #endregion