diff --git a/DungeonShooting_Godot/src/game/room/NavigationPolygonData.cs b/DungeonShooting_Godot/src/game/room/NavigationPolygonData.cs new file mode 100644 index 0000000..c6c9085 --- /dev/null +++ b/DungeonShooting_Godot/src/game/room/NavigationPolygonData.cs @@ -0,0 +1,21 @@ + +using System.Collections.Generic; +using Godot; + +public enum NavigationPolygonType +{ + /// <summary> + /// 外轮廓 + /// </summary> + Out, + /// <summary> + /// 内轮廓 + /// </summary> + In, +} + +public class NavigationPolygonData +{ + public NavigationPolygonType Type; + public List<Vector2> Points = new List<Vector2>(); +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/room/RoomManager.cs b/DungeonShooting_Godot/src/game/room/RoomManager.cs index b86f537..3ac02c3 100644 --- a/DungeonShooting_Godot/src/game/room/RoomManager.cs +++ b/DungeonShooting_Godot/src/game/room/RoomManager.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using System.Globalization; using Godot; /// <summary> @@ -22,8 +24,14 @@ private NavigationPolygonInstance _navigationPolygon; private Enemy _enemy; + //可行走区域的tileId private List<int> _wayIds = new List<int>(new[] { 129 }); - private List<Vector2> _points = new List<Vector2>(); + + //已经标记过的点 + private HashSet<Vector2> _usePoints = new HashSet<Vector2>(); + + //导航区域数据 + private List<NavigationPolygonData> _polygonDataList = new List<NavigationPolygonData>(); public override void _EnterTree() { @@ -83,9 +91,13 @@ { if (GameApplication.Instance.Debug) { - if (_points != null && _points.Count >= 2) + for (var i = 0; i < _polygonDataList.Count; i++) { - DrawPolyline(_points.ToArray(), Colors.Red); + var item = _polygonDataList[i]; + if (item.Points.Count >= 2) + { + DrawPolyline(item.Points.ToArray(), Colors.Red); + } } } } @@ -105,7 +117,6 @@ /// </summary> private void GenerateNavigationPolygon() { - //129 var tileMap = _mapRoot.GetChild(0).GetNode<TileMap>("Wall"); var size = tileMap.CellSize; @@ -116,147 +127,519 @@ 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++) { - for (int j = y; j < h; j++) + for (int i = x; i < w; i++) { var tileId = tileMap.GetCell(i, j); - if (tileId != -1 && _wayIds.Contains(tileId)) + if (IsWayCell(tileId)) { - //--------------------------------------- - - // 0:右, 1:下, 2:左, 3:上 - var dir = 0; - _points.Clear(); - //找到路, 向右开始找边界 - var startPos = new Vector2(i * size.x + size.x * 0.5f, j * size.y + size.y * 0.5f); - _points.Add(startPos); - - var tempI = i; - var tempJ = j; - - while (true) + if (!_usePoints.Contains(new Vector2(i, j))) { - switch (dir) + NavigationPolygonData polygonData = null; + + if (!IsWayCell(tileMap.GetCell(i, j - 1))) { - case 0: //右 - { - if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //先向上找 - { - dir = 3; - var pos = new Vector2(tempI * size.x + size.x * 0.5f, - tempJ * size.y + size.y * 0.5f); - _points.Add(pos); - if (pos == startPos) goto a; - tempJ--; - } - else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //再向右找 - { - tempI++; - } - else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //向下找 - { - dir = 1; - var pos = new Vector2(tempI * size.x + size.x * 0.5f, - tempJ * size.y + size.y * 0.5f); - _points.Add(pos); - if (pos == startPos) goto a; + polygonData = CalcOutline(i, j, tileMap, size); + } + else if (!IsWayCell(tileMap.GetCell(i, j + 1))) + { + polygonData = CalcInline(i, j, tileMap, size); + } - tempJ++; - } - } - break; - case 1: //下 - { - if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //先向右找 - { - dir = 0; - var pos = new Vector2(tempI * size.x + size.x * 0.5f, - tempJ * size.y + size.y * 0.5f); - _points.Add(pos); - if (pos == startPos) goto a; - - tempI++; - } - else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //再向下找 - { - tempJ++; - } - else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //向左找 - { - dir = 2; - var pos = new Vector2(tempI * size.x + size.x * 0.5f, - tempJ * size.y + size.y * 0.5f); - _points.Add(pos); - if (pos == startPos) goto a; - - tempI--; - } - } - break; - case 2: //左 - { - if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //先向下找 - { - dir = 1; - var pos = new Vector2(tempI * size.x + size.x * 0.5f, - tempJ * size.y + size.y * 0.5f); - _points.Add(pos); - if (pos == startPos) goto a; - - tempJ++; - } - else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //再向左找 - { - tempI--; - } - else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //向上找 - { - dir = 3; - var pos = new Vector2(tempI * size.x + size.x * 0.5f, - tempJ * size.y + size.y * 0.5f); - _points.Add(pos); - if (pos == startPos) goto a; - - tempJ--; - } - } - break; - case 3: //上 - { - if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //先向左找 - { - dir = 2; - var pos = new Vector2(tempI * size.x + size.x * 0.5f, - tempJ * size.y + size.y * 0.5f); - _points.Add(pos); - if (pos == startPos) goto a; - - tempI--; - } - else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //再向上找 - { - tempJ--; - } - else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //向右找 - { - dir = 0; - var pos = new Vector2(tempI * size.x + size.x * 0.5f, - tempJ * size.y + size.y * 0.5f); - _points.Add(pos); - if (pos == startPos) goto a; - - tempI++; - } - } - break; + if (polygonData != null) + { + _polygonDataList.Add(polygonData); + //return; } } - //--------------------------------------- } } } - a: ; + } + + private NavigationPolygonData CalcOutline(int i, int j, TileMap tileMap, Vector2 size) + { + var polygonData = new NavigationPolygonData(); + var points = polygonData.Points; + // 0:右, 1:下, 2:左, 3:上 + var dir = 0; + var offset = new Vector2(size.x * 0.5f, size.y * 0.5f); + //找到路, 向右开始找边界 + var startPos = new Vector2(i, j); + + var tempI = i; + var tempJ = j; + + while (true) + { + switch (dir) + { + case 0: //右 + { + if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //先向上找 + { + dir = 3; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempJ--; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //再向右找 + { + if (points.Count == 0) + { + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempI++; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //向下找 + { + dir = 1; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempJ++; + break; + } + + return null; + } + case 1: //下 + { + if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //先向右找 + { + dir = 0; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempI++; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //再向下找 + { + if (points.Count == 0) + { + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempJ++; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //向左找 + { + dir = 2; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempI--; + break; + } + + return null; + } + case 2: //左 + { + if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //先向下找 + { + dir = 1; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempJ++; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //再向左找 + { + if (points.Count == 0) + { + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempI--; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //向上找 + { + dir = 3; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempJ--; + break; + } + + return null; + } + case 3: //上 + { + if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //先向左找 + { + dir = 2; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempI--; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //再向上找 + { + if (points.Count == 0) + { + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempJ--; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //向右找 + { + dir = 0; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempI++; + break; + } + + return null; + } + } + } + } + + private NavigationPolygonData CalcInline(int i, int j, TileMap tileMap, Vector2 size) + { + var polygonData = new NavigationPolygonData(); + var points = polygonData.Points; + // 0:右, 1:下, 2:左, 3:上 + var dir = 0; + var offset = new Vector2(size.x * 0.5f, size.y * 0.5f); + //找到路, 向右开始找边界 + var startPos = new Vector2(i, j); + + var tempI = i; + var tempJ = j; + + while (true) + { + switch (dir) + { + case 0: //右 + { + if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //向下找 + { + dir = 1; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempJ++; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //再向右找 + { + if (points.Count == 0) + { + points.Add(new Vector2((tempI - 1) * size.x, tempJ * size.y) + offset); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempI++; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //先向上找 + { + dir = 3; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempJ--; + break; + } + + return null; + } + case 1: //下 + { + if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //向左找 + { + dir = 2; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempI--; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //再向下找 + { + if (points.Count == 0) + { + points.Add(new Vector2((tempI - 1) * size.x, tempJ * size.y) + offset); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempJ++; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //先向右找 + { + dir = 0; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempI++; + break; + } + + return null; + } + case 2: //左 + { + if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //向上找 + { + dir = 3; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempJ--; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //再向左找 + { + if (points.Count == 0) + { + points.Add(new Vector2((tempI - 1) * size.x, tempJ * size.y) + offset); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempI--; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI, tempJ + 1))) //先向下找 + { + dir = 1; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempJ++; + break; + } + + return null; + } + case 3: //上 + { + if (IsWayCell(tileMap.GetCell(tempI + 1, tempJ))) //向右找 + { + dir = 0; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempI++; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI, tempJ - 1))) //再向上找 + { + if (points.Count == 0) + { + points.Add(new Vector2((tempI - 1) * size.x, tempJ * size.y) + offset); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempJ--; + break; + } + else if (IsWayCell(tileMap.GetCell(tempI - 1, tempJ))) //先向左找 + { + dir = 2; + + points.Add(new Vector2(tempI * size.x, tempJ * size.y) + offset); + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(pos); + + tempI--; + break; + } + + return null; + } + } + } + } + + private void PutUsePoint(Vector2 pos) + { + if (_usePoints.Contains(pos)) + { + throw new Exception("生成导航多边形发生错误! 点: " + pos + "发生交错!"); + } + + _usePoints.Add(pos); } private bool IsWayCell(int cellId)