mirror of
https://github.com/BobbyRafael31/Unity-MazeRunner-Pathfinding-Visualizer.git
synced 2025-08-13 08:52:21 +00:00
feat saving include npc position
This commit is contained in:
8
Assets/Docs.meta
Normal file
8
Assets/Docs.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3c5678ad04a64df4db73256f9e23d75c
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -336,7 +336,7 @@ RectTransform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
m_AnchorMax: {x: 0, y: 0}
|
m_AnchorMax: {x: 0, y: 0}
|
||||||
m_AnchoredPosition: {x: 52.600037, y: 49.700073}
|
m_AnchoredPosition: {x: 52.600098, y: 49.700073}
|
||||||
m_SizeDelta: {x: 81.71, y: 19.77002}
|
m_SizeDelta: {x: 81.71, y: 19.77002}
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!114 &23184662
|
--- !u!114 &23184662
|
||||||
@ -1684,7 +1684,7 @@ RectTransform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 1, y: 0}
|
m_AnchorMin: {x: 1, y: 0}
|
||||||
m_AnchorMax: {x: 1, y: 1}
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
m_AnchoredPosition: {x: -13.392517, y: 0}
|
m_AnchoredPosition: {x: -13.392578, y: 0}
|
||||||
m_SizeDelta: {x: 26.785, y: 0}
|
m_SizeDelta: {x: 26.785, y: 0}
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!114 &249188175
|
--- !u!114 &249188175
|
||||||
@ -7311,8 +7311,8 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 42bfb8854d690bf4fa7ccf911313d0ae, type: 3}
|
m_Script: {fileID: 11500000, guid: 42bfb8854d690bf4fa7ccf911313d0ae, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
numX: 20
|
numX: 10
|
||||||
numY: 20
|
numY: 10
|
||||||
gridNodeViewPrefab: {fileID: 5382759684804752574, guid: bfa28317eb98f2846969e3ffce05f685, type: 3}
|
gridNodeViewPrefab: {fileID: 5382759684804752574, guid: bfa28317eb98f2846969e3ffce05f685, type: 3}
|
||||||
allowDiagonalMovement: 0
|
allowDiagonalMovement: 0
|
||||||
COLOR_WALKABLE: {r: 1, g: 1, b: 1, a: 1}
|
COLOR_WALKABLE: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
@ -489,6 +489,22 @@ public class GridMap : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Simple class to store grid positions for serialization
|
||||||
|
/// </summary>
|
||||||
|
[System.Serializable]
|
||||||
|
public class SerializablePosition
|
||||||
|
{
|
||||||
|
public float x;
|
||||||
|
public float y;
|
||||||
|
|
||||||
|
public SerializablePosition(float x, float y)
|
||||||
|
{
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Kelas untuk menyimpan status grid untuk keperluan save/load
|
/// Kelas untuk menyimpan status grid untuk keperluan save/load
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -496,6 +512,8 @@ public class GridMap : MonoBehaviour
|
|||||||
public class GridState
|
public class GridState
|
||||||
{
|
{
|
||||||
public bool[,] walkableStates;
|
public bool[,] walkableStates;
|
||||||
|
public SerializablePosition npcPosition; // Position of NPC
|
||||||
|
public SerializablePosition destinationPosition; // Position of destination
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -525,15 +543,33 @@ public class GridMap : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save NPC position using our serializable class
|
||||||
|
gridState.npcPosition = new SerializablePosition(
|
||||||
|
npc.transform.position.x / GridNodeWidth,
|
||||||
|
npc.transform.position.y / GridNodeHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
// Save destination position using our serializable class
|
||||||
|
gridState.destinationPosition = new SerializablePosition(
|
||||||
|
destination.position.x / GridNodeWidth,
|
||||||
|
destination.position.y / GridNodeHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
// Configure serializer settings to ignore Unity-specific circular references
|
||||||
|
JsonSerializerSettings settings = new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
||||||
|
};
|
||||||
|
|
||||||
// Mengkonversi ke JSON dan menyimpan ke file
|
// Mengkonversi ke JSON dan menyimpan ke file
|
||||||
string json = JsonConvert.SerializeObject(gridState);
|
string json = JsonConvert.SerializeObject(gridState, settings);
|
||||||
File.WriteAllText(filePath, json);
|
File.WriteAllText(filePath, json);
|
||||||
|
|
||||||
//Debug.Log($"Grid state saved to {filePath}");
|
Debug.Log($"Grid state saved to {filePath}");
|
||||||
}
|
}
|
||||||
catch (System.Exception e)
|
catch (System.Exception e)
|
||||||
{
|
{
|
||||||
//Debug.LogError($"Error saving grid state: {e.Message}");
|
Debug.LogError($"Error saving grid state: {e.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,19 +583,26 @@ public class GridMap : MonoBehaviour
|
|||||||
{
|
{
|
||||||
if (!File.Exists(filePath))
|
if (!File.Exists(filePath))
|
||||||
{
|
{
|
||||||
//Debug.LogError($"Save file not found: {filePath}");
|
Debug.LogError($"Save file not found: {filePath}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Membaca dan mengkonversi data dari file JSON
|
// Membaca dan mengkonversi data dari file JSON
|
||||||
string json = File.ReadAllText(filePath);
|
string json = File.ReadAllText(filePath);
|
||||||
GridState gridState = JsonConvert.DeserializeObject<GridState>(json);
|
|
||||||
|
// Configure deserializer settings to handle missing properties (compatibility)
|
||||||
|
JsonSerializerSettings settings = new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
MissingMemberHandling = MissingMemberHandling.Ignore
|
||||||
|
};
|
||||||
|
|
||||||
|
GridState gridState = JsonConvert.DeserializeObject<GridState>(json, settings);
|
||||||
|
|
||||||
// Periksa apakah ukuran grid dalam file sesuai dengan grid saat ini
|
// Periksa apakah ukuran grid dalam file sesuai dengan grid saat ini
|
||||||
if (gridState.walkableStates.GetLength(0) != numX ||
|
if (gridState.walkableStates.GetLength(0) != numX ||
|
||||||
gridState.walkableStates.GetLength(1) != numY)
|
gridState.walkableStates.GetLength(1) != numY)
|
||||||
{
|
{
|
||||||
//Debug.LogWarning($"Grid size mismatch. File: {gridState.walkableStates.GetLength(0)}x{gridState.walkableStates.GetLength(1)}, Current: {numX}x{numY}. Resizing grid...");
|
Debug.LogWarning($"Grid size mismatch. File: {gridState.walkableStates.GetLength(0)}x{gridState.walkableStates.GetLength(1)}, Current: {numX}x{numY}. Resizing grid...");
|
||||||
ResizeGrid(gridState.walkableStates.GetLength(0), gridState.walkableStates.GetLength(1));
|
ResizeGrid(gridState.walkableStates.GetLength(0), gridState.walkableStates.GetLength(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,11 +616,82 @@ public class GridMap : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Debug.Log($"Grid state loaded from {filePath}");
|
// Check if this is an older save file version (backward compatibility)
|
||||||
|
bool hasPositionData = gridState.npcPosition != null && gridState.destinationPosition != null;
|
||||||
|
|
||||||
|
// Load NPC position if saved
|
||||||
|
if (npc != null)
|
||||||
|
{
|
||||||
|
if (hasPositionData)
|
||||||
|
{
|
||||||
|
// Find the closest valid grid node position
|
||||||
|
int npcX = Mathf.Clamp(Mathf.RoundToInt(gridState.npcPosition.x), 0, numX - 1);
|
||||||
|
int npcY = Mathf.Clamp(Mathf.RoundToInt(gridState.npcPosition.y), 0, numY - 1);
|
||||||
|
|
||||||
|
// Make sure the position is walkable
|
||||||
|
GridNode npcNode = GetGridNode(npcX, npcY);
|
||||||
|
if (npcNode != null && npcNode.IsWalkable)
|
||||||
|
{
|
||||||
|
// Set NPC position
|
||||||
|
npc.SetStartNode(npcNode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Find a walkable node if the saved position isn't walkable
|
||||||
|
FindWalkableNodeAndSetNPC();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// For older save files, find a walkable position
|
||||||
|
FindWalkableNodeAndSetNPC();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load destination position if saved
|
||||||
|
if (destination != null)
|
||||||
|
{
|
||||||
|
if (hasPositionData)
|
||||||
|
{
|
||||||
|
// Find the closest valid grid node position
|
||||||
|
int destX = Mathf.Clamp(Mathf.RoundToInt(gridState.destinationPosition.x), 0, numX - 1);
|
||||||
|
int destY = Mathf.Clamp(Mathf.RoundToInt(gridState.destinationPosition.y), 0, numY - 1);
|
||||||
|
|
||||||
|
// Set destination position
|
||||||
|
SetDestination(destX, destY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// For older save files, set destination to the opposite corner or a walkable node
|
||||||
|
FindWalkableNodeAndSetDestination();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"Grid state loaded from {filePath}");
|
||||||
}
|
}
|
||||||
catch (System.Exception e)
|
catch (System.Exception e)
|
||||||
{
|
{
|
||||||
//Debug.LogError($"Error loading grid state: {e.Message}");
|
Debug.LogError($"Error loading grid state: {e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Find a walkable node and set the NPC position to it
|
||||||
|
/// </summary>
|
||||||
|
private void FindWalkableNodeAndSetNPC()
|
||||||
|
{
|
||||||
|
// Find first walkable node
|
||||||
|
for (int i = 0; i < numX; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < numY; j++)
|
||||||
|
{
|
||||||
|
GridNode node = GetGridNode(i, j);
|
||||||
|
if (node != null && node.IsWalkable)
|
||||||
|
{
|
||||||
|
npc.SetStartNode(node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1007,4 +1121,46 @@ public class GridMap : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Find a walkable node and set the destination position to it
|
||||||
|
/// </summary>
|
||||||
|
private void FindWalkableNodeAndSetDestination()
|
||||||
|
{
|
||||||
|
// Try to place destination in the far corner from the NPC
|
||||||
|
int npcX = (int)(npc.transform.position.x / GridNodeWidth);
|
||||||
|
int npcY = (int)(npc.transform.position.y / GridNodeHeight);
|
||||||
|
|
||||||
|
// Try opposite corner first
|
||||||
|
int destX = numX - 1;
|
||||||
|
int destY = numY - 1;
|
||||||
|
|
||||||
|
GridNode destinationNode = GetGridNode(destX, destY);
|
||||||
|
if (destinationNode != null && destinationNode.IsWalkable)
|
||||||
|
{
|
||||||
|
SetDestination(destX, destY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the opposite corner isn't walkable, find any walkable node that's different from NPC position
|
||||||
|
for (int i = numX - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
for (int j = numY - 1; j >= 0; j--)
|
||||||
|
{
|
||||||
|
// Skip the node where NPC is
|
||||||
|
if (i == npcX && j == npcY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
GridNode node = GetGridNode(i, j);
|
||||||
|
if (node != null && node.IsWalkable)
|
||||||
|
{
|
||||||
|
SetDestination(i, j);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no suitable node found, use the NPC node as a fallback
|
||||||
|
SetDestination(npcX, npcY);
|
||||||
|
}
|
||||||
}
|
}
|
@ -254,6 +254,9 @@ public class NPC : MonoBehaviour
|
|||||||
// Pre-allocate visualizationSteps with estimated capacity to avoid reallocations
|
// Pre-allocate visualizationSteps with estimated capacity to avoid reallocations
|
||||||
visualizationSteps = new List<PathfindingVisualizationStep>(4);
|
visualizationSteps = new List<PathfindingVisualizationStep>(4);
|
||||||
|
|
||||||
|
GC.Collect();
|
||||||
|
GC.WaitForPendingFinalizers(); // Tunggu semua finalizers selesai
|
||||||
|
|
||||||
// ===== MEMORY MEASUREMENT START: Ukur memory sebelum algoritma =====
|
// ===== MEMORY MEASUREMENT START: Ukur memory sebelum algoritma =====
|
||||||
long memoryBefore = System.GC.GetTotalMemory(false);
|
long memoryBefore = System.GC.GetTotalMemory(false);
|
||||||
|
|
||||||
@ -281,6 +284,13 @@ public class NPC : MonoBehaviour
|
|||||||
long memoryAfter = System.GC.GetTotalMemory(false);
|
long memoryAfter = System.GC.GetTotalMemory(false);
|
||||||
long memoryUsed = memoryAfter - memoryBefore;
|
long memoryUsed = memoryAfter - memoryBefore;
|
||||||
|
|
||||||
|
// float miliseconds = algorithmTimer.ElapsedMilliseconds;
|
||||||
|
|
||||||
|
//UnityEngine.Debug.Log("$algorithmTimer.ElapsedTicks: " + algorithmTimer.ElapsedTicks);
|
||||||
|
//UnityEngine.Debug.Log("$Stopwatch.Frequency: " + Stopwatch.Frequency);
|
||||||
|
//float seconds = (float)algorithmTimer.ElapsedTicks / Stopwatch.Frequency;
|
||||||
|
//UnityEngine.Debug.Log("$seconds: " + seconds);
|
||||||
|
|
||||||
float milliseconds = (algorithmTimer.ElapsedTicks * 1000.0f) / Stopwatch.Frequency;
|
float milliseconds = (algorithmTimer.ElapsedTicks * 1000.0f) / Stopwatch.Frequency;
|
||||||
|
|
||||||
// Calculate path length once and reuse
|
// Calculate path length once and reuse
|
||||||
|
@ -374,7 +374,7 @@ public class PathfindingUIManager : MonoBehaviour
|
|||||||
string filePath = Path.Combine(saveDirectory, $"{mapNameInput.text}.json");
|
string filePath = Path.Combine(saveDirectory, $"{mapNameInput.text}.json");
|
||||||
gridMap.SaveGridState(filePath);
|
gridMap.SaveGridState(filePath);
|
||||||
|
|
||||||
Debug.Log($"Map saved to: {filePath}");
|
Debug.Log($"Map saved to: {filePath} (includes grid state, NPC position, and destination position)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
Reference in New Issue
Block a user