Skip to content

Commit e15d41a

Browse files
author
JasonNumberThirteen
committed
Fix working of the algorithm on enabled diagonal movement
1 parent e524434 commit e15d41a

13 files changed

Lines changed: 106 additions & 127 deletions

Assets/Project/Scripts/Data Structures.meta

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
public class MapTileNodeData
2+
{
3+
public float TotalCost => RealValue + HeuristicValue;
4+
5+
public MapTileNode Parent {get; private set;}
6+
public float RealValue {get; private set;}
7+
public float HeuristicValue {get; private set;}
8+
9+
public void SetValues(MapTileNode parentMapTileNode, float realValue, float heuristicValue)
10+
{
11+
Parent = parentMapTileNode;
12+
RealValue = realValue;
13+
HeuristicValue = heuristicValue;
14+
}
15+
}

Assets/Project/Scripts/Data Structures/MapTileNodeData.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/Project/Scripts/Data Structures/PriorityQueue.cs

Lines changed: 0 additions & 22 deletions
This file was deleted.

Assets/Project/Scripts/Data Structures/PriorityQueue.cs.meta

Lines changed: 0 additions & 2 deletions
This file was deleted.

Assets/Project/Scripts/Game Objects/Map Tile/MapTile.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,13 @@ public void ModifyWeightBy(int weight)
4545
SetWeightTo(this.weight + weight);
4646
}
4747

48-
public void SetWeightTo(int weight)
48+
private void Awake()
49+
{
50+
mapTileNode = GetComponent<MapTileNode>();
51+
visualiserEventsManager = FindFirstObjectByType<VisualiserEventsManager>();
52+
}
53+
54+
private void SetWeightTo(int weight)
4955
{
5056
var previousWeight = this.weight;
5157

@@ -66,10 +72,4 @@ public void SetWeightTo(int weight)
6672
visualiserEventsManager.SendEvent(new MapTileBoolVisualiserEvent(this, VisualiserEventType.MapTileWeightWasChanged, true));
6773
}
6874
}
69-
70-
private void Awake()
71-
{
72-
mapTileNode = GetComponent<MapTileNode>();
73-
visualiserEventsManager = FindFirstObjectByType<VisualiserEventsManager>();
74-
}
7575
}

Assets/Project/Scripts/Game Objects/Map Tile/MapTileNode.cs

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,19 @@
66
public class MapTileNode : MonoBehaviour
77
{
88
public UnityEvent<MapTileNodeType> mapTileNodeTypeWasChangedEvent;
9-
9+
1010
public int Weight {get; set;}
11-
public MapTileNode Parent {get; set;}
1211

1312
private MapTileNodeType mapTileNodeType;
1413
private PathfindingManager pathfindingManager;
1514

15+
private readonly MapTileNodeData mapTileNodeData = new();
1616
private readonly List<MapTileNode> neighbours = new();
1717

1818
public Vector2 GetPosition() => transform.position;
1919
public List<MapTileNode> GetNeighbours() => neighbours;
2020
public MapTileNodeType GetMapTileNodeType() => mapTileNodeType;
21-
22-
public float GetCostToReachTo(MapTileNode destinationMapTileNode)
23-
{
24-
if(destinationMapTileNode == null)
25-
{
26-
return float.MaxValue;
27-
}
28-
29-
var heuristicValue = pathfindingManager != null ? pathfindingManager.GetHeuristicValue(GetPosition(), destinationMapTileNode.GetPosition()) : 0f;
30-
31-
return GetPathLengthFromStart() + heuristicValue;
32-
}
21+
public MapTileNodeData GetMapTileNodeData() => mapTileNodeData;
3322

3423
public void SetTileNodeType(MapTileNodeType mapTileNodeType)
3524
{
@@ -48,8 +37,7 @@ public void SetTileNodeType(MapTileNodeType mapTileNodeType)
4837
public void ResetData()
4938
{
5039
SetTileNodeType(MapTileNodeType.Unvisited);
51-
52-
Parent = null;
40+
mapTileNodeData.SetValues(null, 0, 0);
5341
}
5442

5543
public void FindNeighbours(List<MapTileNode> mapTileNodes)
@@ -76,16 +64,4 @@ private void AddNeighbourIfPossible(List<MapTileNode> mapTileNodes, Vector2 dire
7664
neighbours.Add(neighbouringNode);
7765
}
7866
}
79-
80-
private int GetPathLengthFromStart()
81-
{
82-
var length = 0;
83-
84-
if(pathfindingManager != null)
85-
{
86-
pathfindingManager.OperateOnMapTileNodes(this, mapTileNode => length += mapTileNode.Weight);
87-
}
88-
89-
return length;
90-
}
9167
}

Assets/Project/Scripts/Managers/HeuristicManager.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ public class HeuristicManager : MonoBehaviour
55
private HeuristicType heuristicType;
66
private float heuristicWeight;
77

8+
private static readonly float TIE_BREAKING_HEURISTIC_MULTIPLIER = 0.001f;
9+
810
public void SetHeuristicType(HeuristicType heuristicType)
911
{
1012
this.heuristicType = heuristicType;
@@ -17,6 +19,7 @@ public void SetHeuristicWeight(float weight)
1719

1820
public float GetHeuristicValue(Vector2 positionA, Vector2 positionB)
1921
{
22+
var heuristicMultiplier = 1 + TIE_BREAKING_HEURISTIC_MULTIPLIER;
2023
var heuristicValue = heuristicType switch
2124
{
2225
HeuristicType.ManhattanDistance => DistanceMethods.GetOneDimensionalDistance(positionA.x, positionB.x) + DistanceMethods.GetOneDimensionalDistance(positionA.y, positionB.y),
@@ -25,6 +28,6 @@ public float GetHeuristicValue(Vector2 positionA, Vector2 positionB)
2528
_ => 0f
2629
};
2730

28-
return heuristicValue*heuristicWeight;
31+
return heuristicValue*heuristicWeight*heuristicMultiplier;
2932
}
3033
}

Assets/Project/Scripts/Managers/PathfindingManager.cs

Lines changed: 63 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System;
21
using System.Linq;
32
using System.Collections;
43
using System.Collections.Generic;
@@ -14,8 +13,8 @@ public class PathfindingManager : MonoBehaviour
1413

1514
private readonly List<MapTile> mapTilesInScene = new();
1615
private readonly List<MapTileNode> pathMapTileNodes = new();
16+
private readonly List<MapTileNode> mapTileNodesWaitingForVisit = new();
1717
private readonly List<IMapEditingElement> mapEditingElements = new();
18-
private readonly PriorityQueue<MapTileNode> priorityQueue = new();
1918

2019
private MapTile startMapTile;
2120
private MapTile destinationMapTile;
@@ -59,7 +58,6 @@ private bool PathfindingWasStarted
5958
}
6059
}
6160

62-
public float GetHeuristicValue(Vector2 positionA, Vector2 positionB) => heuristicManager != null ? heuristicManager.GetHeuristicValue(positionA, positionB) : 0f;
6361
public bool DiagonalMovementIsEnabled() => diagonalMovementIsEnabled;
6462

6563
public void FindPath()
@@ -86,18 +84,6 @@ public void ClearResults()
8684
resultsWereClearedEvent?.Invoke();
8785
}
8886

89-
public void OperateOnMapTileNodes(MapTileNode mapTileNodeToStartFrom, Action<MapTileNode> action)
90-
{
91-
var currentMapTileNode = mapTileNodeToStartFrom;
92-
93-
while (currentMapTileNode.Parent != null)
94-
{
95-
action?.Invoke(currentMapTileNode);
96-
97-
currentMapTileNode = currentMapTileNode.Parent;
98-
}
99-
}
100-
10187
public void SetDiagonalMovementEnabled(bool enabled)
10288
{
10389
diagonalMovementIsEnabled = enabled;
@@ -202,7 +188,7 @@ private void ClearData()
202188
destinationMapTile = mapTilesInScene.FirstOrDefault(mapTile => mapTile.GetTileType() == MapTileType.Destination);
203189

204190
ClearResults();
205-
priorityQueue.Clear();
191+
mapTileNodesWaitingForVisit.Clear();
206192
CreateConnectionsBetweenMapTileNodes();
207193
}
208194

@@ -221,19 +207,28 @@ private void InitiatePathfinder()
221207
}
222208

223209
mapTilesInScene.ForEach(mapTile => mapTile.GetMapTileNode().ResetData());
224-
startMapTile.SetWeightTo(0);
225-
AddMapTileNodeToQueue(startMapTile.GetMapTileNode());
210+
InitiateStartMapTile();
226211

227212
PathWasFound = false;
228213
}
229214

215+
private void InitiateStartMapTile()
216+
{
217+
if(startMapTile != null)
218+
{
219+
mapTileNodesWaitingForVisit.Add(startMapTile.GetMapTileNode());
220+
}
221+
}
222+
230223
private IEnumerator FindPathToDestination()
231224
{
232225
var simulationIsEnabled = simulationManager != null && simulationManager.SimulationIsEnabled();
233226

234-
while (!pathWasFound && priorityQueue.Count > 0)
227+
while (!pathWasFound && mapTileNodesWaitingForVisit.Count > 0)
235228
{
236-
if(VisitMapTileNodeIfNeeded(priorityQueue.Dequeue()) && simulationIsEnabled)
229+
var currentMapTileNode = mapTileNodesWaitingForVisit.OrderBy(mapTileNode => mapTileNode.GetMapTileNodeData().TotalCost).FirstOrDefault();
230+
231+
if(VisitMapTileNodeIfPossible(currentMapTileNode) && simulationIsEnabled)
237232
{
238233
yield return simulationManager.GetNextStepDelayDependingOnSimulationType();
239234
}
@@ -242,16 +237,17 @@ private IEnumerator FindPathToDestination()
242237
PathfindingWasStarted = false;
243238
}
244239

245-
private bool VisitMapTileNodeIfNeeded(MapTileNode mapTileNode)
240+
private bool VisitMapTileNodeIfPossible(MapTileNode mapTileNode)
246241
{
247-
if(mapTileNode == null || mapTileNode.GetMapTileNodeType() == MapTileNodeType.Visited || destinationMapTile == null)
242+
if(mapTileNode == null)
248243
{
249244
return false;
250245
}
251-
246+
252247
mapTileNode.SetTileNodeType(MapTileNodeType.Visited);
253-
OperateOnMapTileNode(mapTileNode);
248+
mapTileNodesWaitingForVisit.Remove(mapTileNode);
254249
mapTileNodeWasVisitedEvent?.Invoke(mapTileNode);
250+
OperateOnMapTileNode(mapTileNode);
255251

256252
return true;
257253
}
@@ -269,7 +265,7 @@ private void OperateOnMapTileNode(MapTileNode mapTileNode)
269265
}
270266
else
271267
{
272-
AddNeighboursOf(mapTileNode);
268+
OperateOnNeighboursOf(mapTileNode);
273269
}
274270
}
275271

@@ -282,40 +278,66 @@ private void FinishSearchingOn(MapTileNode mapTileNode)
282278

283279
PathWasFound = true;
284280

285-
OperateOnMapTileNodes(mapTileNode, mapTileNode => pathMapTileNodes.Add(mapTileNode));
281+
DefinePathMapTileNodes(mapTileNode);
286282
pathMapTileNodes.ForEach(mapTileNode => mapTileNode.SetTileNodeType(MapTileNodeType.BelongingToPath));
287283
pathWasFoundEvent?.Invoke(pathMapTileNodes);
288284
}
289285

290-
private void AddNeighboursOf(MapTileNode mapTileNode)
286+
private void DefinePathMapTileNodes(MapTileNode mapTileNodeToStartFrom)
291287
{
292-
if(mapTileNode == null)
293-
{
294-
return;
295-
}
288+
var currentMapTileNode = mapTileNodeToStartFrom;
289+
var currentMapTileNodeData = currentMapTileNode.GetMapTileNodeData();
296290

297-
var neighbours = mapTileNode.GetNeighbours().Where(neighbour => neighbour.GetMapTileNodeType() != MapTileNodeType.Visited).ToList();
291+
while (currentMapTileNodeData.Parent != null)
292+
{
293+
pathMapTileNodes.Add(currentMapTileNode);
298294

299-
neighbours?.ForEach(neighbour => SetupAndAddNeighbour(neighbour, mapTileNode));
295+
currentMapTileNode = currentMapTileNodeData.Parent;
296+
currentMapTileNodeData = currentMapTileNode.GetMapTileNodeData();
297+
}
300298
}
301299

302-
private void SetupAndAddNeighbour(MapTileNode neighbouringMapTile, MapTileNode parentMapTile)
300+
private void OperateOnNeighboursOf(MapTileNode parentMapTileNode)
303301
{
304-
neighbouringMapTile.Parent = parentMapTile;
302+
if(parentMapTileNode == null)
303+
{
304+
return;
305+
}
306+
307+
var neighbours = parentMapTileNode.GetNeighbours().Where(neighbour => neighbour.GetMapTileNodeType() != MapTileNodeType.Visited).ToList();
305308

306-
AddMapTileNodeToQueue(neighbouringMapTile);
309+
neighbours.ForEach(neighbour => OperateOnNeighbourIfNeeded(parentMapTileNode, neighbour));
307310
}
308311

309-
private void AddMapTileNodeToQueue(MapTileNode mapTileNode)
312+
private void OperateOnNeighbourIfNeeded(MapTileNode parentMapTileNode, MapTileNode neighbouringMapTileNode)
310313
{
311-
if(mapTileNode == null)
314+
if(parentMapTileNode == null || neighbouringMapTileNode == null)
312315
{
313316
return;
314317
}
318+
319+
var totalCostToReachNeighbourFromParent = GetTotalCostToReachNeighbourFromParent(parentMapTileNode, neighbouringMapTileNode);
320+
var neighbourIsAlreadyWaitingForVisit = mapTileNodesWaitingForVisit.Contains(neighbouringMapTileNode);
321+
var neighbourMapTileNodeData = neighbouringMapTileNode.GetMapTileNodeData();
315322

316-
var mapTileNodeCost = mapTileNode.GetCostToReachTo(destinationMapTile.GetMapTileNode());
317-
var mapTileNodeWithCost = new PriorityQueueElement<MapTileNode>(mapTileNode, mapTileNodeCost);
323+
if(neighbourIsAlreadyWaitingForVisit && totalCostToReachNeighbourFromParent >= neighbourMapTileNodeData.RealValue)
324+
{
325+
return;
326+
}
327+
328+
neighbourMapTileNodeData.SetValues(parentMapTileNode, totalCostToReachNeighbourFromParent, heuristicManager != null ? heuristicManager.GetHeuristicValue(neighbouringMapTileNode.GetPosition(), destinationMapTile.GetMapTileNode().GetPosition()) : 0f);
329+
330+
if(!neighbourIsAlreadyWaitingForVisit)
331+
{
332+
mapTileNodesWaitingForVisit.Add(neighbouringMapTileNode);
333+
}
334+
}
318335

319-
priorityQueue.Enqueue(mapTileNodeWithCost);
336+
private float GetTotalCostToReachNeighbourFromParent(MapTileNode parentMapTileNode, MapTileNode neighbouringMapTileNode)
337+
{
338+
var distanceToNeighbour = DistanceMethods.DistanceBetweenPositionsIsSingleAxis(parentMapTileNode.GetPosition(), neighbouringMapTileNode.GetPosition()) ? 1 : Mathf.Sqrt(2);
339+
var neighbourRealValue = distanceToNeighbour*neighbouringMapTileNode.Weight;
340+
341+
return parentMapTileNode.GetMapTileNodeData().RealValue + neighbourRealValue;
320342
}
321343
}

Assets/Project/Scripts/Static Methods/DistanceMethods.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,14 @@
22

33
public static class DistanceMethods
44
{
5+
public static bool OneDimensionalDistanceBetweenPositionsIsSingleAxis(float a, float b) => Mathf.Approximately(GetOneDimensionalDistance(a, b), 0f);
56
public static float GetOneDimensionalDistance(float a, float b) => Mathf.Abs(a - b);
7+
8+
public static bool DistanceBetweenPositionsIsSingleAxis(Vector2 positionA, Vector2 positionB)
9+
{
10+
var distanceInXIsSingleAxis = OneDimensionalDistanceBetweenPositionsIsSingleAxis(positionA.x, positionB.x);
11+
var distanceInYIsSingleAxis = OneDimensionalDistanceBetweenPositionsIsSingleAxis(positionA.y, positionB.y);
12+
13+
return distanceInXIsSingleAxis || distanceInYIsSingleAxis;
14+
}
615
}

0 commit comments

Comments
 (0)