diff --git a/DungeonShooting_Godot/prefab/role/Enemy.tscn b/DungeonShooting_Godot/prefab/role/Enemy.tscn index 3fad24b..2399534 100644 --- a/DungeonShooting_Godot/prefab/role/Enemy.tscn +++ b/DungeonShooting_Godot/prefab/role/Enemy.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=6 format=2] +[gd_scene load_steps=5 format=2] [ext_resource path="res://prefab/role/Role.tscn" type="PackedScene" id=1] [ext_resource path="res://resource/materlal/Blend.gdshader" type="Shader" id=2] @@ -15,9 +15,6 @@ shader_param/blend = Color( 1, 1, 1, 1 ) shader_param/schedule = 0.0 -[sub_resource type="CircleShape2D" id=3] -radius = 13.0 - [node name="Enemy" instance=ExtResource( 1 )] CollisionLayer = 16 @@ -26,16 +23,9 @@ [node name="AnimatedSprite" parent="." index="2"] material = SubResource( 2 ) -frame = 0 +frame = 3 [node name="ViewRay" type="RayCast2D" parent="." index="6"] position = Vector2( 0, -8 ) -[node name="MarginArea" type="Area2D" parent="." index="8"] -collision_layer = 0 - -[node name="CollisionShape2D" type="CollisionShape2D" parent="MarginArea" index="0"] -position = Vector2( 0, -8 ) -shape = SubResource( 3 ) - -[node name="NavigationAgent2D" type="NavigationAgent2D" parent="." index="9"] +[node name="NavigationAgent2D" type="NavigationAgent2D" parent="." index="8"] diff --git a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs index 1da5264..5a4642a 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs @@ -52,9 +52,9 @@ public float PathSignLength { get; set; } = 500; //------------------------------------------------------- - - private Area2D _marginArea; + private NavigationAgent2D _navigationAgent2D; + private float _navigationUpdateTimer = 0; public Enemy() : base(ResourcePath.prefab_role_Enemy_tscn) { @@ -68,8 +68,6 @@ //视野射线 ViewRay = GetNode("ViewRay"); - _marginArea = GetNode("MarginArea"); - _navigationAgent2D = GetNode("NavigationAgent2D"); PathSign = new PathSign(this, PathSignLength, GameApplication.Instance.Room.Player); @@ -86,20 +84,8 @@ //默认状态 StateController.ChangeState(AIStateEnum.AINormal); - _marginArea.Connect("body_shape_entered", this, nameof(OnObjectEnter)); _navigationAgent2D.SetTargetLocation(GameApplication.Instance.Room.Player.GlobalPosition); } - - public void OnObjectEnter(RID id, Node node, int shapeIndex, int localShapeIndex) - { - GD.Print($"id: {id}, node: {node}, shapeIndex: {shapeIndex}, localShapeIndex: {localShapeIndex}."); - if (node is TileMap tileMap) - { - //tileMap.TileSet.id - // var tileGetShape = tileMap.TileSet.TileGetShapeTransform(shapeIndex, localShapeIndex).; - // GD.Print("enter: ", tileGetShape.GetType().FullName); - } - } public override void _Process(float delta) { @@ -119,10 +105,23 @@ { return; } + var playerGlobalPosition = GameApplication.Instance.Room.Player.GlobalPosition; + //临时处理, 让敌人跟随玩家 + if (_navigationUpdateTimer <= 0) + { + _navigationUpdateTimer = 0.2f; + if (_navigationAgent2D.GetTargetLocation() != playerGlobalPosition) + { + _navigationAgent2D.SetTargetLocation(playerGlobalPosition); + } + } + else + { + _navigationUpdateTimer -= delta; + } - _navigationAgent2D.SetTargetLocation(GameApplication.Instance.Room.Player.GlobalPosition); var nextPos = _navigationAgent2D.GetNextLocation(); - LookTargetPosition(nextPos); + LookTargetPosition(playerGlobalPosition); AnimatedSprite.Animation = AnimatorNames.Run; Velocity = (nextPos - GlobalPosition).Normalized() * MoveSpeed; CalcMove(delta); diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AITailAfterState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AITailAfterState.cs index 1e16c6a..0cfa70c 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/state/AITailAfterState.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/state/AITailAfterState.cs @@ -9,62 +9,67 @@ public StateController StateController { get; set; } public void Enter(AIStateEnum prev, params object[] args) { - Master.PathSign.Enable = true; + //临时处理 + //Master.PathSign.Enable = true; } public void PhysicsProcess(float delta) { - return; var master = Master; - var targetSign = master.PathSign; - var enemyPos = master.GlobalPosition; - if (targetSign.Next == null) + if (Master.PathSign.Enable) { - var targetPosition = targetSign.TargetPosition; - - if (enemyPos.DistanceSquaredTo(targetPosition) <= master.Velocity.LengthSquared() * delta) //移动到下一个节点了, 还是没有找到目标, 变为第二状态 + var targetSign = master.PathSign; + var enemyPos = master.GlobalPosition; + if (targetSign.Next == null) { - StateController.ChangeStateLate(AIStateEnum.AINormal); - } - else //继续移动 - { - master.LookTargetPosition(targetPosition); - master.AnimatedSprite.Animation = AnimatorNames.Run; - master.Velocity = (targetPosition - enemyPos).Normalized() * master.MoveSpeed; - master.CalcMove(delta); - } - } - else - { - var nextPos = targetSign.Next.GlobalPosition; + var targetPosition = targetSign.TargetPosition; - if (enemyPos.DistanceSquaredTo(nextPos) <= master.Velocity.LengthSquared() * delta) //已经移动到下一个节点了, 删除下一个节点, 后面的接上 - { - var nextNext = targetSign.Next.Next; - var tempPos = targetSign.Next.TargetPosition; - targetSign.Next.Next = null; - targetSign.Next.Destroy(); - targetSign.Next = nextNext; - - if (nextNext != null) //下一个点继续移动 + if (enemyPos.DistanceSquaredTo(targetPosition) <= + master.Velocity.LengthSquared() * delta) //移动到下一个节点了, 还是没有找到目标, 变为第二状态 { - nextPos = nextNext.GlobalPosition; + StateController.ChangeStateLate(AIStateEnum.AINormal); + } + else //继续移动 + { + master.LookTargetPosition(targetPosition); + master.AnimatedSprite.Animation = AnimatorNames.Run; + master.Velocity = (targetPosition - enemyPos).Normalized() * master.MoveSpeed; + master.CalcMove(delta); + } + } + else + { + var nextPos = targetSign.Next.GlobalPosition; + + if (enemyPos.DistanceSquaredTo(nextPos) <= + master.Velocity.LengthSquared() * delta) //已经移动到下一个节点了, 删除下一个节点, 后面的接上 + { + var nextNext = targetSign.Next.Next; + var tempPos = targetSign.Next.TargetPosition; + targetSign.Next.Next = null; + targetSign.Next.Destroy(); + targetSign.Next = nextNext; + + if (nextNext != null) //下一个点继续移动 + { + nextPos = nextNext.GlobalPosition; + master.LookTargetPosition(nextPos); + master.AnimatedSprite.Animation = AnimatorNames.Run; + master.Velocity = (nextPos - enemyPos).Normalized() * master.MoveSpeed; + master.CalcMove(delta); + } + else + { + targetSign.TargetPosition = tempPos; + } + } + else //继续移动 + { master.LookTargetPosition(nextPos); master.AnimatedSprite.Animation = AnimatorNames.Run; master.Velocity = (nextPos - enemyPos).Normalized() * master.MoveSpeed; master.CalcMove(delta); } - else - { - targetSign.TargetPosition = tempPos; - } - } - else //继续移动 - { - master.LookTargetPosition(nextPos); - master.AnimatedSprite.Animation = AnimatorNames.Run; - master.Velocity = (nextPos - enemyPos).Normalized() * master.MoveSpeed; - master.CalcMove(delta); } } } diff --git a/DungeonShooting_Godot/src/game/room/RoomManager.cs b/DungeonShooting_Godot/src/game/room/RoomManager.cs index d91a9b5..6816499 100644 --- a/DungeonShooting_Godot/src/game/room/RoomManager.cs +++ b/DungeonShooting_Godot/src/game/room/RoomManager.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Godot; /// @@ -5,30 +6,46 @@ /// public class RoomManager : Navigation2D { + /// + /// 玩家对象 + /// public Role Player { get; private set; } - private Node2D ObjectRoot; - private YSort SortRoot; + //对象根节点 + private Node2D _objectRoot; + + //对象根节点, 带y轴排序功能 + private YSort _sortRoot; + + private Node2D _mapRoot; + + private NavigationPolygonInstance _navigationPolygon; private Enemy _enemy; + private List _wayIds = new List(new[] { 129 }); + private List _points = new List(); + public override void _EnterTree() { Input.MouseMode = Input.MouseModeEnum.Hidden; - SortRoot = GetNode("SortRoot"); - ObjectRoot = GetNode("ObjectRoot"); + _sortRoot = GetNode("SortRoot"); + _objectRoot = GetNode("ObjectRoot"); + + _navigationPolygon = GetNode("NavigationPolygonInstance"); //初始化地图 - var node = GetNode("MapRoot").GetChild(0).GetNode("Config"); + _mapRoot = GetNode("MapRoot"); + var node = _mapRoot.GetChild(0).GetNode("Config"); Color color = (Color)node.GetMeta("ClearColor"); VisualServer.SetDefaultClearColor(color); - + //创建玩家 Player = new Player(); Player.Position = new Vector2(100, 100); Player.Name = "Player"; Player.PutDown(); - + _enemy = new Enemy(); _enemy.Name = "Enemy"; _enemy.PutDown(new Vector2(150, 150)); @@ -36,6 +53,8 @@ public override void _Ready() { + GenerateNavigationPolygon(); + //播放bgm SoundManager.PlayMusic(ResourcePath.resource_sound_bgm_Intro_ogg, -17f); _enemy.PickUpWeapon(WeaponManager.GetGun("1001")); @@ -48,13 +67,27 @@ WeaponManager.GetGun("1003").PutDown(new Vector2(180, 80)); WeaponManager.GetGun("1003").PutDown(new Vector2(180, 180)); WeaponManager.GetGun("1002").PutDown(new Vector2(180, 120)); - + WeaponManager.GetGun("1004").PutDown(new Vector2(220, 120)); } public override void _Process(float delta) { + if (GameApplication.Instance.Debug) + { + Update(); + } + } + public override void _Draw() + { + if (GameApplication.Instance.Debug) + { + if (_points != null && _points.Count >= 2) + { + DrawPolyline(_points.ToArray(), Colors.Red); + } + } } /// @@ -64,6 +97,153 @@ /// public Node2D GetRoot(bool useYSort = false) { - return useYSort ? SortRoot : ObjectRoot; + return useYSort ? _sortRoot : _objectRoot; + } + + /// + /// 自动生成导航区域 + /// + private void GenerateNavigationPolygon() + { + //129 + var tileMap = _mapRoot.GetChild(0).GetNode("Wall"); + var size = tileMap.CellSize; + + var rect = tileMap.GetUsedRect(); + + var x = (int)rect.Position.x; + var y = (int)rect.Position.y; + var w = (int)rect.Size.x; + var h = (int)rect.Size.y; + + for (int i = x; i < w; i++) + { + for (int j = y; j < h; j++) + { + var tileId = tileMap.GetCell(i, j); + if (tileId != -1 && _wayIds.Contains(tileId)) + { + //--------------------------------------- + + // 0:右, 1:下, 2:左, 3:上 + var dir = 0; + _points.Clear(); + //找到路, 向右开始找边界 + _points.Add(new Vector2(i * size.x + size.x * 0.5f, j * size.y + size.y * 0.5f)); + + var tempI = i; + var tempJ = j; + + var prevI = i; + var prevJ = j; + + var len = 1; + + while (true) + { + switch (dir) + { + case 0: + tempI++; + break; + case 1: + tempJ++; + break; + case 2: + tempI--; + break; + case 3: + tempJ--; + break; + } + + bool flag = true; + int nextCellId = -1; + + switch (dir) + { + case 0: //右 + { + //向右找 + nextCellId = tileMap.GetCell(tempI, tempJ); + flag = isWayCell(nextCellId); + if (!flag) + { + if (isWayCell(tileMap.GetCell(tempI, tempJ - 1))) //向上找 + { + dir = 3 - 1; + } + } + } + break; + case 1: //下 + { + nextCellId = tileMap.GetCell(tempI, tempJ); + flag = isWayCell(nextCellId); + } + break; + case 2: //左 + { + // nextCellId = tileMap.GetCell(tempI, tempJ + 1);//向下找 + // flag = isWayCell(nextCellId); + // if (flag) + // { + // dir = 1 - 1; + // } + // else + // { + nextCellId = tileMap.GetCell(tempI, tempJ); //向左找 + flag = isWayCell(nextCellId); + //} + } + break; + case 3: //上 + { + nextCellId = tileMap.GetCell(tempI, tempJ); + flag = isWayCell(nextCellId); + } + break; + } + + if (!flag) //下一个不是可行走区域 + { + + if (len <= 1) + { + //有问题, 不支持单格道路! + GD.PrintErr("不支持单格道路: " + tempI + ", " + tempJ); + } + + tempI = prevI; + tempJ = prevJ; + //转向 + dir++; + //记录当前点 + _points.Add(new Vector2(tempI * size.x + size.x * 0.5f, tempJ * size.y + size.y * 0.5f)); + if (dir == 4) + { + goto a; + } + } + else + { + len++; + } + + prevI = tempI; + prevJ = tempJ; + } + //--------------------------------------- + } + } + } + + a: ; + + } + + private bool isWayCell(int cellId) + { + return cellId != -1 && _wayIds.Contains(cellId); } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/test/TestNavigation2.cs b/DungeonShooting_Godot/src/test/TestNavigation2.cs index 0fb004c..802a000 100644 --- a/DungeonShooting_Godot/src/test/TestNavigation2.cs +++ b/DungeonShooting_Godot/src/test/TestNavigation2.cs @@ -41,7 +41,7 @@ if (points != null && points.Length >= 2) { DrawPolyline(points, Colors.Red); - DrawMultiline(points, Colors.Red); + //DrawMultiline(points, Colors.Red); } }