Map Manager
- 현재 맵 gird 데이터, 크기, 충돌 타일 등의 데이터를 관리한다.
- Game Object에게 길찾기 알고리즘을 제공한다. (사용 안함)
📄 MapManager.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public struct Pos
{
public Pos(int y, int x) { Y = y; X = x; }
public int Y;
public int X;
}
public struct PQNode : IComparable<PQNode>
{
public int F;
public int G;
public int Y;
public int X;
public int CompareTo(PQNode other)
{
if (F == other.F)
return 0;
return F < other.F ? 1 : -1;
}
}
public class MapManager
{
public Grid CurrentGrid { get; private set; }
public int MinX { get; set; }
public int MaxX { get; set; }
public int MinY { get; set; }
public int MaxY { get; set; }
public int SizeX { get { return MaxX - MinX + 1; } }
public int SizeY { get { return MaxY - MinY + 1; } }
bool[,] _collision;
public bool CanGo(Vector3Int cellPos)
{
if (cellPos.x < MinX || cellPos.x > MaxX)
return false;
if (cellPos.y < MinY || cellPos.y > MaxY)
return false;
int x = cellPos.x - MinX;
int y = MaxY - cellPos.y;
return !_collision[y, x];
}
public void LoadMap(int mapId)
{
DestroyMap();
string mapName = "Map_" + mapId.ToString("000");
GameObject go = Managers.Resource.Instantiate($"Map/{mapName}");
go.name = "Map";
GameObject collision = Util.FindChild(go, "Tilemap_Collision", true);
if (collision != null)
collision.SetActive(false);
CurrentGrid = go.GetComponent<Grid>();
TextAsset txt = Managers.Resource.Load<TextAsset>($"Map/{mapName}");
StringReader reader = new StringReader(txt.text);
MinX = int.Parse(reader.ReadLine());
MaxX = int.Parse(reader.ReadLine());
MinY = int.Parse(reader.ReadLine());
MaxY = int.Parse(reader.ReadLine());
int xCount = MaxX - MinX + 1;
int yCount = MaxY - MinY + 1;
_collision = new bool[yCount, xCount];
for (int y = 0; y < yCount; y++)
{
string line = reader.ReadLine();
for (int x = 0; x < xCount; x++)
{
_collision[y, x] = (line[x] == '1' ? true : false);
}
}
}
public void DestroyMap()
{
GameObject map = GameObject.Find("Map");
if (map != null)
{
GameObject.Destroy(map);
CurrentGrid = null;
}
}
#region A* PathFinding
int[] _deltaY = new int[] { 1, -1, 0, 0 };
int[] _deltaX = new int[] { 0, 0, -1, 1 };
int[] _cost = new int[] { 10, 10, 10, 10 };
public List<Vector3Int> FindPath(Vector3Int startCellPos, Vector3Int destCellPos, bool ignoreDestCollision = false)
{
List<Pos> path = new List<Pos>();
bool[,] closed = new bool[SizeY, SizeX];
int[,] open = new int[SizeY, SizeX];
for (int y = 0; y < SizeY; y++)
for (int x = 0; x < SizeX; x++)
open[y, x] = Int32.MaxValue;
Pos[,] parent = new Pos[SizeY, SizeX];
PriorityQueue<PQNode> pq = new PriorityQueue<PQNode>();
Pos pos = Cell2Pos(startCellPos);
Pos dest = Cell2Pos(destCellPos);
open[pos.Y, pos.X] = 10 * (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X));
pq.Push(new PQNode() { F = 10 * (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X)), G = 0, Y = pos.Y, X = pos.X });
parent[pos.Y, pos.X] = new Pos(pos.Y, pos.X);
while (pq.Count > 0)
{
PQNode node = pq.Pop();
if (closed[node.Y, node.X])
continue;
closed[node.Y, node.X] = true;
if (node.Y == dest.Y && node.X == dest.X)
break;
for (int i = 0; i < _deltaY.Length; i++)
{
Pos next = new Pos(node.Y + _deltaY[i], node.X + _deltaX[i]);
if (!ignoreDestCollision || next.Y != dest.Y || next.X != dest.X)
{
if (CanGo(Pos2Cell(next)) == false)
continue;
}
if (closed[next.Y, next.X])
continue;
int g = 0;
int h = 10 * ((dest.Y - next.Y) * (dest.Y - next.Y) + (dest.X - next.X) * (dest.X - next.X));
if (open[next.Y, next.X] < g + h)
continue;
open[dest.Y, dest.X] = g + h;
pq.Push(new PQNode() { F = g + h, G = g, Y = next.Y, X = next.X });
parent[next.Y, next.X] = new Pos(node.Y, node.X);
}
}
return CalcCellPathFromParent(parent, dest);
}
List<Vector3Int> CalcCellPathFromParent(Pos[,] parent, Pos dest)
{
List<Vector3Int> cells = new List<Vector3Int>();
int y = dest.Y;
int x = dest.X;
while (parent[y, x].Y != y || parent[y, x].X != x)
{
cells.Add(Pos2Cell(new Pos(y, x)));
Pos pos = parent[y, x];
y = pos.Y;
x = pos.X;
}
cells.Add(Pos2Cell(new Pos(y, x)));
cells.Reverse();
return cells;
}
Pos Cell2Pos(Vector3Int cell)
{
return new Pos(MaxY - cell.y, cell.x - MinX);
}
Vector3Int Pos2Cell(Pos pos)
{
return new Vector3Int(pos.X + MinX, MaxY - pos.Y, 0);
}
#endregion
}