Initial commit
This commit is contained in:
172
Assets/Scripts/AStar_Manhattan.cs
Normal file
172
Assets/Scripts/AStar_Manhattan.cs
Normal file
@ -0,0 +1,172 @@
|
||||
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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user