If you want to see some example code, I have a simple pathfinder in my grid-based game that takes two points on a grid, and returns the nearest empty space next to one point, which seems to be what you’re looking for:
/* FindPath Uses Dijkstra's Algorithm to find the shortest path through the map from an origin point to a goal point.
* It expands a frontier from the goal point until it finds the origin, making note of the point along the frontier
* that "found" the origin and then returns that as the first step along the path from the origin to the goal.
* The parameter nextStepMustBeEmpty can ignore 'first steps' that are occupied; otherwise, it will return the next step
* along the shortest path whether or not it is occupied. */
public static Node FindPath(Node origin, Node goal, bool nextStepMustBeEmpty)
{
if (origin == goal)
{
Debug.Log("Tried to find a path to and from the same point.");
return null;
}
List<Node> frontier = new List<Node>(); // the frontier (nodes that are expanding)
bool[,] searched = new bool[Dungeon.xSize, Dungeon.ySize]; // whether or not a map node has been searched
Node nextStep = null; // the direction to the next node in the path (from startP), this is what is returned.
bool found = false;
searched[goal.x, goal.y] = true;
frontier.Add(goal);
//Expand the frontier until startP is found or there are no more possible nodes
while (frontier.Count > 0 && !found)
{
Node f = frontier[0]; // the space we're currently checking from
frontier.RemoveAt(0); // pop!
for (int i = 0; i <= 8 && !found; i++) //check all 8 squares around it...
{
Node next = DungeonControl.DetermineNextStep(f, 45 * i, false); // find the next node in this direction
if (next == null || searched[next.x, next.y]) // If we've already searched here or it's outside of the borders...
{
continue; // do nothing and continue.
}
else if (next.x == origin.x && next.y == origin.y) // If this is the goal (origin) and we still haven't found it...
{
if(!nextStepMustBeEmpty || !Dungeon.map[f.x, f.y].occupied) // only use this if the current space is unoc, since we have to walk to it.
{
found = true;
nextStep = f; // set the next step to the space we're checking FROM.
frontier.Clear();
continue;
}
continue; // otherwise, keep searching, ignoring this finding of the goal/origin.
}
else // We haven't searched this spot, it's legit, and it's not the goal
{
searched[next.x, next.y] = true; // We don't need to search this again.
if (Dungeon.map[next.x, next.y].walkable) // only if this space is able to be walked on (not a wall).
{
frontier.Add(next); // add it to the frontier! hooray!
}
continue;
}
}
}
searched = null;
frontier = null;
return nextStep;
}
Hopefully the struct Node is self-explanatory. Dungeon.map[,] is an array of Nodes.
The way this works is that the character seeking a path will use this to find the next step they take – it’s a turn-based game, so for example if the enemy needs to seek the player, FindPath is called with the enemy’s location as the ‘origin’ paramtere, and the player as the ‘goal’ parameter. Then the algorithm finds the shortest path starting from the goal (player) to the enemy (origin), and returns the empty node closest to the enemy (origin) along that path, so the enemy knows that’s the next step to take.
Though it sounds like the doors and items and stuff in your game are not on the grid at all…? If they are on the grid, just make sure the objects know what node they’re on, instead of trying to “find” the node when they’re clicked on. So if your door knows which node its on, when you click on it, you can just use that data to give the player a point to seek. If they’re not on the grid, you’ll have to determine what spaces you considered ‘occupied by’ or ‘surrounding’ those things, which will depend on the design of your game/grid.