diff --git a/DungeonShooting_Godot/scene/Main.tscn b/DungeonShooting_Godot/scene/Main.tscn index aff7b6d..35a4274 100644 --- a/DungeonShooting_Godot/scene/Main.tscn +++ b/DungeonShooting_Godot/scene/Main.tscn @@ -24,6 +24,7 @@ [node name="Main" type="Node2D"] script = ExtResource( 3 ) +Debug = true CursorPack = ExtResource( 4 ) RoomPath = NodePath("ViewCanvas/ViewportContainer/Viewport/Room") ViewportPath = NodePath("ViewCanvas/ViewportContainer/Viewport") diff --git a/DungeonShooting_Godot/src/game/GameApplication.cs b/DungeonShooting_Godot/src/game/GameApplication.cs index 6bb09c1..f53ca90 100644 --- a/DungeonShooting_Godot/src/game/GameApplication.cs +++ b/DungeonShooting_Godot/src/game/GameApplication.cs @@ -5,6 +5,11 @@ { public static GameApplication Instance { get; private set; } + /// + /// 是否开启调试 + /// + [Export] public bool Debug = false; + [Export] public PackedScene CursorPack; [Export] public NodePath RoomPath; diff --git a/DungeonShooting_Godot/src/game/role/PathSign.cs b/DungeonShooting_Godot/src/game/role/PathSign.cs index 0b7f03e..3925315 100644 --- a/DungeonShooting_Godot/src/game/role/PathSign.cs +++ b/DungeonShooting_Godot/src/game/role/PathSign.cs @@ -4,24 +4,68 @@ /// /// 寻路标记, 记录下Role移动过的位置, 用于Ai寻路 /// -public class PathSign : Node2D +public class PathSign : Node2D, IDestroy { + public bool IsDestroyed { get; private set; } + /// - /// 是否启用 + /// 当前标记在整个链上的索引 /// - public bool Enable { get; set; } + public int Index { get; } + + /// + /// 监视的对象 + /// + public Role Target { get; } + + /// + /// 视野半径 + /// + public float ViewRadius { get; } + + /// + /// 射线对象 + /// + public RayCast2D RayCast { get; } + + /// + /// 连接的上一个 PathSign + /// + public PathSign Prev { get; set; } + + /// + /// 连接的下一个 PathSign + /// + public PathSign Next { get; set; } + + private Vector2 _prevTargetPos; /// /// 创建标记 /// /// 坐标 - /// 用于debug, 显示箭头 - public PathSign(Vector2 pos, bool debug = false) + /// 视野半径 + /// 监视对象 + public PathSign(Vector2 pos, float viewRadius, Role target) : this(pos, viewRadius, target, 0, null) { + } + + private PathSign(Vector2 pos, float viewRadius, Role target, int index, PathSign prev) + { + Index = index; + Prev = prev; + Target = target; + ViewRadius = viewRadius; GameApplication.Instance.Room.GetRoot(false).AddChild(this); GlobalPosition = pos; - if (debug) + //目前只检测墙壁碰撞 + RayCast = new RayCast2D(); + RayCast.CollisionMask = PhysicsLayer.Wall; + AddChild(RayCast); + + //绘制箭头 + if (GameApplication.Instance.Debug) { var sprite = new Sprite(); sprite.Texture = ResourceManager.Load(ResourcePath.resource_effects_debug_arrows_png); @@ -29,4 +73,63 @@ AddChild(sprite); } } + + public override void _Process(float delta) + { + base._Process(delta); + if (GameApplication.Instance.Debug) + { + Update(); + } + } + + public override void _PhysicsProcess(float delta) + { + if (Next == null) + { + //监视目标 + 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; + } + } + } + + public void Destroy() + { + if (IsDestroyed) + { + return; + } + + IsDestroyed = true; + + if (Next != null) + { + Next.Destroy(); + } + + QueueFree(); + } + + public override void _Draw() + { + if (GameApplication.Instance.Debug) + { + if (Next != null) + { + DrawLine(Vector2.Zero,ToLocal(Next.GlobalPosition), Colors.Red); + } + } + } } diff --git a/DungeonShooting_Godot/src/game/role/Player.cs b/DungeonShooting_Godot/src/game/role/Player.cs index 5e0d434..0671568 100644 --- a/DungeonShooting_Godot/src/game/role/Player.cs +++ b/DungeonShooting_Godot/src/game/role/Player.cs @@ -14,15 +14,6 @@ /// public float Friction { get; set; } = 800f; - //----------------------- 寻路相关 ---------------------------- - - //路径标记点总个数 - private int _signLength = 15; - //存放所有路径点 - private readonly List _pathSignList = new List(); - - //------------------------------------------------------------- - public Player(): base(ResourcePath.prefab_role_Player_tscn) { AttackLayer = PhysicsLayer.Wall | PhysicsLayer.Props | PhysicsLayer.Enemy; @@ -212,7 +203,7 @@ CalcMove(delta); } - + // 播放动画 private void PlayAnim() { diff --git a/DungeonShooting_Godot/src/game/role/Role.cs b/DungeonShooting_Godot/src/game/role/Role.cs index 7720549..24ecc4c 100644 --- a/DungeonShooting_Godot/src/game/role/Role.cs +++ b/DungeonShooting_Godot/src/game/role/Role.cs @@ -302,6 +302,28 @@ } /// + /// 使角色看向指定的坐标, + /// 注意, 调用该函数会清空 LookTarget, 因为拥有 LookTarget 会每帧更新玩家视野位置 + /// + /// + public void LookTargetPosition(Vector2 pos) + { + LookTarget = null; + //脸的朝向 + var gPos = GlobalPosition; + if (pos.x > gPos.x && Face == FaceDirection.Left) + { + Face = FaceDirection.Right; + } + else if (pos.x < gPos.x && Face == FaceDirection.Right) + { + Face = FaceDirection.Left; + } + //枪口跟随目标 + MountPoint.SetLookAt(pos); + } + + /// /// 判断指定坐标是否在角色视野方向 /// public bool IsPositionInForward(Vector2 pos) diff --git a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs index e293d65..1a93b89 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs @@ -39,6 +39,15 @@ /// public RayCast2D ViewRay { get; } + //------------------- 寻路相关 --------------------------- + + + private PathSign _pathSign; + //上一帧玩家位置 + private Vector2 _prevPlayerPos; + + //------------------------------------------------------- + public Enemy() : base(ResourcePath.prefab_role_Enemy_tscn) { StateController = new StateController(); @@ -59,6 +68,15 @@ StateController.ChangeState(StateEnum.Idle); } + public override void _Process(float delta) + { + base._Process(delta); + if (GameApplication.Instance.Debug) + { + Update(); + } + } + public override void _PhysicsProcess(float delta) { base._PhysicsProcess(delta); @@ -83,24 +101,46 @@ ViewRay.CastTo = localPos; ViewRay.ForceRaycastUpdate(); - if (ViewRay.IsColliding()) + if (ViewRay.IsColliding()) //在视野范围内, 但是碰到墙壁 { + if (_pathSign == null) //路径标记 + { + _pathSign = new PathSign(_prevPlayerPos, ViewRange, player); + } LookTarget = null; StateController.ChangeState(StateEnum.Idle); } - else + else //视野无阻 { + if (_pathSign != null) //删除路径标记 + { + _pathSign.Destroy(); + _pathSign = null; + } + LookTarget = player; StateController.ChangeState(StateEnum.Run); } ViewRay.Enabled = false; } - else + else //超出视野半径 { LookTarget = null; StateController.ChangeState(StateEnum.Idle); } + _prevPlayerPos = playerPos; + } + } + + public override void _Draw() + { + if (GameApplication.Instance.Debug) + { + if (_pathSign != null) + { + DrawLine(Vector2.Zero,ToLocal(_pathSign.GlobalPosition), Colors.Red); + } } } }