自动计算ai可移动区域
1 parent 99a1712 commit 1ff8b9623035669793051b35bea8ad5dad247a8a
@小李xl 小李xl authored on 23 Nov 2022
Showing 2 changed files
View
21
DungeonShooting_Godot/src/game/room/NavigationPolygonData.cs 0 → 100644
 
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>();
}
View
1264
DungeonShooting_Godot/src/game/room/RoomManager.cs
using System;
using System.Collections.Generic;
using System.Globalization;
using Godot;
 
/// <summary>
/// 房间管理器
 
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()
{
Input.MouseMode = Input.MouseModeEnum.Hidden;
public override void _Draw()
{
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);
}
}
}
}
 
/// 自动生成导航区域
/// </summary>
private void GenerateNavigationPolygon()
{
//129
var tileMap = _mapRoot.GetChild(0).GetNode<TileMap>("Wall");
var size = tileMap.CellSize;
 
var rect = tileMap.GetUsedRect();
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++)
{
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))
{
//---------------------------------------
 
// 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)
{
switch (dir)
{
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;
 
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 (IsWayCell(tileId))
{
if (!_usePoints.Contains(new Vector2(i, j)))
{
NavigationPolygonData polygonData = null;
 
if (!IsWayCell(tileMap.GetCell(i, j - 1)))
{
polygonData = CalcOutline(i, j, tileMap, size);
}
else if (!IsWayCell(tileMap.GetCell(i, j + 1)))
{
polygonData = CalcInline(i, j, tileMap, size);
}
 
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)
{