diff --git a/DungeonShooting_Godot/DungeonShooting.sln.DotSettings.user b/DungeonShooting_Godot/DungeonShooting.sln.DotSettings.user index 5ef2d60..66f7988 100644 --- a/DungeonShooting_Godot/DungeonShooting.sln.DotSettings.user +++ b/DungeonShooting_Godot/DungeonShooting.sln.DotSettings.user @@ -1,2 +1,5 @@  - WARNING \ No newline at end of file + WARNING + <AssemblyExplorer> + <Assembly Path="D:\GameProject\DungeonShooting\DungeonShooting_Godot\.mono\assemblies\Debug\GodotSharp.dll" /> +</AssemblyExplorer> \ No newline at end of file diff --git a/DungeonShooting_Godot/prefab/role/Player.tscn b/DungeonShooting_Godot/prefab/role/Player.tscn index 7154560..7bfb950 100644 --- a/DungeonShooting_Godot/prefab/role/Player.tscn +++ b/DungeonShooting_Godot/prefab/role/Player.tscn @@ -24,4 +24,4 @@ [node name="AnimatedSprite" parent="." index="2"] material = SubResource( 2 ) -frame = 1 +frame = 3 diff --git a/DungeonShooting_Godot/src/game/GameApplication.cs b/DungeonShooting_Godot/src/game/GameApplication.cs index 587b2f2..c2aec78 100644 --- a/DungeonShooting_Godot/src/game/GameApplication.cs +++ b/DungeonShooting_Godot/src/game/GameApplication.cs @@ -61,6 +61,7 @@ public override void _EnterTree() { + GD.Randomize(); ActivityObject.IsDebug = Debug; GlobalNodeRoot = GetNode(GlobalNodeRootPath); diff --git a/DungeonShooting_Godot/src/game/role/StateBase.cs b/DungeonShooting_Godot/src/game/role/StateBase.cs index d2a7586..c4d2d17 100644 --- a/DungeonShooting_Godot/src/game/role/StateBase.cs +++ b/DungeonShooting_Godot/src/game/role/StateBase.cs @@ -49,7 +49,7 @@ } /// - /// 是否允许切换至下一个状态 + /// 是否允许切换至下一个状态, 该函数由状态机控制器调用, 不需要手动调用 /// /// 下一个状态类型 public virtual bool CanChangeState(S next) diff --git a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs index dc0bfb4..98940e9 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs @@ -18,7 +18,6 @@ /// public class Enemy : Role { - /// /// 敌人身上的状态机控制器 /// @@ -109,13 +108,19 @@ /// /// 调用视野检测, 如果被墙壁和其它物体遮挡, 则返回被挡住视野的物体对象, 视野无阻则返回 null /// - public Godot.Object TestViewRayCast(Vector2 target) + public bool TestViewRayCast(Vector2 target) { ViewRay.Enabled = true; ViewRay.CastTo = ViewRay.ToLocal(target); ViewRay.ForceRaycastUpdate(); - var collObj = ViewRay.GetCollider(); + return ViewRay.IsColliding(); + } + + /// + /// 调用视野检测完毕后, 需要调用 TestViewRayCastOver() 来关闭视野检测射线 + /// + public void TestViewRayCastOver() + { ViewRay.Enabled = false; - return collObj; } } diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalState.cs index 8eb006b..03a0d35 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalState.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalState.cs @@ -6,21 +6,76 @@ /// public class AiNormalState : StateBase { + //是否发现玩家 + private bool _isFindPlayer; + //下一个运动的角度 + private Vector2 _nextPos; + //是否移动结束 + private bool _isMoveOver; + public AiNormalState() : base(AIStateEnum.AINormal) { } - + + public override void Enter(AIStateEnum prev, params object[] args) + { + _isFindPlayer = false; + _isMoveOver = true; + } + public override void PhysicsProcess(float delta) { - //检测玩家 - var player = GameApplication.Instance.Room.Player; - //玩家中心点坐标 - var playerPos = player.MountPoint.GlobalPosition; - if (Master.IsInViewRange(playerPos) && Master.TestViewRayCast(playerPos) == null) + if (_isFindPlayer) //已经找到玩家了 { - //发现玩家 + //现临时处理, 直接切换状态 ChangeStateLate(AIStateEnum.AITailAfter); } + else //没有找到玩家 + { + //检测玩家 + var player = GameApplication.Instance.Room.Player; + //玩家中心点坐标 + var playerPos = player.MountPoint.GlobalPosition; + + if (Master.IsInViewRange(playerPos) && !Master.TestViewRayCast(playerPos)) //发现玩家 + { + //发现玩家 + _isFindPlayer = true; + } + else if (_isMoveOver) //没发现玩家, 且已经移动完成 + { + var angle = Utils.RandRange(0, Mathf.Pi * 2f); + var len = Utils.RandRangeInt(50, 500); + _nextPos = new Vector2(len, 0).Rotated(angle); + //获取射线碰到的坐标 + if (Master.TestViewRayCast(_nextPos)) //碰到墙壁 + { + _nextPos = Master.ViewRay.GetCollisionPoint(); + } + Master.NavigationAgent2D.SetTargetLocation(_nextPos); + _isMoveOver = false; + } + else //移动中 + { + //计算移动 + var nextPos = Master.NavigationAgent2D.GetNextLocation(); + Master.LookTargetPosition(_nextPos); + Master.AnimatedSprite.Animation = AnimatorNames.Run; + Master.Velocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() * Master.MoveSpeed; + Master.CalcMove(delta); + + if (Master.NavigationAgent2D.IsNavigationFinished()) + { + _isMoveOver = true; + } + } + Master.TestViewRayCastOver(); + } + } + + public override void DebugDraw() + { + Master.DrawLine(Vector2.Zero, Master.ToLocal(_nextPos), Colors.Green); } } diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs index 07396bc..5ff99ac 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs @@ -26,12 +26,11 @@ public override void PhysicsProcess(float delta) { - var master = Master; - if (master.NavigationAgent2D.IsNavigationFinished()) + if (Master.NavigationAgent2D.IsNavigationFinished()) { return; } - var masterPos = master.GlobalPosition; + var masterPos = Master.GlobalPosition; var playerPos = GameApplication.Instance.Room.Player.GlobalPosition; //更新玩家位置 @@ -39,9 +38,9 @@ { //每隔一段时间秒更改目标位置 _navigationUpdateTimer = _navigationInterval; - if (master.NavigationAgent2D.GetTargetLocation() != playerPos) + if (Master.NavigationAgent2D.GetTargetLocation() != playerPos) { - master.NavigationAgent2D.SetTargetLocation(playerPos); + Master.NavigationAgent2D.SetTargetLocation(playerPos); } } else @@ -50,14 +49,14 @@ } //计算移动 - var nextPos = master.NavigationAgent2D.GetNextLocation(); - master.LookTargetPosition(playerPos); - master.AnimatedSprite.Animation = AnimatorNames.Run; - master.Velocity = (nextPos - master.GlobalPosition - master.NavigationPoint.Position).Normalized() * master.MoveSpeed; - master.CalcMove(delta); + var nextPos = Master.NavigationAgent2D.GetNextLocation(); + Master.LookTargetPosition(playerPos); + Master.AnimatedSprite.Animation = AnimatorNames.Run; + Master.Velocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() * Master.MoveSpeed; + Master.CalcMove(delta); //检测玩家是否在视野内, 此时视野可穿墙, 直接检测距离即可 - _isInView = masterPos.DistanceSquaredTo(playerPos) <= master.TailAfterViewRange * master.TailAfterViewRange; + _isInView = masterPos.DistanceSquaredTo(playerPos) <= Master.TailAfterViewRange * Master.TailAfterViewRange; if (_isInView) { _viewTimer = 0; diff --git a/DungeonShooting_Godot/src/game/room/RoomManager.cs b/DungeonShooting_Godot/src/game/room/RoomManager.cs index 10ca35c..9a39e41 100644 --- a/DungeonShooting_Godot/src/game/room/RoomManager.cs +++ b/DungeonShooting_Godot/src/game/room/RoomManager.cs @@ -13,6 +13,11 @@ /// public Role Player { get; private set; } + /// + /// 导航区域形状 + /// + public NavigationPolygonInstance NavigationPolygon { get; private set; } + //对象根节点 private Node2D _objectRoot; @@ -21,8 +26,6 @@ private Node2D _mapRoot; - private NavigationPolygonInstance _navigationPolygon; - //可行走区域的tileId private List _wayIds = new List(new[] { 129 }); @@ -32,6 +35,8 @@ //导航区域数据 private List _polygonDataList = new List(); + private TileMap _tileMap; + public override void _EnterTree() { Input.MouseMode = Input.MouseModeEnum.Hidden; @@ -39,13 +44,14 @@ _sortRoot = GetNode("SortRoot"); _objectRoot = GetNode("ObjectRoot"); - //_navigationPolygon = GetNode("NavigationPolygonInstance"); - _navigationPolygon = new NavigationPolygonInstance(); - AddChild(_navigationPolygon); + NavigationPolygon = new NavigationPolygonInstance(); + AddChild(NavigationPolygon); //初始化地图 _mapRoot = GetNode("MapRoot"); - var node = _mapRoot.GetChild(0).GetNode("Config"); + var child = _mapRoot.GetChild(0); + _tileMap = child.GetNode("Wall"); + var node = child.GetNode("Config"); Color color = (Color)node.GetMeta("ClearColor"); VisualServer.SetDefaultClearColor(color); @@ -69,7 +75,7 @@ polygon.AddOutline(polygonData.Points.ToArray()); } polygon.MakePolygonsFromOutlines(); - _navigationPolygon.Navpoly = polygon; + NavigationPolygon.Navpoly = polygon; //播放bgm SoundManager.PlayMusic(ResourcePath.resource_sound_bgm_Intro_ogg, -17f); @@ -132,14 +138,31 @@ } /// + /// 返回指定位置的Tile是否为可以行走 + /// + public bool IsWayTile(int x, int y) + { + var cellId = _tileMap.GetCell(x, y); + return cellId != -1 && _wayIds.Contains(cellId); + } + + /// + /// 返回指定坐标下对应的Tile是否为可以行走 + /// + public bool IsWayPosition(float x, float y) + { + var tileMapCellSize = _tileMap.CellSize; + return IsWayTile((int)(x / tileMapCellSize.x), (int)(y / tileMapCellSize.y)); + } + + /// /// 自动生成导航区域 /// private void GenerateNavigationPolygon() { - var tileMap = _mapRoot.GetChild(0).GetNode("Wall"); - var size = tileMap.CellSize; + var size = _tileMap.CellSize; - var rect = tileMap.GetUsedRect(); + var rect = _tileMap.GetUsedRect(); var x = (int)rect.Position.x; var y = (int)rect.Position.y; @@ -150,20 +173,19 @@ { for (int i = x; i < w; i++) { - var tileId = tileMap.GetCell(i, j); - if (IsWayCell(tileId)) + if (IsWayTile(i, j)) { if (!_usePoints.Contains(new Vector2(i, j))) { NavigationPolygonData polygonData = null; - if (!IsWayCell(tileMap.GetCell(i, j - 1))) + if (!IsWayTile(i, j - 1)) { - polygonData = CalcOutline(i, j, tileMap, size); + polygonData = CalcOutline(i, j, _tileMap, size); } - else if (!IsWayCell(tileMap.GetCell(i, j + 1))) + else if (!IsWayTile(i, j + 1)) { - polygonData = CalcInline(i, j, tileMap, size); + polygonData = CalcInline(i, j, _tileMap, size); } if (polygonData != null) @@ -196,7 +218,7 @@ { case 0: //右 { - if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //先向上找 + if (IsWayTile(tempI, tempJ - 1)) //先向上找 { dir = 3; @@ -212,7 +234,7 @@ tempJ--; break; } - else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //再向右找 + else if (IsWayTile(tempI + 1, tempJ)) //再向右找 { if (points.Count == 0) { @@ -229,7 +251,7 @@ tempI++; break; } - else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //向下找 + else if (IsWayTile(tempI, tempJ + 1)) //向下找 { dir = 1; @@ -250,7 +272,7 @@ } case 1: //下 { - if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //先向右找 + if (IsWayTile(tempI + 1, tempJ)) //先向右找 { dir = 0; @@ -266,7 +288,7 @@ tempI++; break; } - else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //再向下找 + else if (IsWayTile(tempI, tempJ + 1)) //再向下找 { if (points.Count == 0) { @@ -283,7 +305,7 @@ tempJ++; break; } - else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //向左找 + else if (IsWayTile(tempI - 1, tempJ)) //向左找 { dir = 2; @@ -304,7 +326,7 @@ } case 2: //左 { - if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //先向下找 + if (IsWayTile(tempI, tempJ + 1)) //先向下找 { dir = 1; @@ -320,7 +342,7 @@ tempJ++; break; } - else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //再向左找 + else if (IsWayTile(tempI - 1, tempJ)) //再向左找 { if (points.Count == 0) { @@ -337,7 +359,7 @@ tempI--; break; } - else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //向上找 + else if (IsWayTile(tempI, tempJ - 1)) //向上找 { dir = 3; @@ -358,7 +380,7 @@ } case 3: //上 { - if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //先向左找 + if (IsWayTile(tempI - 1, tempJ)) //先向左找 { dir = 2; @@ -374,7 +396,7 @@ tempI--; break; } - else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //再向上找 + else if (IsWayTile(tempI, tempJ - 1)) //再向上找 { if (points.Count == 0) { @@ -391,7 +413,7 @@ tempJ--; break; } - else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //向右找 + else if (IsWayTile(tempI + 1, tempJ)) //向右找 { dir = 0; @@ -434,7 +456,7 @@ { case 0: //右 { - if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //向下找 + if (IsWayTile(tempI, tempJ + 1)) //向下找 { dir = 1; @@ -450,7 +472,7 @@ tempJ++; break; } - else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //再向右找 + else if (IsWayTile(tempI + 1, tempJ)) //再向右找 { if (points.Count == 0) { @@ -467,7 +489,7 @@ tempI++; break; } - else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //先向上找 + else if (IsWayTile(tempI, tempJ - 1)) //先向上找 { dir = 3; @@ -488,7 +510,7 @@ } case 1: //下 { - if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //向左找 + if (IsWayTile(tempI - 1, tempJ)) //向左找 { dir = 2; @@ -504,7 +526,7 @@ tempI--; break; } - else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //再向下找 + else if (IsWayTile(tempI, tempJ + 1)) //再向下找 { if (points.Count == 0) { @@ -521,7 +543,7 @@ tempJ++; break; } - else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //先向右找 + else if (IsWayTile(tempI + 1, tempJ)) //先向右找 { dir = 0; @@ -542,7 +564,7 @@ } case 2: //左 { - if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //向上找 + if (IsWayTile(tempI, tempJ - 1)) //向上找 { dir = 3; @@ -558,7 +580,7 @@ tempJ--; break; } - else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //再向左找 + else if (IsWayTile(tempI - 1, tempJ)) //再向左找 { if (points.Count == 0) { @@ -575,7 +597,7 @@ tempI--; break; } - else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //先向下找 + else if (IsWayTile(tempI, tempJ + 1)) //先向下找 { dir = 1; @@ -596,7 +618,7 @@ } case 3: //上 { - if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //向右找 + if (IsWayTile(tempI + 1, tempJ)) //向右找 { dir = 0; @@ -612,7 +634,7 @@ tempI++; break; } - else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //再向上找 + else if (IsWayTile(tempI, tempJ - 1)) //再向上找 { if (points.Count == 0) { @@ -629,7 +651,7 @@ tempJ--; break; } - else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //先向左找 + else if (IsWayTile(tempI - 1, tempJ)) //先向左找 { dir = 2; @@ -661,9 +683,4 @@ _usePoints.Add(pos); } - - private bool IsWayCell(int cellId) - { - return cellId != -1 && _wayIds.Contains(cellId); - } } \ No newline at end of file