Enable diagonal paths in A* implementation
The way this works is like so, where 'o' is the voxel we're trying to leave, '_' is a possible exit, 'x' is an obstacle, and * is the exit. __* _o_ ___ xx* _o_ ___ xxx _o* ___ xx_ _ox __* Basically, if both the north and east paths are available, AND the northeast path is available, we use the northeast path.
This commit is contained in:
parent
b56a53dc81
commit
2edd199fca
@ -15,6 +15,14 @@ namespace TrueCraft.Core.AI
|
|||||||
Coordinates3D.West
|
Coordinates3D.West
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private readonly Coordinates3D[][] DiagonalNeighbors = new Coordinates3D[][]
|
||||||
|
{
|
||||||
|
new[] { Coordinates3D.North, Coordinates3D.East },
|
||||||
|
new[] { Coordinates3D.North, Coordinates3D.West },
|
||||||
|
new[] { Coordinates3D.South, Coordinates3D.East },
|
||||||
|
new[] { Coordinates3D.South, Coordinates3D.West },
|
||||||
|
};
|
||||||
|
|
||||||
private PathResult TracePath(Coordinates3D start, Coordinates3D goal, Dictionary<Coordinates3D, Coordinates3D> parents)
|
private PathResult TracePath(Coordinates3D start, Coordinates3D goal, Dictionary<Coordinates3D, Coordinates3D> parents)
|
||||||
{
|
{
|
||||||
var list = new List<Coordinates3D>();
|
var list = new List<Coordinates3D>();
|
||||||
@ -28,6 +36,13 @@ namespace TrueCraft.Core.AI
|
|||||||
return new PathResult { Waypoints = list };
|
return new PathResult { Waypoints = list };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool CanOccupyVoxel(IWorld world, BoundingBox box, Coordinates3D voxel)
|
||||||
|
{
|
||||||
|
var id = world.GetBlockID(voxel);
|
||||||
|
// TODO: Make this more sophisticated
|
||||||
|
return id == 0;
|
||||||
|
}
|
||||||
|
|
||||||
public PathResult FindPath(IWorld world, BoundingBox subject, Coordinates3D start, Coordinates3D goal)
|
public PathResult FindPath(IWorld world, BoundingBox subject, Coordinates3D start, Coordinates3D goal)
|
||||||
{
|
{
|
||||||
// Thanks to www.redblobgames.com/pathfinding/a-star/implementation.html
|
// Thanks to www.redblobgames.com/pathfinding/a-star/implementation.html
|
||||||
@ -49,15 +64,40 @@ namespace TrueCraft.Core.AI
|
|||||||
|
|
||||||
closedset.Add(current);
|
closedset.Add(current);
|
||||||
|
|
||||||
|
// Test directly adjacent voxels
|
||||||
for (int i = 0; i < Neighbors.Length; i++)
|
for (int i = 0; i < Neighbors.Length; i++)
|
||||||
{
|
{
|
||||||
var next = Neighbors[i] + current;
|
var next = Neighbors[i] + current;
|
||||||
if (closedset.Contains(next))
|
if (closedset.Contains(next))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var id = world.GetBlockID(next);
|
if (!CanOccupyVoxel(world, subject, next))
|
||||||
if (id != 0)
|
continue;
|
||||||
continue; // TODO: Make this more sophisticated
|
|
||||||
|
var cost = (int)(costs[current] + current.DistanceTo(next));
|
||||||
|
if (!costs.ContainsKey(next) || cost < costs[next])
|
||||||
|
{
|
||||||
|
costs[next] = cost;
|
||||||
|
var priority = cost + next.DistanceTo(goal);
|
||||||
|
openset.Enqueue(next, priority);
|
||||||
|
parents[next] = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test diagonally
|
||||||
|
for (int i = 0; i < DiagonalNeighbors.Length; i++)
|
||||||
|
{
|
||||||
|
var pair = DiagonalNeighbors[i];
|
||||||
|
var next = pair[0] + pair[1] + current;
|
||||||
|
if (closedset.Contains(next))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!CanOccupyVoxel(world, subject, next))
|
||||||
|
continue;
|
||||||
|
if (!CanOccupyVoxel(world, subject, pair[0] + current))
|
||||||
|
continue;
|
||||||
|
if (!CanOccupyVoxel(world, subject, pair[1] + current))
|
||||||
|
continue;
|
||||||
|
|
||||||
var cost = (int)(costs[current] + current.DistanceTo(next));
|
var cost = (int)(costs[current] + current.DistanceTo(next));
|
||||||
if (!costs.ContainsKey(next) || cost < costs[next])
|
if (!costs.ContainsKey(next) || cost < costs[next])
|
||||||
|
Reference in New Issue
Block a user