Pathfinding can be a fundamental component of your game. Truly understanding how it works gives you fine-grained control of how units interact with the environment.
Learn how A* pathfinding truly works by diving deep into the mechanics. We'll go step by step through each process as well as cover the edge cases not often talked about.
Unity package/source code: https://bit.ly/3njRKwD
🔔 SUBSCRIBE: https://bit.ly/3eqG1Z6
🗨️ DISCORD: https://discord.gg/GqeHHnhHpz
✅ MORE TUTORIALS: https://www.youtube.com/tarodev
[Music] [Music] [Applause] [Music] pathfinding is the concept of finding the shortest route between two points the most popular pathfinding algorithm found in games today is the a-star pathfinding algorithm the idea of this video is to help you truly understand how the a-star pathfinding algorithm works by showing you a bare-bones implementation saying that i will give you a few tips to further optimize as well as point you to some pre-built solutions by the way all the code will be provided in the description alright let's get into it a-star utilizes three main numbers to calculate the best path the g cost signifies the travel distance from the node to the start node the h cost is the opposite in that it represents the estimated travel cost from the node to the target node the h cost is optimistic in nature so it will either be spot on or it will underestimate the cost it will never give a cheaper than possible value take this grid for example the h cost of this node is three because it is three nodes from the target but if we put an obstacle in the way making three moves to the target impossible the h cost remains the same as it was only an optimistic assignment so to iterate the actual steps required from any node will always be equal or more than the estimated h cost the f cost is equal to the g cost plus the h cost the lower the f cost the more attractive it is as a pathfinding option the goal is to simply choose the lowest f cost over and over until we reach the target node okay let's look at a few examples of a star in action all right so i'll begin by placing my target here and we'll begin path finding so as you can see all the nodes have a g cost of one as we are just one node away from our start but the h costs vary depending on how far away they are from the target so first we'll find our lowest f cost so this will be four and we'll choose this so we will now move to this node and we will check our surrounding targets again and we'll choose the lowest f cost again and as you can see our g cost is getting larger as we're moving away from our start position but our h cost is getting lower as we're getting closer to our target and our f cost will stay the same as we are just raising one number and lowering the other until we find our target okay so another example i'll put my target here so we choose our lowest f cost and now we have three nodes with an f cost of five so what we do is we then turn to our h cost and we find the lowest h cost so the closest uh estimation to our target wins so we'll choose this one and now we've got three nodes with five as the f cost so we'll keep choosing the lowest h cost and we'll get to our target the reason i'm using hex grids in my examples is because every direction from the node has a movement cost of one whereas in a square or isometric grid the horizontal and vertical cost is 1 while the diagonal cost is 1.4 we usually multiply these numbers by 10 giving us the integers 10 and 14. i actually use the exact same pathfinding code across all three grid types the only difference is the distance calculations from node to node i won't be covering how to calculate the distance for all three grid types in this video as that falls onto general grid logic but the code for all three will be provided in the link below okay let's dive into the code so here is roughly what the node class looks like i've redacted a lot of miscellaneous functionality to keep you focused on what's required but as you can see we have a g and h floats with corresponding functions which update them as well as an f getter which just adds j and h together we also have a connection variable but we'll get into that a bit later alright so we begin by taking in two arguments the start node and the target node we create a list of our nodes that we need to search and as we're starting obviously from the start node we will add it to the list and we'll also create a list for our nodes that we have already processed so that we don't double up by the way the search nodes are green on the map and the process nodes are blue on the map so we begin by looping over our search nodes and we will do that for as long as there are nodes to search or until we've found a path now that we're in the context of one of our search nodes what we're going to do is find the current best f cost node so first we'll just set our current to the first index in the search list then we'll loop over all of our other search nodes to see if this new search node has a better f score than our current one and if so we'll set it or if it has the same f cost as our current one we'll check to see if it's got a lower h cost uh and if so we will make it the current but by the end of this four inch loop we will have our best choice to set as our current node so now that we've got our node and we're about to process it let's add it to the process list and then we'll remove it out of the to search list so that we don't uh process it again and now it's where it actually gets interesting so now that we've got our best f cost uh node we will loop over all of that node's neighbors uh to perform some logic here so the neighbors that we care about are the ones that are walkable and also that we haven't actually processed them yet so uh if they're walkable and we haven't processed them let's uh iterate over them so first i just cashed this boolean here just whether or not it's uh already in the search list because we're going to use that a few times and here is arguably the most complex part of the algorithm to actually get your head around so if you think about it our current node here is what we have chosen as the best node of the bunch right which means any neighboring node that we find here should technically come through our current node right because because as far as we know our current node is the best node so far so the cost to this new neighbor will be at least what it has cost to get to this tile plus whatever it takes to get to the next node which in uh hex grid is one so now that we've got this g cost we need to determine if we want to actually do anything with it if it's worthwhile to actually update uh the values in this neighbor so we do two checks here we say is it already in the search list and if it's not then yes we will be updating these because we haven't done it yet or if this new cost is actually more favorable than the one that the node already has set okay so i'm just going to explain to you how a node can get a new g cost so i'll set my target here and we'll begin pathfinding and we'll come up here now take note of this node here with a g cost of four now it has a g cluster four because it took one two three four trips to get here so now we need to look for the next node to process and it looks like this one will be it so just keep track of this node here so as you can see the g cost is now three and that is because we have uh found a better route to that tile which is one two three so that's how a j-class can change just when the tile gets re-evaluated for a better route so now we can head up and finish our path and now we have our route all right back to the code okay so now hopefully you know why we do this check and how this can occur just from the beginning we make this g cost we determine this new neighbor's g cost and then we say if it's not already in the search list or if this g cost is better than the current one that it's got let's action it and set its values so we'll set the g cost so basically in this function it's just saying neighbor dot equals this new cost we'll connect this neighbor to the current node this is what allows us to retrace our path once we're done it's all well in good processing until we get to our target node but if we don't know how to recharge our path we've really done nothing at all think of this like drawing a line from the current node to the new neighbor this connection may change in the future but for now it's accurate okay so just to show you how the connection hierarchy works i'm going to put my target there and we'll begin building our path and you can see one solid line there and then we thought that was a better path here so we have broken it and now our best path is here and straight down so there will always only ever be one solid path back to the start node okay so i hope that made sense so we set our connection and then we check to see if this block is in the search list so in this conditional obviously we checked to see if it wasn't in the search list but it may have actually already been in the search list and got through on this condition so we'll check if it's in the search list if it's not we'll set its h cost now i set the h cost in here a lot of the times i see this actually set here but the h cost is just heuristic and it never changes so uh i'll just set it the one time and then we'll add this neighbor into the search list because if you remember up here at the start of this while loop here we determine which node in our search list is the best node so who knows this neighbor may actually be the best node now there's actually one last thing we need to do and that is to check to see if our current node is actually our target node because if that's the case then we have reached our our goal and we can return the path so we can just slot this part in here so after we select our best node which if if the target node is available it will definitely be the best node so if the current node is indeed the target node we will set our current path tile to the target node create a new list to return we will start our while loop while this current node does not equal the start node and we will add the node into a list and then we will set the current path tile to the connection if you remember we were setting the connections throughout it so there will be a connection from all the way from the target node to the start node once we get back to the start node we will just return the path [Music] so there you have it that is the entire a-star algorithm so as i mentioned earlier this code was written for readability to ease the explanation and there's a few things you can do to optimize the algorithm so this part here is the slowest part of the algorithm finding the best fcos node and obviously the more nodes you have the longer it takes to iterate through them all so this could be replaced by a simple binary tree or otherwise known as a heap and that way you won't have to process every single node you'll just have to process a handful at a time alternatively instead of directly using the class here we could extract the pathfinding data out to a struct and then we could off load that to the job system codemonkey has a video detailing a very efficient a-star pathfinding algorithm using the burst compiler so check that out alternatively the a-star pathfinding project by aaron grauberg on the asset store is a fantastic paid solution with many different grid types and customization or if you'd just like to study the code that i have in this project i've included the link down below it has some regeneration and distance logic for all the three different grid types that i've shown in this video so that might be handy for you so if you enjoyed this video on pathfinding subscribe to the channel and i'll see you in the next one bye