Files
Aplikasi-VR-Edukasi-Mitigas…/Assets/Scripts/AStar_Manhattan.cs
Savina Rizdafayi d7120c397a Initial commit
2025-07-12 19:53:40 +07:00

173 lines
5.2 KiB
C#

using System.Collections.Generic;
using UnityEngine;
public class AStar_Manhattan : MonoBehaviour
{
public MengaturGrid grid;
public Transform pintuDepan;
public Transform pintuDapur;
public Transform pintuGarasi;
public List<Node> FindPath(Vector3 startPos, Vector3 targetPos)
{
grid.visitedNodeCount = 0;
Node startNode = grid.NodeFromWorldPoint(startPos);
Node targetNode = grid.NodeFromWorldPoint(targetPos);
List<Node> openSet = new List<Node>();
HashSet<Node> closedSet = new HashSet<Node>();
openSet.Add(startNode);
while (openSet.Count > 0)
{
Node currentNode = openSet[0];
for (int i = 1; i < openSet.Count; i++)
{
if (openSet[i].fCost < currentNode.fCost ||
(openSet[i].fCost == currentNode.fCost && openSet[i].hCost < currentNode.hCost))
{
currentNode = openSet[i];
}
}
openSet.Remove(currentNode);
closedSet.Add(currentNode);
grid.visitedNodeCount++;
if (currentNode == targetNode)
return RetracePath(startNode, targetNode);
foreach (Node neighbour in grid.GetNeighbours(currentNode))
{
if (!neighbour.walkable || closedSet.Contains(neighbour)) continue;
int newCost = currentNode.gCost + GetDistance(currentNode, neighbour);
if (newCost < neighbour.gCost || !openSet.Contains(neighbour))
{
neighbour.gCost = newCost;
neighbour.hCost = GetManhattanDistance(neighbour, targetNode);
neighbour.parent = currentNode;
if (!openSet.Contains(neighbour))
openSet.Add(neighbour);
}
}
}
return null;
}
public PathResult FindCombinedPath(Vector3 start, Vector3 pintu, Vector3 zonaAman, string label = "")
{
var stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
grid.visitedNodeCount = 0;
List<Node> path1 = FindPath(start, pintu);
Node lastNodePath1 = grid.NodeFromWorldPoint(pintu);
List<Node> path2 = FindPath(pintu, zonaAman);
Node lastNodePath2 = grid.NodeFromWorldPoint(zonaAman);
if (path1 == null || path2 == null) return null;
path1.AddRange(path2);
int panjangJalur = path1.Count;
float langkahUnit = 1f;
float kecepatanPlayer = 3f;
// Penalty
float penaltyCost = GetExitPenalty(pintu);
// Hitung total cost
int totalCost = lastNodePath1.gCost + lastNodePath2.gCost + Mathf.RoundToInt(penaltyCost * 10f);
float waktuTempuh = totalCost / (kecepatanPlayer * 10f);
stopwatch.Stop();
float waktuKomputasi = stopwatch.ElapsedMilliseconds / 1000f;
int jumlahNodeDikunjungi = grid.visitedNodeCount;
Debug.Log(
$"[Evaluasi A* - {label}]\n" +
$"- Waktu Komputasi: {waktuKomputasi:F4} detik\n" +
$"- Jumlah Node Dikunjungi: {jumlahNodeDikunjungi}\n" +
$"- Panjang Jalur: {panjangJalur} langkah\n" +
$"- Total Cost: {totalCost}\n" +
$"- Estimasi Waktu Tempuh: {waktuTempuh:F2} detik\n" +
$"- Pintu Keluar: {label}"
);
return new PathResult
{
path = path1,
totalCost = totalCost,
keterangan = label,
panjangJalur = panjangJalur,
estimasiWaktu = waktuTempuh
};
}
public List<PathResult> FindMultiplePathsMelaluiPintu(Vector3 startPos, Vector3 zonaAman, List<Vector3> pintuList, int maxJalur, List<string> namaPintu)
{
List<PathResult> semuaJalur = new List<PathResult>();
for (int i = 0; i < pintuList.Count; i++)
{
Vector3 pintu = pintuList[i];
string label = (namaPintu != null && i < namaPintu.Count) ? namaPintu[i] : $"Pintu ({pintu.x:F0},{pintu.z:F0})";
PathResult jalur = FindCombinedPath(startPos, pintu, zonaAman, label);
if (jalur != null)
semuaJalur.Add(jalur);
}
semuaJalur.Sort((a, b) => a.totalCost.CompareTo(b.totalCost));
return semuaJalur.GetRange(0, Mathf.Min(maxJalur, semuaJalur.Count));
}
List<Node> RetracePath(Node startNode, Node endNode)
{
List<Node> path = new List<Node>();
Node currentNode = endNode;
while (currentNode != startNode)
{
path.Add(currentNode);
currentNode = currentNode.parent;
}
path.Reverse();
return path;
}
int GetDistance(Node a, Node b)
{
return 10 * (Mathf.Abs(a.gridX - b.gridX) + Mathf.Abs(a.gridY - b.gridY));
}
int GetManhattanDistance(Node a, Node b)
{
return 10 * (Mathf.Abs(a.gridX - b.gridX) + Mathf.Abs(a.gridY - b.gridY));
}
float GetExitPenalty(Vector3 pintu)
{
if (pintuDepan != null && Vector3.Distance(pintu, pintuDepan.position) < 1f)
return 2f; // Pintu depan
else if (pintuDapur != null && Vector3.Distance(pintu, pintuDapur.position) < 1f)
return 1f; // Pintu dapur
else if (pintuGarasi != null && Vector3.Distance(pintu, pintuGarasi.position) < 1f)
return 1f; // Pintu garasi
return 0f; // Tidak ada penalty
}
}