Files
Savina Rizdafayi d7120c397a Initial commit
2025-07-12 19:53:40 +07:00

174 lines
5.4 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using System.Diagnostics;
public class AStar_Euclidean : MonoBehaviour
{
public MengaturGridE grid;
public Transform pintuDepan;
public Transform pintuDapur;
public Transform pintuGarasi;
public List<Node> FindPath(Vector3 startPos, Vector3 targetPos)
{
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 newMovementCostToNeighbour = currentNode.gCost + GetDistance(currentNode, neighbour);
if (newMovementCostToNeighbour < neighbour.gCost || !openSet.Contains(neighbour))
{
neighbour.gCost = newMovementCostToNeighbour;
neighbour.hCost = GetEuclideanDistance(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 = "")
{
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
List<Node> path1 = FindPath(start, pintu);
List<Node> path2 = FindPath(pintu, zonaAman);
if (path1 == null || path2 == null) return null;
path1.AddRange(path2);
float totalCost = 0f;
for (int i = 1; i < path1.Count; i++)
{
totalCost += GetEuclideanDistance(path1[i - 1], path1[i]);
}
float penalty = GetExitPenalty(pintu);
totalCost += penalty * 10f;
float kecepatanPlayer = 5f;
float waktuTempuh = totalCost / (kecepatanPlayer * 10f);
stopwatch.Stop();
float waktuKomputasi = stopwatch.ElapsedMilliseconds / 1000f;
int jumlahNodeDikunjungi = grid.visitedNodeCount;
UnityEngine.Debug.Log(
$"[Evaluasi A* - {label}]\n" +
$"- Waktu Komputasi: {waktuKomputasi:F4} detik\n" +
$"- Jumlah Node Dikunjungi: {jumlahNodeDikunjungi}\n" +
$"- Panjang Jalur: {path1.Count}\n" +
$"- Total Cost: {totalCost:F2}\n" +
$"- Pintu Keluar: {label}"
);
return new PathResult
{
path = path1,
totalCost = totalCost,
keterangan = label,
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.estimasiWaktu.CompareTo(b.estimasiWaktu));
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)
{
int dstX = Mathf.Abs(a.gridX - b.gridX);
int dstY = Mathf.Abs(a.gridY - b.gridY);
if (dstX > dstY)
return 14 * dstY + 10 * (dstX - dstY);
return 14 * dstX + 10 * (dstY - dstX);
}
int GetEuclideanDistance(Node a, Node b)
{
float dx = a.gridX - b.gridX;
float dy = a.gridY - b.gridY;
return Mathf.RoundToInt(Mathf.Sqrt(dx * dx + dy * dy) * 10);
}
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
}
}