This week I will talk a bit about our pathfinding. (Warning: Confusing)
There are a couple of different pathfinding algorithms out there, on the internet. There are Breath-first, Best-first, Dijkstra, A*(A-star), etc. Almost everyone, on different forums, suggest A* as pathfinding algorithm for most games. It is reasonable fast in most instances, even though some of the others were quicker in some scenarios.
A*, like most other algorithms, needs a tile based system to search through.
Each Tile, or Cell, is given three values: F, G and H.
- G is the cost to move from the starting Cell to this cell.
- H is the guessed cost to move from this Cell to the goal, as if there was no collision in between.
- F is the sum of G and H. (G + H), the approximated cost to move from start to finish through that cell.
Each cell also holds a pointer that points to its “parent”, which is the cell that put the active cell on the open list.
It uses three lists to store cells in: Open, Closed and Final.
- In Closed all the checked cells are stored, so we don’t check the same cell more than once.
- In Open all the cells still to check are stored.
- In Final we store the final path, when we have found our goal. We get the path by backtracking from the goal and go through all the “parent” cells until we are at the first cell.
Each iteration of the algorithm takes the cell with the lowest F-value in the Open list, and puts it on the Closed list. Then it checks all the surrounding cells that is not already on the Closed list and gives them values. It one of the cells is already on the Open list, it checks if the new F-value is smaller than the last. If it is, it changes the parent of that cell so it points to the new, cheaper, parent.
When the goal cell is finally found in the Open list, we backtrack from there. Going from parent to parent, storing each cell and when we are back at the start cell we have the shortest path.
The picture shows an example of A*. The Green tile is Start, Red is Goal, Gray are walls, Blue is on Closed list, Green on Open list and the yellow line shows the path we got at the end.
Unlike the other Escape-concept groups, we chose not to have tile based. The reason for this is that we felt that tiles are too limiting when it comes to placement of walls and furniture’s. We wished to have more freedom, to rotate and place assets “however” we wanted, to give each room a unique feel.
Because of this I had to simulate a grid to use A*, otherwise, each pixel had to represent the tiles, and that would be too many squares to search through. The grid is stored in:
- std::vector<std::vector<bool>>
Which is vectors in vector. The outer vector is the tiles Y-position and the inner its X-position.
Instead I divided the map into equal sized squares and checked each square for collision. If collision was detected I put its bool-value to false, otherwise true.
Then, to see if the grid worked I drew the grid on top of the level ingame, and each walkable tile was colored red and the unwalkable teal.
As the picture shows, it looks like it is working.
I hope I made myself clear, but I’m afraid that would be really wishful thinking…