lab6
This commit is contained in:
1 parent
1b564e47e9
commit
7f65ead644
44 files changed
+4582
-2
No files matched your search
@@ -0,0 +1,324 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Lab6
|
||||
{
|
||||
public class GraphGrid : Graph
|
||||
{
|
||||
public GameObject obstaclePrefab;
|
||||
public string mapName = "arena.map";
|
||||
public bool get8Vicinity = false;
|
||||
public float cellSize = 1f;
|
||||
|
||||
[Range(0, Mathf.Infinity)]
|
||||
public float defaultCost = 1f;
|
||||
|
||||
private const string MapsDir = "Resources/Maps";
|
||||
private int _numCols;
|
||||
private int _numRows;
|
||||
private GameObject[] _vertexObj;
|
||||
private bool[,] _mapVertices;
|
||||
|
||||
private Dictionary<int, int> _gridIdToVertexIndex;
|
||||
|
||||
private int GridToId(int x, int y)
|
||||
{
|
||||
return _numCols * y + x;
|
||||
}
|
||||
|
||||
private Vector2Int IdToGrid(int id)
|
||||
{
|
||||
return new Vector2Int(id % _numCols, id / _numCols);
|
||||
}
|
||||
|
||||
private void LoadMap(string filename)
|
||||
{
|
||||
var path = Application.dataPath + "/" + MapsDir + "/" + filename;
|
||||
|
||||
try
|
||||
{
|
||||
var strmRdr = new StreamReader(path);
|
||||
using (strmRdr)
|
||||
{
|
||||
strmRdr.ReadLine();
|
||||
|
||||
var line = strmRdr.ReadLine();
|
||||
if (line != null && line.StartsWith("height"))
|
||||
{
|
||||
_numRows = int.Parse(line.Split(' ')[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Invalid map format: height line not found");
|
||||
return;
|
||||
}
|
||||
|
||||
line = strmRdr.ReadLine();
|
||||
if (line != null && line.StartsWith("width"))
|
||||
{
|
||||
_numCols = int.Parse(line.Split(' ')[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Invalid map format: width line not found");
|
||||
return;
|
||||
}
|
||||
|
||||
strmRdr.ReadLine();
|
||||
|
||||
var totalCells = _numRows * _numCols;
|
||||
Vertices = new List<Vertex>();
|
||||
Neighbours = new List<List<Vertex>>();
|
||||
Costs = new List<List<float>>();
|
||||
_vertexObj = new GameObject[totalCells];
|
||||
_mapVertices = new bool[_numRows, _numCols];
|
||||
_gridIdToVertexIndex = new Dictionary<int, int>();
|
||||
|
||||
Debug.Log($"Loading map {_numRows}x{_numCols} (total cells: {totalCells})");
|
||||
|
||||
for (var row = 0; row < _numRows; row++)
|
||||
{
|
||||
line = strmRdr.ReadLine();
|
||||
|
||||
if (string.IsNullOrEmpty(line) || line.Length < _numCols)
|
||||
{
|
||||
Debug.LogError($"Map line {row} is too short or missing");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var col = 0; col < _numCols; col++)
|
||||
{
|
||||
var cellChar = line[col];
|
||||
var isGround = (cellChar == '.' || cellChar == 'G' || cellChar == ' ');
|
||||
|
||||
_mapVertices[row, col] = isGround;
|
||||
|
||||
var position = new Vector3(col * cellSize, 0f, row * cellSize);
|
||||
var gridId = GridToId(col, row);
|
||||
|
||||
GameObject obj;
|
||||
|
||||
if (isGround && vertexPrefab != null)
|
||||
{
|
||||
obj = Instantiate(vertexPrefab, position, Quaternion.identity);
|
||||
}
|
||||
else if (!isGround && obstaclePrefab != null)
|
||||
{
|
||||
obj = Instantiate(obstaclePrefab, position, Quaternion.identity);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
obj.transform.position = position;
|
||||
|
||||
var renderer1 = obj.GetComponent<Renderer>();
|
||||
if (renderer1 != null)
|
||||
{
|
||||
renderer1.material.color = isGround ? Color.green : Color.red;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj == null) continue;
|
||||
|
||||
obj.name = $"{(isGround ? "Ground" : "Obstacle")}_{gridId}";
|
||||
obj.transform.parent = transform;
|
||||
|
||||
var scale = obj.transform.localScale;
|
||||
scale.x = cellSize;
|
||||
scale.z = cellSize;
|
||||
scale.y = isGround ? 0.1f : 1f;
|
||||
obj.transform.localScale = scale;
|
||||
|
||||
_vertexObj[gridId] = obj;
|
||||
|
||||
if (!isGround) continue;
|
||||
|
||||
var v = obj.GetComponent<Vertex>();
|
||||
if (v == null)
|
||||
v = obj.AddComponent<Vertex>();
|
||||
|
||||
v.id = gridId;
|
||||
v.neighbours = new List<Edge>();
|
||||
|
||||
var vertexIndex = Vertices.Count;
|
||||
Vertices.Add(v);
|
||||
Neighbours.Add(new List<Vertex>());
|
||||
Costs.Add(new List<float>());
|
||||
|
||||
_gridIdToVertexIndex[gridId] = vertexIndex;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"Created {Vertices.Count} walkable vertices");
|
||||
|
||||
foreach (var kvp in _gridIdToVertexIndex)
|
||||
{
|
||||
var gridId = kvp.Key;
|
||||
var vertexIndex = kvp.Value;
|
||||
var gridPos = IdToGrid(gridId);
|
||||
SetNeighbours(gridPos.x, gridPos.y, vertexIndex);
|
||||
}
|
||||
|
||||
Debug.Log($"Map loaded successfully. {Vertices.Count} walkable vertices");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Failed to load map: {e.Message}");
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void SetNeighbours(int x, int y, int vertexIndex)
|
||||
{
|
||||
var currentVertex = Vertices[vertexIndex];
|
||||
var gridId = currentVertex.id;
|
||||
|
||||
Neighbours[vertexIndex].Clear();
|
||||
Costs[vertexIndex].Clear();
|
||||
currentVertex.neighbours.Clear();
|
||||
|
||||
Vector2Int[] directions;
|
||||
|
||||
if (get8Vicinity)
|
||||
{
|
||||
directions = new[]
|
||||
{
|
||||
new Vector2Int(x, y - 1), new Vector2Int(x + 1, y - 1), new Vector2Int(x + 1, y), new Vector2Int(x + 1, y + 1), new Vector2Int(x, y + 1), new Vector2Int(x - 1, y + 1), new Vector2Int(x - 1, y), new Vector2Int(x - 1, y - 1)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
directions = new[]
|
||||
{
|
||||
new Vector2Int(x, y - 1), new Vector2Int(x + 1, y), new Vector2Int(x, y + 1), new Vector2Int(x - 1, y)
|
||||
};
|
||||
}
|
||||
|
||||
var diagonalCost = defaultCost * 1.4f;
|
||||
|
||||
foreach (var dir in directions)
|
||||
{
|
||||
if (dir.x < 0 || dir.x >= _numCols || dir.y < 0 || dir.y >= _numRows)
|
||||
continue;
|
||||
|
||||
if (!_mapVertices[dir.y, dir.x])
|
||||
continue;
|
||||
|
||||
var neighbourGridId = GridToId(dir.x, dir.y);
|
||||
|
||||
if (!_gridIdToVertexIndex.TryGetValue(neighbourGridId, out var neighbourIndex))
|
||||
continue;
|
||||
|
||||
var neighbourVertex = Vertices[neighbourIndex];
|
||||
|
||||
var cost = defaultCost;
|
||||
if (dir.x != x && dir.y != y)
|
||||
{
|
||||
cost = diagonalCost;
|
||||
}
|
||||
|
||||
Neighbours[vertexIndex].Add(neighbourVertex);
|
||||
Costs[vertexIndex].Add(cost);
|
||||
currentVertex.neighbours.Add(new Edge(neighbourVertex, cost));
|
||||
}
|
||||
}
|
||||
|
||||
public override void Load()
|
||||
{
|
||||
LoadMap(mapName);
|
||||
}
|
||||
|
||||
public override Vertex GetNearestVertex(Vector3 position)
|
||||
{
|
||||
var col = Mathf.RoundToInt(position.x / cellSize);
|
||||
var row = Mathf.RoundToInt(position.z / cellSize);
|
||||
|
||||
col = Mathf.Clamp(col, 0, _numCols - 1);
|
||||
row = Mathf.Clamp(row, 0, _numRows - 1);
|
||||
|
||||
if (!_mapVertices[row, col])
|
||||
{
|
||||
return FindNearestWalkable(col, row);
|
||||
}
|
||||
|
||||
var gridId = GridToId(col, row);
|
||||
|
||||
return _gridIdToVertexIndex.TryGetValue(gridId, out var vertexIndex) ? Vertices[vertexIndex] : null;
|
||||
}
|
||||
|
||||
private Vertex FindNearestWalkable(int startCol, int startRow)
|
||||
{
|
||||
var queue = new Queue<Vector2Int>();
|
||||
var explored = new HashSet<Vector2Int>();
|
||||
|
||||
queue.Enqueue(new Vector2Int(startCol, startRow));
|
||||
explored.Add(new Vector2Int(startCol, startRow));
|
||||
|
||||
const int maxSearchRadius = 20;
|
||||
var steps = 0;
|
||||
|
||||
while (queue.Count > 0 && steps < maxSearchRadius * maxSearchRadius)
|
||||
{
|
||||
var pos = queue.Dequeue();
|
||||
|
||||
if (_mapVertices[pos.y, pos.x])
|
||||
{
|
||||
var gridId = GridToId(pos.x, pos.y);
|
||||
if (_gridIdToVertexIndex.TryGetValue(gridId, out var vertexIndex))
|
||||
{
|
||||
return Vertices[vertexIndex];
|
||||
}
|
||||
}
|
||||
|
||||
var neighbours = new[]
|
||||
{
|
||||
new Vector2Int(pos.x, pos.y - 1),
|
||||
new Vector2Int(pos.x + 1, pos.y),
|
||||
new Vector2Int(pos.x, pos.y + 1),
|
||||
new Vector2Int(pos.x - 1, pos.y)
|
||||
};
|
||||
|
||||
foreach (var n in neighbours)
|
||||
{
|
||||
if (n.x < 0 || n.x >= _numCols || n.y < 0 || n.y >= _numRows || !explored.Add(n)) continue;
|
||||
queue.Enqueue(n);
|
||||
}
|
||||
|
||||
steps++;
|
||||
}
|
||||
|
||||
Debug.LogWarning($"No walkable vertex found near ({startCol}, {startRow})");
|
||||
|
||||
return Vertices.Count > 0 ? Vertices[0] : null;
|
||||
}
|
||||
|
||||
public override Vertex[] GetNeighbours(Vertex v)
|
||||
{
|
||||
if (!v || Vertices == null || Neighbours == null || !_gridIdToVertexIndex.TryGetValue(v.id, out var vertexIndex) || vertexIndex < 0 || vertexIndex >= Neighbours.Count || Neighbours[vertexIndex] == null)
|
||||
return Array.Empty<Vertex>();
|
||||
|
||||
return Neighbours[vertexIndex].ToArray();
|
||||
}
|
||||
|
||||
public override Edge[] GetEdges(Vertex v)
|
||||
{
|
||||
if (!v || v.neighbours == null)
|
||||
return Array.Empty<Edge>();
|
||||
|
||||
return v.neighbours.ToArray();
|
||||
}
|
||||
|
||||
public override Vertex GetVertexObj(int id)
|
||||
{
|
||||
if (!_gridIdToVertexIndex.TryGetValue(id, out var vertexIndex)) return null;
|
||||
|
||||
if (vertexIndex >= 0 && vertexIndex < Vertices.Count)
|
||||
return Vertices[vertexIndex];
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user