diff --git a/DungeonShooting_Godot/src/game/role/PathSign.cs b/DungeonShooting_Godot/src/game/role/PathSign.cs
index 3925315..cec2ea9 100644
--- a/DungeonShooting_Godot/src/game/role/PathSign.cs
+++ b/DungeonShooting_Godot/src/game/role/PathSign.cs
@@ -7,7 +7,7 @@
public class PathSign : Node2D, IDestroy
{
public bool IsDestroyed { get; private set; }
-
+
///
/// 当前标记在整个链上的索引
///
@@ -27,37 +27,65 @@
/// 射线对象
///
public RayCast2D RayCast { get; }
-
- ///
- /// 连接的上一个 PathSign
- ///
- public PathSign Prev { get; set; }
-
+
///
/// 连接的下一个 PathSign
///
public PathSign Next { get; set; }
- private Vector2 _prevTargetPos;
-
+ ///
+ /// 是否启用标记路径, 如果禁用, 将会清空所有标记
+ ///
+ public bool Enable
+ {
+ get => _enable;
+ set
+ {
+ if (_enable && !value && Next != null)
+ {
+ Next.Destroy();
+ Next = null;
+ }
+
+ if (!value)
+ {
+ _isInRange = false;
+ _isCollision = false;
+ _targetPos = Vector2.Zero;
+ _isDiscoverTarget = false;
+ }
+ _enable = value;
+ }
+ }
+
+ //是否发现过目标
+ private bool _isDiscoverTarget = false;
+ //目标在视野范围内出现过的位置
+ private Vector2 _targetPos;
+ //射线是否碰撞到目标
+ private bool _isCollision;
+ //目标是否在范围内
+ private bool _isInRange;
+ //是否启用
+ private bool _enable = false;
+
///
/// 创建标记
///
- /// 坐标
+ /// 挂载节点
/// 视野半径
/// 监视对象
- public PathSign(Vector2 pos, float viewRadius, Role target) : this(pos, viewRadius, target, 0, null)
+ public PathSign(Node2D root, float viewRadius, Role target) : this(root, Vector2.Zero, viewRadius, target, 0)
{
}
- private PathSign(Vector2 pos, float viewRadius, Role target, int index, PathSign prev)
+ private PathSign(Node2D root, Vector2 pos, float viewRadius, Role target, int index)
{
Index = index;
- Prev = prev;
Target = target;
ViewRadius = viewRadius;
- GameApplication.Instance.Room.GetRoot(false).AddChild(this);
- GlobalPosition = pos;
+ root.AddChild(this);
+ Position = pos;
//目前只检测墙壁碰撞
RayCast = new RayCast2D();
@@ -85,24 +113,62 @@
public override void _PhysicsProcess(float delta)
{
- if (Next == null)
+ if (!_enable)
{
- //监视目标
- var targetPos = Target.GlobalPosition;
- if (GlobalPosition.DistanceSquaredTo(targetPos) <= ViewRadius * ViewRadius) //在视野范围内
- {
- RayCast.Enabled = true;
- RayCast.CastTo = RayCast.ToLocal(targetPos);
- RayCast.ForceRaycastUpdate();
-
- if (RayCast.IsColliding())
- {
- Next = new PathSign(_prevTargetPos, ViewRadius, Target, Index + 1, this);
- }
- RayCast.Enabled = false;
- _prevTargetPos = targetPos;
- }
+ return;
}
+ //监视目标
+ var nowTargetPos = Target.GlobalPosition;
+ var distanceSquared = GlobalPosition.DistanceSquaredTo(nowTargetPos);
+ var nowIsInRange = distanceSquared <= ViewRadius * ViewRadius;
+
+ if (nowIsInRange) //在视野范围内
+ {
+ var isCollision = Detect(nowTargetPos);
+
+ if (isCollision) //碰到墙
+ {
+ if (_isInRange && !_isCollision && Next == null) //如果上一帧就在视野内, 才能创建新的折点
+ {
+ var distance = Mathf.Sqrt(distanceSquared);
+ Next = new PathSign(GameApplication.Instance.Room.GetRoot(false), _targetPos, ViewRadius - distance, Target, Index + 1);
+ Next._targetPos = nowTargetPos;
+ }
+ }
+ else //没有碰到墙
+ {
+ if (Next != null)
+ {
+ Next.Destroy();
+ Next = null;
+ }
+ _targetPos = nowTargetPos;
+ _isDiscoverTarget = true;
+ }
+
+ _isCollision = isCollision;
+ }
+ else
+ {
+ _isCollision = false;
+ }
+
+ _isInRange = nowIsInRange;
+ }
+
+ ///
+ /// 检测射线是否碰到墙壁
+ ///
+ ///
+ private bool Detect(Vector2 pos)
+ {
+ RayCast.Enabled = true;
+ RayCast.CastTo = RayCast.ToLocal(pos);
+ RayCast.ForceRaycastUpdate();
+
+ var flag = RayCast.IsColliding();
+ RayCast.Enabled = false;
+ return flag;
}
public void Destroy()
@@ -124,11 +190,23 @@
public override void _Draw()
{
- if (GameApplication.Instance.Debug)
+ if (GameApplication.Instance.Debug && _isDiscoverTarget)
{
if (Next != null)
{
- DrawLine(Vector2.Zero,ToLocal(Next.GlobalPosition), Colors.Red);
+ DrawLine(Vector2.Zero, ToLocal(Next.GlobalPosition), Colors.Blue);
+ }
+ else if (_isInRange && !_isCollision)
+ {
+ var pos = ToLocal(_targetPos);
+ DrawString(ResourceManager.Load(ResourcePath.resource_font_cn_font_12_tres), new Vector2(-6, 12), (ViewRadius - GlobalPosition.DistanceTo(_targetPos)).ToString());
+ DrawLine(Vector2.Zero, pos, Colors.Red);
+ }
+ else
+ {
+ var pos = ToLocal(_targetPos);
+ DrawString(ResourceManager.Load(ResourcePath.resource_font_cn_font_12_tres), new Vector2(-6, 12), "0");
+ DrawLine(Vector2.Zero, pos, Colors.Yellow);
}
}
}
diff --git a/DungeonShooting_Godot/src/game/role/Role.cs b/DungeonShooting_Godot/src/game/role/Role.cs
index 24ecc4c..dfc1877 100644
--- a/DungeonShooting_Godot/src/game/role/Role.cs
+++ b/DungeonShooting_Godot/src/game/role/Role.cs
@@ -303,7 +303,7 @@
///
/// 使角色看向指定的坐标,
- /// 注意, 调用该函数会清空 LookTarget, 因为拥有 LookTarget 会每帧更新玩家视野位置
+ /// 注意, 调用该函数会清空 LookTarget, 因为拥有 LookTarget 时也会每帧更新玩家视野位置
///
///
public void LookTargetPosition(Vector2 pos)
diff --git a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
index 1a93b89..142ee21 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
@@ -41,11 +41,16 @@
//------------------- 寻路相关 ---------------------------
-
- private PathSign _pathSign;
- //上一帧玩家位置
- private Vector2 _prevPlayerPos;
-
+ ///
+ /// 移动目标标记
+ ///
+ public PathSign TargetSign { get; }
+
+ ///
+ /// 寻路标记线段总长度
+ ///
+ public float PathSignLength { get; set; } = 500;
+
//-------------------------------------------------------
public Enemy() : base(ResourcePath.prefab_role_Enemy_tscn)
@@ -66,6 +71,8 @@
StateController.Register(new AIRunState());
//默认状态
StateController.ChangeState(StateEnum.Idle);
+
+ TargetSign = new PathSign(this, PathSignLength, GameApplication.Instance.Room.Player);
}
public override void _Process(float delta)
@@ -84,52 +91,39 @@
var player = GameApplication.Instance.Room.Player;
//玩家中心点坐标
var playerPos = player.MountPoint.GlobalPosition;
-
- //检测是否在视野内
- var pos = GlobalPosition;
-
+
//玩家是否在前方
var isForward = IsPositionInForward(playerPos);
if (isForward) //脸朝向玩家
{
- if (pos.DistanceSquaredTo(playerPos) <= ViewRange * ViewRange) //没有超出视野半径
- {
- //射线检测墙体
- ViewRay.Enabled = true;
- var localPos = ViewRay.ToLocal(playerPos);
- ViewRay.CastTo = localPos;
- ViewRay.ForceRaycastUpdate();
-
- if (ViewRay.IsColliding()) //在视野范围内, 但是碰到墙壁
- {
- if (_pathSign == null) //路径标记
- {
- _pathSign = new PathSign(_prevPlayerPos, ViewRange, player);
- }
- LookTarget = null;
- StateController.ChangeState(StateEnum.Idle);
- }
- else //视野无阻
- {
- if (_pathSign != null) //删除路径标记
- {
- _pathSign.Destroy();
- _pathSign = null;
- }
-
- LookTarget = player;
- StateController.ChangeState(StateEnum.Run);
- }
-
- ViewRay.Enabled = false;
- }
- else //超出视野半径
- {
- LookTarget = null;
- StateController.ChangeState(StateEnum.Idle);
- }
- _prevPlayerPos = playerPos;
+ // if (GlobalPosition.DistanceSquaredTo(playerPos) <= ViewRange * ViewRange) //没有超出视野半径
+ // {
+ // //射线检测墙体
+ // ViewRay.Enabled = true;
+ // var localPos = ViewRay.ToLocal(playerPos);
+ // ViewRay.CastTo = localPos;
+ // ViewRay.ForceRaycastUpdate();
+ //
+ // if (ViewRay.IsColliding()) //在视野范围内, 但是碰到墙壁
+ // {
+ // LookTarget = null;
+ // StateController.ChangeState(StateEnum.Idle);
+ // }
+ // else //视野无阻
+ // {
+ // LookTarget = player;
+ // StateController.ChangeState(StateEnum.Run);
+ // }
+ //
+ // ViewRay.Enabled = false;
+ // }
+ // else //超出视野半径
+ // {
+ // LookTarget = null;
+ // StateController.ChangeState(StateEnum.Idle);
+ // }
+ // //_prevPlayerPos = playerPos;
}
}
@@ -137,9 +131,9 @@
{
if (GameApplication.Instance.Debug)
{
- if (_pathSign != null)
+ if (TargetSign != null)
{
- DrawLine(Vector2.Zero,ToLocal(_pathSign.GlobalPosition), Colors.Red);
+ DrawLine(Vector2.Zero,ToLocal(TargetSign.GlobalPosition), Colors.Red);
}
}
}
diff --git a/DungeonShooting_Godot/src/game/room/RoomManager.cs b/DungeonShooting_Godot/src/game/room/RoomManager.cs
index a3c9331..35e709c 100644
--- a/DungeonShooting_Godot/src/game/room/RoomManager.cs
+++ b/DungeonShooting_Godot/src/game/room/RoomManager.cs
@@ -61,9 +61,9 @@
///
/// 获取房间根节点
///
- ///
+ /// 是否获取 YSort 节点
///
- public Node2D GetRoot(bool useYSort)
+ public Node2D GetRoot(bool useYSort = false)
{
return useYSort ? SortRoot : ObjectRoot;
}