@@louissherwood5221 He has a far posher voice than Hugh Grant, though: he pronounces "off" as "orf" and "gone" as "gorne", for instance, and I suspect he would pronounce "hour" as "ahr" and "flower power" as "flahr pahr" (so-called triphthong smoothing). A very pleasant voice speaking Conservative RP. Not that usual nowadays.
I'd like to add one more thing about this for anyone else who scours the comments for tweaks - three years late, i know, but these tutorials are phenomenal and i've been going through them. I've learned more about A* than I ever thought possible. Mathf.RoundToInt((gridSizeX-1) * percentX) is almost right, but not quite. By subtracting 1 before multiplying by the percent, you won't go over the number of squares that exist, but you'll be getting a percent of an incorrect number. If you have a grid with 100 or more squares, you may eventually encounter situations where you are off by a square. Also, you need to you FloorToInt, because assuming 0 is the left-edge of the grid, it's also the left edge of the first square. 0.5, then, would be the middle of the first square, and so would 0.9, 0.99, and so on. If you ever round up, you can be inaccurate by as much as half a square. So instead what i've done is Mathf.FloorToInt(Mathf.Min(gridSizeX * percentX), gridSizeX - 1)
19:30 if you round down a percentage multiplied by a grid-1 you can end with a target one node away from your actual current node. Take x = 14.4 for example: (14.4 + 30 / 2) / 30 = 0.98 x = round(29 * 0.98) = round(28.42) = 28, so you end up at node 28. But if your x = 14.4 you are between x=14 and x=15, so you actually are at the far right node (29) You should not round and subtract one, you should floor without subtracting: x = floor(30*0.98) = floor(29.4) = 29 edit: you also need to clamp before floor: int x = Mathf.FloorToInt(Mathf.Clamp((gridSizeX) * percentX, 0, gridSizeX - 1)); o/
You should also remove these lines> percentX = Mathf.Clamp01(percentX); percentY = Mathf.Clamp01(percentY); Becouse otherwise the bottom Y node is always one above from the current node. This is my whole function: public Node NodeFromWorldPoint(Vector3 worldPosition) { float percentX = (worldPosition.x + gridWorldSize.x / 2) / gridWorldSize.x; float percentY = (worldPosition.y + gridWorldSize.y / 2) / gridWorldSize.y; int x = Mathf.FloorToInt(Mathf.Clamp((gridSizeX) * percentX, 0, gridSizeX - 1)); int y = Mathf.RoundToInt((gridSizeY) * percentY) +1; return grid[x, y]; }
Omg I know I'm a bit late so you may well not see this comment but this tutorial dude wow. I'm trying to implement A* into an Xcom style strategy game and after hours of trying to follow another UA-camr (I won't name names but god it was infuriating), this tutorial is just what I needed :) I've followed this all the way through and feel so much better about A* now, you're a great programmer mate thanks so much.
I have watched this and Part 1 and am super excited to try this stuff out. I'll be able to quickly create some fun games for my kids with this AI. Keep up the good work friend.
Thanks a lot. You are the best 😊 teacher. Explained everything in details and your voice have magic, can hear all the day without feel bored. thanks a lot again. 😇😊
I'm trying to implement this in Java and it works fine. I only had problem with percentX and percentY, wich were returning 5X bigger value than they should, but I fixed it. Thanks for great tutorial!
I came here from this guy named Daniel... he kind of just reuploaded your tutorial with his following your tutorial... he did NOT fix the "that's y it's meant to be z" for the percent value. I've been stuck for a week. Lol.
Thanks for making this tutorial and for also adding the source files for the 2D project somewhere in the comments (as the video is for 3D). I am still learning c# and unity and now trying to learn A* pathfinding. I am finding this really useful and educational.
Amazing tutorial, I'm using Aron Granberg's pathfinding since I couldn't implement it myself. Your explainations are extremely easy to understand. Great work!
Thanks!!!!!!! Incredible explanation! I was struggling setting the grid for my project, but I followed along and it turned out really simple and easy. now to part 3...
Awesome video, one problem that I encountered while testing this code is that when you pass the player position parameter to NodeFromWorldPoint you have to convert coordinates to local relative to grid object with Transform.InverseTransformPoint otherwise if your grid is not centered on 0,0,0 then it will not work :)
To anyone ready to spend an hour or so looking through the comments for the solution. Try this method from @itsybitsypixel. His comment is buried, so hopefully this finds and helps you before you start digging: ANYONE WHO IS HAVING INACCURATE POSITIONS FROM THE NodeFromWorldPoint READ THIS I found that the "NodeFromWorldPoint" method returned an inaccurate position while on the sides of the grid, so I tried remaking it too show a more accurate position. It's basically the same but it skips the percent and uses the nodeRadius and nodeDiameter variables and that somehow works. int x = Mathf.RoundToInt((worldPosition.x + gridWorldSize.x / 2 - nodeRadius)/nodeDiameter); int y = Mathf.RoundToInt((worldPosition.y + gridWorldSize.y / 2 - nodeRadius)/nodeDiameter); x = Mathf.Clamp(x, 0, gridSizeX - 1); y = Mathf.Clamp(y, 0, gridSizeY - 1); return grid[x, y]; ^This code is inside the method^ I tested this and it worked and gave me a more accurate position, but I have not tested this with the rest of the tutorial so be warned. Also I am using this for a 2D game so I used the Y position instead of the Z position in "worldPosition". If you are making a 3D game use Z instead.
I was JUST wondering how I was going to do the AI for the top down shooter. I've had some exposure to A* before but never in the context of actually doing it. Sebastian: I love you.
There's another way to do 17:17 on the NodeFromWorldPoint function. Which is to just Vector3.InverseLerp(-gridPosition*.5,gridPosition*.5,worldPosition.x) It's automatically clamped to 0 and 1 so no need to do Mathf.Clamp or whatever: Mathf.InverseLerp(-gridWorldSize.x*.5f,gridWorldSize.x*.5f, worldPosition.x); Mathf.InverseLerp(-gridWorldSize.z*.5f,gridWorldSize.y*.5f, worldPosition.z); Remember, gridWorldSize and worldPosition are 1:1 proportion. Little definition of Inverse Lerp: InverseLerp(min,max,t) What InverseLerp does is that it returns a float value that converts value t into a value between 0,1. Kinda like Lerp except t is a value you pass in that is between 0 and 1 and returns a float value that is between min and max.
Another great tutorial Sebastian! Procedural generation sounds like a great idea! I would also like to suggest procedural voxel terrain in Unity, maybe block type worlds like Minecraft or smooth voxel terrains by using something like marching cubes or even better Dual Contouring, which allows you to have sharp features for buiulding but the smoothness that you want for the ground.
A little late and don't know if this has been posted already or not, but currently you don't use the unwalkableMask. If you have for example other gameobjects with a collider, they will also be added to the non-walkable grid. To fix this you have to add the layer mask to line 28: bool walkable = !(Physics.CheckSphere(worldPoint, nodeRadius, unwalkableMask)); Also to update the grid just run the CreatGrid(), for example by pressing the N button: if (Input.GetKeyDown(KeyCode.N)) { CreateGrid(); } or from a different script (don't forget to make CreateGrid() public: if (Input.GetKeyDown(KeyCode.N)) { GameObject.Find("A*").GetComponent().CreateGrid(); }
I would like to see how you would go about having an Enemy AI that jumps up and down platform to chase the player , in a 2D SideScroller platformer, Which route would you pick ? A* pathfinder , Raycast , Grid base ,MeshBase. Possibly also giving your opinion on difference between them with Pros and Cons.
Be aware if you are following this tutorial there is a pitfall, the map is suppose to be at 0,0,0 it cant move if you do the path to the character is off. To fix this do this instead of what was provided. private Node GetNodeFromWorldPoint(Vector3 worldPosition) { var percentX = (worldPosition.x - transform.position.x + GridSize.x / 2) / GridSize.x; var percentY = (worldPosition.y - transform.position.y + GridSize.y / 2) / GridSize.y; Thank me later but this portion really threw me off and solved it in about 5 minutes.
It is like this actually: float percentX = (worldPosition.x - transform.position.x + gridWorldSize.x/2) / gridWorldSize.x; float percentY = (worldPosition.z - transform.position.z + gridWorldSize.y/2) / gridWorldSize.y; But, thank you for saving my day!
I love these videos, they are great! Just one small thing that's bugging me slightly, at 16:39 and in earlier videos, you're calling these things percents but that would be something between 0 and 100 rather than between 0 and 1, right? Would be better (in terms of intuitive variable names etc.) to call them fractions, as that is what they are.
Saying "42" versus "42%" would be quite different in meaning. Mathematically rather than colloquially, a percent is a number between 0 and 1, as Sebastian has presented here. The reason for this is that "percent" means literally "divided by 100." So percents are indeed fractions: they are always fractions out of 100 🙂
@@marcindathefierce Exactly, I know that. But he said "a percentage of point five" (for the middle of the screen), when it would be either a fraction of point five, or a percentage of 50, right? That's what I meant.
We should also take node radius and our A* object position into account when getting node from world point or the results will be pretty inaccurate. Here's what I ended up with: float percentX = (worldPosition.x - transform.position.x) / gridWorldSize.x + 0.5f - (nodeRadius / gridWorldSize.x); float percentY = (worldPosition.z - transform.position.z) / gridWorldSize.y + 0.5f - (nodeRadius / gridWorldSize.y);
+Alexander Sorokin I think I'm having this problem. When I was following along and testing and put it at 0,0,0 it was all fine. Now that I actually want to implement it in my game as soon as it pathfinds it's trying to go somewhere weird. I think its the NodeFromWorldPoint method that's doing it but can't figure out how to fix it. Your reply seems to suggest there should be some code. Mind posting it again as I can't see anything and I'm hoping you have the answer! Thanks :)
this is the most important comment on youtube I've ever read! UP YOU GO, SIR! WITHOUT THIS, YOU CAN'T USE IT IN YOUR GAME, meaning: you can't move the grid.
OverflowException: Number overflow. Grid.CreateGrid () (at Assets/Pathfinding/Pathfinding_test/Grid.cs:22) Grid.Start () (at Assets/Pathfinding/Pathfinding_test/Grid.cs:18) I use Unity 5
What does following line means at 9:42 : Vector3 worldPoint = worldBottomLeft + Vector3.right * (x * nodeDiameter + nodeRadius) + Vector3.forward * (y * nodeDiameter + nodeRadius);
You're finding the middle point of the node the loop is currently looking at. If you start at worldBottomLeft, which is the bottom left point of the bottom left node, but you're now looking at node (x,y), you would need to move x times the diameter of a node to the right to end at the bottom left of the x'th node, but you want the middle point, so you add the nodeRadius one more time. Therefore you add x * nodeDiameter to move to that node, and then nodeRadius again to get to the middle. You multiply all that with the unit vector to the right to make sure you're going in the right direction and using the right units. The other part is just the same, but for the y coordinate. It uses forward rather than up to make sure you don't go up (off of the ground) in the three-dimensional space.
Wow, nice tutorial as always! One question though. What would the math look like inside the NodeFromWorldPoint function if the grid origin was in the corner at 0, 0 and not at the center? These are the variables I use: public int gridRows = 5; public int gridColumns = 5; public float nodeScale = 1; In CreateGrid() this is what I do: Vector3 nodePos = transform.position + new Vector3(r, 0, c) * nodeScale; bool walkable = Physics.CheckBox(nodePos, Vector3.one * nodeScale, Quaternion.identity, obstacleLayerMask) == false; grid[r, c] = new Node(nodePos, walkable); As you see, I left out the extra math and simply build the grid from "transform.position". The problem is, I can't figure out how I get a node from a world position. This is the closest "formula" I could figure out thanks to the people in the comments. int x = Mathf.FloorToInt((worldPosition.x - transform.position.x) + (gridRows * 0.5f) / nodeScale); x = Mathf.Clamp(x, 0, (gridRows - 1)); int z = Mathf.FloorToInt((worldPosition.z - transform.position.z) + (gridColumns * 0.5f) / nodeScale); z = Mathf.Clamp(z, 0, (gridColumns - 1)); return grid[x, z]; But the bigger the offset from World 0,0,0 the bigger the offset between worldPosition and nodePosition in the grid. Any help?
I usually use this for "index from positions": int x = (int)((worldPosition.x - worldBottomLeft.x) / (nodeRadius * 2)); int y = (int)((worldPosition.z - worldBottomLeft.z) / (nodeRadius * 2)); x = Mathf.Clamp(x, 0, gridSizeX - 1); y = Mathf.Clamp(y, 0, gridSizeY - 1); return grid[x, y]; ps: worldBottomLeft must be global and calculate at Start()
fantastic tutorial Sebastian!! I have one issue. The playerNode will not update or show as a different color. I even continued on I even continued on to the next tutorial for pathfinding to see if the old code would correct itself and it did not. I changed the zed and y coordinates and everything but it would work on either the x or y plane. So that means no path finding. It does work for the layer mask but none of the update type of functionality. Just the stuff that's on the startup section what do you suggest
I know it's been years since this video came out but can we generate nodes onto something more abstract than a plane? Say something like a sphere or something with hills. This is a good starting point for me in learning more about A* Pathfinding.
If you're deaf, I recommend not relying on specific platforms to supply Accessibility features for this exact reason. Most OSs both on phone and Computers have features for generating captions. They aren't always right, but they all get pretty close.
add if (grid != null) if you are tired of the constant errormessages it just checks if it has a grid before trying to calculate { Node playernode = nodefromworldpoint(player.position); }
Hey Sebastian, I was wondering what the equivalent of creating a plane and, using gizmos to visually display the walkable and unwalkable regions of the world would be for a 2d project? Furthermore, What is the equivalent of the Physics.CheckSphere method in a 2d environment? At the moment I am currently using colliders, and I was hoping that there is a better solution in existence. Thanks!
is there any way in which we could avoid the diagonal grid tiles and figure out the path to the target only by moving horizontal or vertical directions if you have any suggestion please let me know
There is something I would like to see, the nodes being generated on 3D coords and not only on 2D, I have an Idea and will try to use ur way but the implementation on 3D aspect needs a bit more thinking before just dropping the nods around the world for example if we are going to put them on the world terrain, how should we handle the slope that is possible for navigation? etc. etc. so can you add another video about node generation for 3D space. Thanks
80 Proof Gameplay yah i got some sort of working solution for 3d system but the lookup table would be too big for each scene or at least i think i was doing hasty job in R&D but if you join 3Dbuzz.com, i will soon publish some videos there about my systemm subscription is free, so why not?
GetNodeFromWorldPos has a problem. When the world pos is near edges it gets inaccurate. For example when it's at the most edge the position percentage is below zero. When you round that value to nearest Integer if that below zero value is less than 0.5f it will round to 0 and you get the most edge node yes But if it's more than 0.5 it will round to 1 and you will get next the Node. You should floor it without subtracting one than clamp to max index so it will not get out of index.
very wonderfull tutorials man, im enjoying so much your tutorials. And i want to add something very little, i dont like that NodeFromWorldPoint get the node to the right or bottom of the capsule so i modified the percent so they are calculated from the center of the capsule, but i dont know if the modification i did its really working on any case, here is my modification: percentX = (worldPosition.x + gridWorldSize.x/2 + nodeRadius) / gridWorldSize.x; percentY = (worldPosition.z + gridWorldSize.x/2 + nodeRadius)/ gridWorldSize.y; pd: forget it, it doesnt work, i was testing it just for the top right, the other sides doesnt work. pd2: well i think now works, just to make more precise the transition between nodes: public Node NodeFromWorldPoint(Vector3 worldPosition) { float percentX = (worldPosition.x + gridWorldSize.x/2) / gridWorldSize.x; float percentY = (worldPosition.z + gridWorldSize.y/2) / gridWorldSize.y; percentX = Mathf.Clamp01(percentX); percentY = Mathf.Clamp01(percentY); int x = Mathf.RoundToInt((gridSizeX-1) * percentX); int y = Mathf.RoundToInt((gridSizeY-1) * percentY); //here start my added modification if (grid [x, y].worldPosition.x + nodeRadius < worldPosition.x && x < gridSizeX - 1 && x > 0) x++; else if (grid [x, y].worldPosition.x - nodeRadius > worldPosition.x && x < gridSizeX - 1 && x > 0) x--; if (grid [x, y].worldPosition.z + nodeRadius < worldPosition.z && y < gridSizeY - 1 && y > 0) y++; else if(grid [x, y].worldPosition.z - nodeRadius > worldPosition.z && y < gridSizeY - 1 && y > 0) y--; return grid[x,y]; } this should be easy for you but since i'm new with unity i wanted to see if im doing it right.
Hey, great video! Quick question, if I want a grid node for a 3d terrain, should I just raycast down and create each node at the hit point, is it that simple?
You need to explain more in detail what exactly the variables do. I feel like im just copying, without learning anything,. Thanks for the videos though!
This tutorial is beautifully done, the pace might be high for starters but as an experienced programmer i really appreciate the speed. Also, programming wise there is nothing special or difficult in the used variables/functions.
I changed the code a bit to account for a fact that a large object (e.g. player ship) can occupy several nodes. To create gizmos with the same color for all such nodes, I added a boolean to Node object (playerhere) and a condition in the CreateGrid() method ("player_shield_weak" is simply a collider object of the player ship): if (walkable == false) { Collider[] col = Physics.OverlapSphere (worldPoint, nodeRadius); if (col [0].gameObject.tag == "player_shield_weak") { grid [x, y] = new Node (walkable, worldPoint, true); } else { grid [x, y] = new Node (walkable, worldPoint, false); } } else { grid [x, y] = new Node(walkable, worldPoint, false); } This creates a Node object with playerhere =true, and then, in DrawGizmos() method I just changed the condition to check this boolean: if (node.playerhere == true) { Gizmos.color = Color.cyan; } and it worked!
Hi Sebastian, nice tut! The 'NodeFromWorldPoint' function works fine for me when the player is near the (0, 0) point (the center of the map, we can say). But it gives me unaccurate values if I put the player far from that point. Any ideas about what's happening? Thank you!
Is it weird that I reply to a 3-year-old comment? Were you able to solve this? I kinda know where the problem is; if you're in a position that is larger than the grid world size (say your world size is set to 20 and you're at position 70), you're technically out of bounds, even though you're inside the grid, and that's because the division result will be larger than 1 which would then be clamped to 1 which is at the border of the grid. So we need some kinda offset from the origin, but so far all my attempts have failed :(
I've actually just solved the problem. As I mentioned above, the problem was with the offset. I was trying to offset everything from the origin, but the solution was to actually pretend we've never left the origin. To do that, I subtracted the player's position with the object's position (so if the player is at 75,0 and the enemy is at 70,0 --> We can treat it as if the enemy is at the origin and the player is at 5,0), this way the function makes sense and resulting value would always be
I know this might be a little bit off topic, but have you considered doing a GOAP AI tutorial? Since this sort of pathfinding is popularly implemented with GOAPs, i figured it could be an interesting follow up. Also, keep up the good work :)
I've been using "Sublime Text 2" in Unity for a little while now, mostly because I love its Ctrl+D function. When you mentioned the replace x with y using Cmd+R at 8:32, is that a plugin? I do notice you are using iOS, while I am on Windows, but I tried using Ctrl, the Windows button, Alt, Shift, and then went on Google to try and look it up. I can't find anything on it. This might be a stupid question with an obvious answer, but I'm just very confused right now and would love to know how you did that. :P
Hello. Since I realize that he is pretty bad at explaining. I will explain it to you. The point of WorldPoint is simple. It changes the point for every new cube(node in this example) by calculating the diameter and moving the new position correspondingly left and up to the diameter, so the cubes calculate the spacing between them and don't spawn in the same place... That's as simple as I can to explain it. First he creates a massive of object from the class Node//Node[,] grid\\ which contains (walkable and worldPosition) from the class //public Node(walkable, worldPosition);\\ Then he calculates the sizeX and sizeY by determing the diameter of every cube so he can get clear picture of how many cubes are to take the grid and then he creates a for loop to go through every cube on the grid and change the position of every new one by using a virtual function of Node //grid=new Node[gridSizeX, gridSizeY]\\ and the worldpoint(which I already tried to explain). Hope I helped. It can be done easier by the way but he "overcomplicates" the code.
What he does is basically make a massive and save every cube's position by making it a virtual function so for exmaple grid[0,1] will have a worldPosition equal to worldPoint as seen in the code where he changes the assigns the parameter worldPoint to worldPosition.
*ANYONE WHO IS HAVING INACCURATE POSITIONS FROM THE NodeFromWorldPoint READ THIS* I found that the "NodeFromWorldPoint" method returned an inaccurate position while on the sides of the grid, so I tried remaking it too show a more accurate position. It's basically the same but it skips the percent and uses the nodeRadius and nodeDiameter variables and that somehow works. int x = Mathf.RoundToInt((worldPosition.x + gridWorldSize.x / 2 - nodeRadius)/nodeDiameter); int y = Mathf.RoundToInt((worldPosition.y + gridWorldSize.y / 2 - nodeRadius)/nodeDiameter); x = Mathf.Clamp(x, 0, gridSizeX - 1); y = Mathf.Clamp(y, 0, gridSizeY - 1); return grid[x, y]; ^This code is inside the method^ I tested this and it worked and gave me a more accurate position, but I have not tested this with the rest of the tutorial so be warned. Also I am using this for a 2D game so I used the Y position instead of the Z position in "worldPosition". If you are making a 3D game use Z instead.
I know this is old, but this tutorial is probably the best for pathfinding, and sorry for asking a question 2 years later, but I am also doing a 2D game, and for me when I first test to see the red and white squares, they are all white for me. None of them turn red. I changed the code so it showed in an XY way and removed the Z, but it doesn't work. I think it has something to do with bool walkable = !(Physics.CheckSphere(worldPoint, nodeRadius, unwalkableMask)); The 3D physics I think is the problem, but not sure how to fix it. Ideas?
@@Seanld98 Have you created a layer mask for unwalkable objects on your scene? If you have check if you have added the layer mask to your unwalkable game objects. Also if that is not the case check if you maybe forgot to change the "Unwalkable Mask" parameter on your "Grid" script from "Default" to "Unwalkable". If this is all correct for you maybe you miss-spelled something while writing the gizmos? This "bool walkable = !(Physics.CheckSphere(worldPoint, nodeRadius, unwalkableMask)); " seams fine to me :P. Hope this helps.
@@smilos99 I have double checked all that, but what I found changed it was adding the normal Box Colliders (non 2D) to the 2D boxes and that seemed to work so I'm not sure why it wouldn't work in the 2D space, thanks though :)
@@Seanld98 I'm currently going through this tutorial. This worked for me: bool walkable = !(Physics2D.CircleCast(worldPoint, nodeRadius, Vector3.forward, nodeRadius, unwalkableMask)); 2D and 3D colliders don't collide, so you gotta go 2D!
How would you change this to make it work with 2d sprites instead of cubes? So far my best idea is to hide cubes behind the sprites which has worked but seems like it might cause lag with lots of obstacles. Edit: Looking over it it seems that it is the boxes collision that causes the detection so I just need some way to add collision to sprites.
just change vector.forward to vector.up and instead of spherecast use bool walkable = !(Physics2D.OverlapBox(worldPoint, new Vector2(nodeDiameter, nodeDiameter), unwalkableMask)); or at least it seems to work for me at this lesson's stage of implementing and Gizmos.DrawWireCube(transform.position, new Vector3(gridWorldSize.x, gridWorldSize.y)); for grid
I don't know if it is because of a recent update but the methode OnDrawGizmos() is being callsed before the start function, which means that the grid variable stays null and the grid is never drawn even if the CreateGrid() function works correctly, i will probably try to save the grid in an external file and import it in the Asset folder
Hey - you are amazing! I love your teaching style! Thank you for these videos. I just wanted to ask - does the grid know how to detect sprites? I have no trouble getting the grid set up the way you have it, and it works fine with cubes as long as they're under the layer "unwalkable", or with newly imported quads etc. But not sprites, it seems. Do you have any advice? Is there something about the sprite renderer that acts differently than a mesh renderer? Thanks again!
Perhaps it's something to do with the "bool walkable = !(Physics.CheckSphere (worldPoint,nodeRadius,unwalkablemask)); ? Because sprites are 2d, does it have to be a different physics check? that's my guess anyway.
+Anna Leonid Yup yup. For 2D, Change, bool walkable = !(Physics.CheckSphere (worldPoint,nodeRadius,unwalkablemask)); to bool walkable = !(Physics2D.OverlapCircle(worldPoint, nodeRadius, unwalkableMask)); After this, it will still not work because, the sprite have no collider to detect collision (Physics2D.OverlapCircle) Therefore, add a 2D collider to the sprite. Worked on mine.
+Muhd Amirul Thanks!! That totally works!! One more question. How would I set walkable so that it can detect both sprites and 3d objects? bool walkable = !(Physics2D.OverlapCircle(worldPoint, nodeRadius, unwalkableMask)) || !(Physics.CheckSphere (worldPoint, nodeRadius, unwalkableMask)); Am I missing some parentheses? I'm unable to get the grid to detect both.
+Anna Leonid Yo yo, Sorry for late reply. I was addicted to a specific game and yeah... I apologize, as this time, I am unable to explain why the following code work. Change, bool walkable = !(Physics2D.OverlapCircle(worldPoint, nodeRadius, unwalkableMask)) || !(Physics.CheckSphere (worldPoint, nodeRadius, unwalkableMask)); to bool walkable = !( (Physics2D.OverlapCircle(worldPoint, nodeRadius, unwalkableMask)) || (Physics.CheckSphere(worldPoint, nodeRadius, unwalkableMask)) ); It would seems that it has something to do with the ''!''. If it still doesnt detect the 3D object, make sure that the 3D object is touching the Grid. If it still doesnt work, then all the best. Im not sure if the new code would affect the pathfinding, because I already ditch my plan of using this tutorial because it doesnt provide me with smooth pathfinding, and dynamic pathfinding.
Hello there! I know this video is quite old, but I'd like to ask something... for some unknown reason, the nodes that are at the corners of my objects don't turn red, unless I change the value of the node size... it's weird because I can clearly see the object tresspassing the node's limits... well, thanks in advance, and keep up with the great work!
is it possible to use this in a game in unity where your scene is so smalll that your node points to world points need to get small floats/doubles? I'm trying to use this in a game but sometimes my enemies go to spots they shouldn't be able to and get stuck, i think its something with the conversion but not sure.
This is an excellent presentation. But... around 18:45 the clamping protection is weak. I.e. a 10 element array indexed with 1.0 will attempt to access element 10 - but only 0 though 9 are valid. Of course if I watch the rest of this excellent video and this problem is addressed I will be embarrassed.
I'm encountering a problem with the code. I have written everything down like it was done in the video, but when i run the program in Unity, no grid is drawn at all. Console doesn't return any errors either.
Sebastian Lague If I wanted to make the cyan colored detection cube for the player to work properly, does the plane have to be centered at 0,0,0? I've tested this out and that seems to be the case. What's a good solution to have the player detection working properly for planes positioned at any world position? Thanks in advance.
Im am trying to do this in UE4 and C++ i really wonder where you guys learn this stuff because i wantto learn it and atm i have no idea what i have to change in my code so this works. I also have no idea what all the position calculations do . so if anyone has some websites where i can learn this stuff pls let me know.
17:29 float percentX = (worldPosition.x + gridWorldSize.x / 2) / gridWorldSize.x; is actually: float percentX = (worldPosition.x / gridWorldSize.x) + .5f; means that you are taking the world position, dividing it with entire grid and adding a half.
Hey Sebastian, great Video !!! But I have a question about the Node-Constructor in the Node class. I am a starter-programmer so forgive me any stupidity. Here is my Question : Why didn't you create the Node-Constructor in the grid-script and would this be possible too ? BR, Ben.
I'm currently struggling really really hard to make this sort of grid work and also have climbable terrain. I'd need 3 dimensions, obviously, but I'd also need a way to tell the code that it's not ok to climb up into thin air.
+80 Proof Gameplay are you using the built in terrain system? if so this might help: docs.unity3d.com/ScriptReference/Terrain.SampleHeight.html alternatively (and I am kind of guessing here) you could try a 3d gride and a layer called "walkable". basically if the node does not touch an area defined as walkable it will be marked either as unwalkable or as "air" if you want to be more dynamic with your flags. But this risks a lot of extra unnecessary nodes. depending on height. In part it depends on the specifics of what you are trying to do as it will change the ways you want to enact specific restraints.
I didn't really understand the 'nodefromworldposition' method that you created, if you or somebody else could please explain this part I would really appreciate it.
I could listen to this guys voice all day, strangely relaxing . . .
Not me, for sure!
he pays hugh grant to do his voice overs xD
@@louissherwood5221 He has a far posher voice than Hugh Grant, though: he pronounces "off" as "orf" and "gone" as "gorne", for instance, and I suspect he would pronounce "hour" as "ahr" and "flower power" as "flahr pahr" (so-called triphthong smoothing). A very pleasant voice speaking Conservative RP. Not that usual nowadays.
@@peterbengtson7406 To me it's really not RP, it's more from mainland Europe (pretty sure he's Danish)
When he says "cheers", I melt every time.
17:00
(a + b/2) / b = (a/b) + (b/(2*b)) = a/b + 1/2 [ = a/b + 0.5 ]
And calculating "a/b + 0.5" is easier for the PC than "(a + b/2) / b".
Good optimization, thanks for pointing that out.
why the fuck would you do that? this is a float.
Not the same fact
I'd like to add one more thing about this for anyone else who scours the comments for tweaks - three years late, i know, but these tutorials are phenomenal and i've been going through them. I've learned more about A* than I ever thought possible.
Mathf.RoundToInt((gridSizeX-1) * percentX) is almost right, but not quite.
By subtracting 1 before multiplying by the percent, you won't go over the number of squares that exist, but you'll be getting a percent of an incorrect number. If you have a grid with 100 or more squares, you may eventually encounter situations where you are off by a square.
Also, you need to you FloorToInt, because assuming 0 is the left-edge of the grid, it's also the left edge of the first square. 0.5, then, would be the middle of the first square, and so would 0.9, 0.99, and so on. If you ever round up, you can be inaccurate by as much as half a square.
So instead what i've done is Mathf.FloorToInt(Mathf.Min(gridSizeX * percentX), gridSizeX - 1)
Did you mean:
Mathf.FloorToInt(Mathf.Min(gridSizeX * percentX, gridSizeX - 1))
Lovely pace for learning stuff - including mistakes, which are a natural part of the coding experience. I’m glad you are not editing them out.
just finished watching this tutorial, now gotta do it 99 more times for me to get it
At least you'll get a skill cape
19:30
if you round down a percentage multiplied by a grid-1 you can end with a target one node away from your actual current node.
Take x = 14.4 for example:
(14.4 + 30 / 2) / 30 = 0.98
x = round(29 * 0.98) = round(28.42) = 28, so you end up at node 28.
But if your x = 14.4 you are between x=14 and x=15, so you actually are at the far right node (29)
You should not round and subtract one, you should floor without subtracting:
x = floor(30*0.98) = floor(29.4) = 29
edit: you also need to clamp before floor:
int x = Mathf.FloorToInt(Mathf.Clamp((gridSizeX) * percentX, 0, gridSizeX - 1));
o/
You should also remove these lines>
percentX = Mathf.Clamp01(percentX);
percentY = Mathf.Clamp01(percentY);
Becouse otherwise the bottom Y node is always one above from the current node.
This is my whole function:
public Node NodeFromWorldPoint(Vector3 worldPosition)
{
float percentX = (worldPosition.x + gridWorldSize.x / 2) / gridWorldSize.x;
float percentY = (worldPosition.y + gridWorldSize.y / 2) / gridWorldSize.y;
int x = Mathf.FloorToInt(Mathf.Clamp((gridSizeX) * percentX, 0, gridSizeX - 1));
int y = Mathf.RoundToInt((gridSizeY) * percentY) +1;
return grid[x, y];
}
@@zoetechandme Can you please elaborate this little bit more. Why do you need to add +1 to int y?
o/
This!
THANK U
You're an amazing programmer. Thanks for the videos.
I saw this video in my recommended, and I've already watched it twice, but I clicked on it again just to listen to your voice lol
Omg I know I'm a bit late so you may well not see this comment but this tutorial dude wow. I'm trying to implement A* into an Xcom style strategy game and after hours of trying to follow another UA-camr (I won't name names but god it was infuriating), this tutorial is just what I needed :) I've followed this all the way through and feel so much better about A* now, you're a great programmer mate thanks so much.
Sebastian Lague More, and more videos please, you are a great tutor!!!
More videos about anything! In every video I learn something new.
Thank you Marcell :)
I have watched this and Part 1 and am super excited to try this stuff out. I'll be able to quickly create some fun games for my kids with this AI. Keep up the good work friend.
Thanks a lot. You are the best 😊 teacher. Explained everything in details and your voice have magic, can hear all the day without feel bored. thanks a lot again. 😇😊
I'm trying to implement this in Java and it works fine. I only had problem with percentX and percentY, wich were returning 5X bigger value than they should, but I fixed it. Thanks for great tutorial!
I'd love to see an update on this, using unity's new Tilemap Grid system.
This guy is the reason i requested .1x playing speed from UA-cam.
I came here from this guy named Daniel... he kind of just reuploaded your tutorial with his following your tutorial... he did NOT fix the "that's y it's meant to be z" for the percent value. I've been stuck for a week. Lol.
No idea what you're talking about but I'm still interested.
Thanks for making this tutorial and for also adding the source files for the 2D project somewhere in the comments (as the video is for 3D). I am still learning c# and unity and now trying to learn A* pathfinding. I am finding this really useful and educational.
Hey can you link me up with the code for 2D. I'm working with this and trying to figure out how to check for collisions on 2D
Amazing tutorial, I'm using Aron Granberg's pathfinding since I couldn't implement it myself. Your explainations are extremely easy to understand. Great work!
I wish the youtube has another LIKE button !! thank you Sebastian for this piece of magic code :)
Thanks!!!!!!! Incredible explanation! I was struggling setting the grid for my project, but I followed along and it turned out really simple and easy. now to part 3...
I am a big fan of you! Great way to explain the logic of your code, thanx for the amazing tutorial.
Awesome video, one problem that I encountered while testing this code is that when you pass the player position parameter to NodeFromWorldPoint you have to convert coordinates to local relative to grid object with Transform.InverseTransformPoint otherwise if your grid is not centered on 0,0,0 then it will not work :)
Hey there, I know it's 3 years late, but how would you go about doing this? Could you clarify? Thanks.
To anyone ready to spend an hour or so looking through the comments for the solution. Try this method from @itsybitsypixel. His comment is buried, so hopefully this finds and helps you before you start digging:
ANYONE WHO IS HAVING INACCURATE POSITIONS FROM THE NodeFromWorldPoint READ THIS
I found that the "NodeFromWorldPoint" method returned an inaccurate position while on the sides of the grid, so I tried remaking it too show a more accurate position. It's basically the same but it skips the percent and uses the nodeRadius and nodeDiameter variables and that somehow works.
int x = Mathf.RoundToInt((worldPosition.x + gridWorldSize.x / 2 - nodeRadius)/nodeDiameter);
int y = Mathf.RoundToInt((worldPosition.y + gridWorldSize.y / 2 - nodeRadius)/nodeDiameter);
x = Mathf.Clamp(x, 0, gridSizeX - 1);
y = Mathf.Clamp(y, 0, gridSizeY - 1);
return grid[x, y];
^This code is inside the method^
I tested this and it worked and gave me a more accurate position, but I have not tested this with the rest of the tutorial so be warned.
Also I am using this for a 2D game so I used the Y position instead of the Z position in "worldPosition". If you are making a 3D game use Z instead.
thank you very much for this Sebastian i now understand what i need to do to make a placement grid for my citybuilder game project
worked perfectly for me. really enjoying this series. :D thanks for sharing it
Talk about A(*) programmers! Great video and great code, I love all your videos!
I was JUST wondering how I was going to do the AI for the top down shooter. I've had some exposure to A* before but never in the context of actually doing it.
Sebastian: I love you.
lmao gay
@@windowsxseven I love you
@@Phagocytosis 💝💝💘💋💋💌💓💕💞❤️🔥💟💚💙💜😘😘😙🥰💕💗💖
There's another way to do 17:17 on the NodeFromWorldPoint function.
Which is to just Vector3.InverseLerp(-gridPosition*.5,gridPosition*.5,worldPosition.x)
It's automatically clamped to 0 and 1 so no need to do Mathf.Clamp or whatever:
Mathf.InverseLerp(-gridWorldSize.x*.5f,gridWorldSize.x*.5f, worldPosition.x);
Mathf.InverseLerp(-gridWorldSize.z*.5f,gridWorldSize.y*.5f, worldPosition.z);
Remember, gridWorldSize and worldPosition are 1:1 proportion.
Little definition of Inverse Lerp:
InverseLerp(min,max,t)
What InverseLerp does is that it returns a float value that converts value t into a value between 0,1.
Kinda like Lerp except t is a value you pass in that is between 0 and 1 and returns a float value that is between min and max.
its an old video but gotta love the fact that you got stockfish there
Really great tutorial!
Quick, to the point and clear.
Thanks!
Thanks for the great Tutorial. It helped me very much.
Also good explanation and easy to follow.
if you have an inaccurate position from the NodeToWorldPoint, make sure your GameObjects position with the Grid Script is set to Vector3(0,0,0)
if possible i would really like to see a tutorial/tutorial series on procedural level generation :)
Yeah that'd be fun :) Do you have something particular in mind? I could easily do some sort of cool cave generation using using cellular automata..
Sebastian Lague
Yeah, either your suggested cave generation or some kind of race track, which would be of greater interest to you ?
Another great tutorial Sebastian! Procedural generation sounds like a great idea! I would also like to suggest procedural voxel terrain in Unity, maybe block type worlds like Minecraft or smooth voxel terrains by using something like marching cubes or even better Dual Contouring, which allows you to have sharp features for buiulding but the smoothness that you want for the ground.
Sebastian Lague
I think something along the lines of Terraria style map generation would be extremely useful.
Sebastian Lague
Also, if possible random planet generation, using spheres as the planet for space exploration, would be very intriguing.
excellent tutorial, thank you very much dude, you save my FYP and my life
Just implemented this for my infinite world map! I love GMS2's new class/object programming
what?... how? seriously, im lost how do u do it for an infinite map
omg, what a amazing video for a star, thank you very much
It might be a fun little project to get A* path finding to work on your spherical world.
"fun" might not be the best word to describe it.
A little late and don't know if this has been posted already or not, but currently you don't use the unwalkableMask. If you have for example other gameobjects with a collider, they will also be added to the non-walkable grid. To fix this you have to add the layer mask to line 28:
bool walkable = !(Physics.CheckSphere(worldPoint, nodeRadius, unwalkableMask));
Also to update the grid just run the CreatGrid(), for example by pressing the N button:
if (Input.GetKeyDown(KeyCode.N))
{
CreateGrid();
}
or from a different script (don't forget to make CreateGrid() public:
if (Input.GetKeyDown(KeyCode.N))
{
GameObject.Find("A*").GetComponent().CreateGrid();
}
I would like to see how you would go about having an Enemy AI that jumps up and down platform to chase the player , in a 2D SideScroller platformer, Which route would you pick ? A* pathfinder , Raycast , Grid base ,MeshBase. Possibly also giving your opinion on difference between them with Pros and Cons.
I absolutely love this ^^ such a clear explanation :)
Be aware if you are following this tutorial there is a pitfall, the map is suppose to be at 0,0,0 it cant move if you do the path to the character is off. To fix this do this instead of what was provided.
private Node GetNodeFromWorldPoint(Vector3 worldPosition)
{
var percentX = (worldPosition.x - transform.position.x + GridSize.x / 2) / GridSize.x;
var percentY = (worldPosition.y - transform.position.y + GridSize.y / 2) / GridSize.y;
Thank me later but this portion really threw me off and solved it in about 5 minutes.
you literally saved my life thanks
This needs to get pinned
thanks
It is like this actually:
float percentX = (worldPosition.x - transform.position.x + gridWorldSize.x/2) / gridWorldSize.x;
float percentY = (worldPosition.z - transform.position.z + gridWorldSize.y/2) / gridWorldSize.y;
But, thank you for saving my day!
thank you you are great dad
A* Life Saver
Was a really good video!
exactly what i was looking for, thanks a lot! :D
you can use this with his cavesystem if you diable the node script then enable it after runtime when the mesh and collision has been generated.
I love these videos, they are great!
Just one small thing that's bugging me slightly, at 16:39 and in earlier videos, you're calling these things percents but that would be something between 0 and 100 rather than between 0 and 1, right? Would be better (in terms of intuitive variable names etc.) to call them fractions, as that is what they are.
Saying "42" versus "42%" would be quite different in meaning. Mathematically rather than colloquially, a percent is a number between 0 and 1, as Sebastian has presented here. The reason for this is that "percent" means literally "divided by 100." So percents are indeed fractions: they are always fractions out of 100 🙂
@@marcindathefierce Exactly, I know that. But he said "a percentage of point five" (for the middle of the screen), when it would be either a fraction of point five, or a percentage of 50, right? That's what I meant.
We should also take node radius and our A* object position into account when getting node from world point or the results will be pretty inaccurate.
Here's what I ended up with:
float percentX = (worldPosition.x - transform.position.x) / gridWorldSize.x + 0.5f - (nodeRadius / gridWorldSize.x);
float percentY = (worldPosition.z - transform.position.z) / gridWorldSize.y + 0.5f - (nodeRadius / gridWorldSize.y);
+Alexander Sorokin Thanks!
+Alexander Sorokin I think I'm having this problem. When I was following along and testing and put it at 0,0,0 it was all fine. Now that I actually want to implement it in my game as soon as it pathfinds it's trying to go somewhere weird.
I think its the NodeFromWorldPoint method that's doing it but can't figure out how to fix it.
Your reply seems to suggest there should be some code. Mind posting it again as I can't see anything and I'm hoping you have the answer!
Thanks :)
Ashley Jones dunno why you don't see it, I am still seeing it in my reply.
Anyway, here you go:
gist.github.com/alsorokin/2550976f89b5649314a4
Helped me, thank you very much! :)
this is the most important comment on youtube I've ever read! UP YOU GO, SIR!
WITHOUT THIS, YOU CAN'T USE IT IN YOUR GAME, meaning: you can't move the grid.
Great tutorial - many thanks
So I got all the code right but it just wouldn't work and after a half hour of checking over the code turns out I misspelled "position" 😑
that's 40% of being programmer - fixing simple mistakes ¯\_(ツ)_/¯
A CLASSIC
How did you not see that on the error log lmao
That’s a mood
get a linter
Me, about to go to bed because I work tomorrow: "Well, guess I'm watching this whole series first".
OverflowException: Number overflow.
Grid.CreateGrid () (at Assets/Pathfinding/Pathfinding_test/Grid.cs:22)
Grid.Start () (at Assets/Pathfinding/Pathfinding_test/Grid.cs:18)
I use Unity 5
trinketos I've got same error (grid = new Node[gridSizeX, gridSizeY];) of Number overflow. have you got the solution? I am also using unity 5.0.0.
no, that's bad for me xD, maybe I have to ask to some "experts" in unity xD
trinketos Ooo :|
:D
+trinketos You managed to get this part working?
What does following line means at 9:42 :
Vector3 worldPoint = worldBottomLeft + Vector3.right * (x * nodeDiameter + nodeRadius) + Vector3.forward * (y * nodeDiameter + nodeRadius);
You're finding the middle point of the node the loop is currently looking at.
If you start at worldBottomLeft, which is the bottom left point of the bottom left node, but you're now looking at node (x,y), you would need to move x times the diameter of a node to the right to end at the bottom left of the x'th node, but you want the middle point, so you add the nodeRadius one more time. Therefore you add x * nodeDiameter to move to that node, and then nodeRadius again to get to the middle. You multiply all that with the unit vector to the right to make sure you're going in the right direction and using the right units.
The other part is just the same, but for the y coordinate. It uses forward rather than up to make sure you don't go up (off of the ground) in the three-dimensional space.
Wow, nice tutorial as always!
One question though.
What would the math look like inside the NodeFromWorldPoint function if the grid origin was in the corner at 0, 0 and not at the center?
These are the variables I use:
public int gridRows = 5;
public int gridColumns = 5;
public float nodeScale = 1;
In CreateGrid() this is what I do:
Vector3 nodePos = transform.position + new Vector3(r, 0, c) * nodeScale;
bool walkable = Physics.CheckBox(nodePos, Vector3.one * nodeScale, Quaternion.identity, obstacleLayerMask) == false;
grid[r, c] = new Node(nodePos, walkable);
As you see, I left out the extra math and simply build the grid from "transform.position".
The problem is, I can't figure out how I get a node from a world position.
This is the closest "formula" I could figure out thanks to the people in the comments.
int x = Mathf.FloorToInt((worldPosition.x - transform.position.x) + (gridRows * 0.5f) / nodeScale);
x = Mathf.Clamp(x, 0, (gridRows - 1));
int z = Mathf.FloorToInt((worldPosition.z - transform.position.z) + (gridColumns * 0.5f) / nodeScale);
z = Mathf.Clamp(z, 0, (gridColumns - 1));
return grid[x, z];
But the bigger the offset from World 0,0,0 the bigger the offset between worldPosition and nodePosition in the grid. Any help?
in NodeFromWorldPoint function Add: worldPosition.x - transform.position
Like:
float percentX = ((worldPosition.x - transform.position.x) / gridWorldSize.x) + .5f;
OR
float percentX = ((worldPosition.x - transform.position.x) + (gridWorldSize.x / 2)) / gridWorldSize.x;
I usually use this for "index from positions":
int x = (int)((worldPosition.x - worldBottomLeft.x) / (nodeRadius * 2));
int y = (int)((worldPosition.z - worldBottomLeft.z) / (nodeRadius * 2));
x = Mathf.Clamp(x, 0, gridSizeX - 1);
y = Mathf.Clamp(y, 0, gridSizeY - 1);
return grid[x, y];
ps: worldBottomLeft must be global and calculate at Start()
wow, copying this guy makes me feel clever :O
Best channel ever
fantastic tutorial Sebastian!! I have one issue. The playerNode will not update or show as a different color. I even continued on I even continued on to the next tutorial for pathfinding to see if the old code would correct itself and it did not. I changed the zed and y coordinates and everything but it would work on either the x or y plane. So that means no path finding. It does work for the layer mask but none of the update type of functionality. Just the stuff that's on the startup section
what do you suggest
I know it's been years since this video came out but can we generate nodes onto something more abstract than a plane? Say something like a sphere or something with hills. This is a good starting point for me in learning more about A* Pathfinding.
Sure you can, the only difference is going to be how to assign the location of the node, the algorithm itself doesn't change at all.
Can you enable the subtitles ? some of us are deaf.Thanks.
You’re deaf?
No
I'm sorry, I shouldn't be laughing, but this comment is so hilarious in the best way possible. "Some of us are deaf" so matter of fact lmao
If you're deaf, I recommend not relying on specific platforms to supply Accessibility features for this exact reason.
Most OSs both on phone and Computers have features for generating captions. They aren't always right, but they all get pretty close.
add if (grid != null) if you are tired of the constant errormessages it just checks if it has a grid before trying to calculate
{
Node playernode = nodefromworldpoint(player.position);
}
then he deleates it in the end of the video. wow like getting my painting ripped from the refrigirator :(
Love the video, please do audio books - your voice is great!
You are a boss at debugging....
Hey Sebastian,
I was wondering what the equivalent of creating a plane and, using gizmos to visually display the walkable and unwalkable regions of the world would be for a 2d project?
Furthermore, What is the equivalent of the Physics.CheckSphere method in a 2d environment? At the moment I am currently using colliders, and I was hoping that there is a better solution in existence.
Thanks!
Phyiscs2D.OverlapCircle works. 3 years late answer, but maybe someone else in the future will find it useful.
@@PvPNetwork yeah, thanks. 2 years late, but still... haha
is there any way in which we could avoid the diagonal grid tiles and figure out the path to the target only by moving horizontal or vertical directions if you have any suggestion please let me
know
There is something I would like to see, the nodes being generated on 3D coords and not only on 2D, I have an Idea and will try to use ur way but the implementation on 3D aspect needs a bit more thinking before just dropping the nods around the world for example if we are going to put them on the world terrain, how should we handle the slope that is possible for navigation? etc. etc. so can you add another video about node generation for 3D space. Thanks
+Alireza Khodakarami Did you get your idea working? I'm trying to do something similar. Please do help me out
80 Proof Gameplay yah i got some sort of working solution for 3d system but the lookup table would be too big for each scene or at least i think i was doing hasty job in R&D but if you join 3Dbuzz.com, i will soon publish some videos there about my systemm subscription is free, so why not?
what does the Node[,] variable do in Grid? It's not working for me, do I have to attach the node script?
GetNodeFromWorldPos has a problem. When the world pos is near edges it gets inaccurate. For example when it's at the most edge the position percentage is below zero. When you round that value to nearest Integer if that below zero value is less than 0.5f it will round to 0 and you get the most edge node yes But if it's more than 0.5 it will round to 1 and you will get next the Node.
You should floor it without subtracting one than clamp to max index so it will not get out of index.
very wonderfull tutorials man, im enjoying so much your tutorials. And i want to add something very little, i dont like that NodeFromWorldPoint get the node to the right or bottom of the capsule so i modified the percent so they are calculated from the center of the capsule, but i dont know if the modification i did its really working on any case, here is my modification:
percentX = (worldPosition.x + gridWorldSize.x/2 + nodeRadius) / gridWorldSize.x;
percentY = (worldPosition.z + gridWorldSize.x/2 + nodeRadius)/ gridWorldSize.y;
pd: forget it, it doesnt work, i was testing it just for the top right, the other sides doesnt work.
pd2: well i think now works, just to make more precise the transition between nodes:
public Node NodeFromWorldPoint(Vector3 worldPosition) {
float percentX = (worldPosition.x + gridWorldSize.x/2) / gridWorldSize.x;
float percentY = (worldPosition.z + gridWorldSize.y/2) / gridWorldSize.y;
percentX = Mathf.Clamp01(percentX);
percentY = Mathf.Clamp01(percentY);
int x = Mathf.RoundToInt((gridSizeX-1) * percentX);
int y = Mathf.RoundToInt((gridSizeY-1) * percentY);
//here start my added modification
if (grid [x, y].worldPosition.x + nodeRadius < worldPosition.x && x < gridSizeX - 1 && x > 0)
x++;
else
if (grid [x, y].worldPosition.x - nodeRadius > worldPosition.x && x < gridSizeX - 1 && x > 0)
x--;
if (grid [x, y].worldPosition.z + nodeRadius < worldPosition.z && y < gridSizeY - 1 && y > 0)
y++;
else
if(grid [x, y].worldPosition.z - nodeRadius > worldPosition.z && y < gridSizeY - 1 && y > 0)
y--;
return grid[x,y];
}
this should be easy for you but since i'm new with unity i wanted to see if im doing it right.
Hey, great video! Quick question, if I want a grid node for a 3d terrain, should I just raycast down and create each node at the hit point, is it that simple?
You need to explain more in detail what exactly the variables do. I feel like im just copying, without learning anything,. Thanks for the videos though!
Agreed. He doesn't explain each step thoroughly enough.
I understood fine... :/
Probably it's a good idea to go through a basic programming training first.
His tutorials are not about programming, so you should learn a bit before and it will become more clear.
This tutorial is beautifully done, the pace might be high for starters but as an experienced programmer i really appreciate the speed. Also, programming wise there is nothing special or difficult in the used variables/functions.
This is so good! Thank you!
I changed the code a bit to account for a fact that a large object (e.g. player ship) can occupy several nodes. To create gizmos with the same color for all such nodes, I added a boolean to Node object (playerhere) and a condition in the CreateGrid() method ("player_shield_weak" is simply a collider object of the player ship):
if (walkable == false) {
Collider[] col = Physics.OverlapSphere (worldPoint, nodeRadius);
if (col [0].gameObject.tag == "player_shield_weak") {
grid [x, y] = new Node (walkable, worldPoint, true);
} else {
grid [x, y] = new Node (walkable, worldPoint, false);
}
} else {
grid [x, y] = new Node(walkable, worldPoint, false);
}
This creates a Node object with playerhere =true, and then, in DrawGizmos() method I just changed the condition to check this boolean:
if (node.playerhere == true)
{
Gizmos.color = Color.cyan;
}
and it worked!
Hi Sebastian, nice tut!
The 'NodeFromWorldPoint' function works fine for me when the player is near the (0, 0) point (the center of the map, we can say). But it gives me unaccurate values if I put the player far from that point. Any ideas about what's happening?
Thank you!
Is it weird that I reply to a 3-year-old comment?
Were you able to solve this? I kinda know where the problem is; if you're in a position that is larger than the grid world size (say your world size is set to 20 and you're at position 70), you're technically out of bounds, even though you're inside the grid, and that's because the division result will be larger than 1 which would then be clamped to 1 which is at the border of the grid. So we need some kinda offset from the origin, but so far all my attempts have failed :(
I've actually just solved the problem. As I mentioned above, the problem was with the offset. I was trying to offset everything from the origin, but the solution was to actually pretend we've never left the origin. To do that, I subtracted the player's position with the object's position (so if the player is at 75,0 and the enemy is at 70,0 --> We can treat it as if the enemy is at the origin and the player is at 5,0), this way the function makes sense and resulting value would always be
Awesome videos! But could you please increase the font size of your code? That would be great
thanks for this video how can I do for only make a line renderer betwen a few cubes in taking the shortest path?
I know this might be a little bit off topic, but have you considered doing a GOAP AI tutorial? Since this sort of pathfinding is popularly implemented with GOAPs, i figured it could be an interesting follow up.
Also, keep up the good work :)
Great tutorial thank you very much.
I've been using "Sublime Text 2" in Unity for a little while now, mostly because I love its Ctrl+D function. When you mentioned the replace x with y using Cmd+R at 8:32, is that a plugin? I do notice you are using iOS, while I am on Windows, but I tried using Ctrl, the Windows button, Alt, Shift, and then went on Google to try and look it up. I can't find anything on it. This might be a stupid question with an obvious answer, but I'm just very confused right now and would love to know how you did that. :P
Can you explain the math behind Converting World point to Node.
Hello. Since I realize that he is pretty bad at explaining. I will explain it to you. The point of WorldPoint is simple. It changes the point for every new cube(node in this example) by calculating the diameter and moving the new position correspondingly left and up to the diameter, so the cubes calculate the spacing between them and don't spawn in the same place... That's as simple as I can to explain it. First he creates a massive of object from the class Node//Node[,] grid\\ which contains (walkable and worldPosition) from the class //public Node(walkable, worldPosition);\\
Then he calculates the sizeX and sizeY by determing the diameter of every cube so he can get clear picture of how many cubes are to take the grid and then he creates a for loop to go through every cube on the grid and change the position of every new one by using a virtual function of Node //grid=new Node[gridSizeX, gridSizeY]\\ and the worldpoint(which I already tried to explain). Hope I helped. It can be done easier by the way but he "overcomplicates" the code.
What he does is basically make a massive and save every cube's position by making it a virtual function so for exmaple grid[0,1] will have a worldPosition equal to worldPoint as seen in the code where he changes the assigns the parameter worldPoint to worldPosition.
IFrozenFireI Thank you for replying and i understood that.
good clear instructions. thanks
wow,just wow dude u r amazing where r u from !!! from land of genuis
I know this video is old, but the code still works incase anyone was wondering.
*ANYONE WHO IS HAVING INACCURATE POSITIONS FROM THE NodeFromWorldPoint READ THIS*
I found that the "NodeFromWorldPoint" method returned an inaccurate position while on the sides of the grid, so I tried remaking it too show a more accurate position. It's basically the same but it skips the percent and uses the nodeRadius and nodeDiameter variables and that somehow works.
int x = Mathf.RoundToInt((worldPosition.x + gridWorldSize.x / 2 - nodeRadius)/nodeDiameter);
int y = Mathf.RoundToInt((worldPosition.y + gridWorldSize.y / 2 - nodeRadius)/nodeDiameter);
x = Mathf.Clamp(x, 0, gridSizeX - 1);
y = Mathf.Clamp(y, 0, gridSizeY - 1);
return grid[x, y];
^This code is inside the method^
I tested this and it worked and gave me a more accurate position, but I have not tested this with the rest of the tutorial so be warned.
Also I am using this for a 2D game so I used the Y position instead of the Z position in "worldPosition". If you are making a 3D game use Z instead.
I know this is old, but this tutorial is probably the best for pathfinding, and sorry for asking a question 2 years later, but I am also doing a 2D game, and for me when I first test to see the red and white squares, they are all white for me. None of them turn red. I changed the code so it showed in an XY way and removed the Z, but it doesn't work. I think it has something to do with bool walkable = !(Physics.CheckSphere(worldPoint, nodeRadius, unwalkableMask)); The 3D physics I think is the problem, but not sure how to fix it. Ideas?
@@Seanld98 Have you created a layer mask for unwalkable objects on your scene? If you have check if you have added the layer mask to your unwalkable game objects. Also if that is not the case check if you maybe forgot to change the "Unwalkable Mask" parameter on your "Grid" script from "Default" to "Unwalkable". If this is all correct for you maybe you miss-spelled something while writing the gizmos? This "bool walkable = !(Physics.CheckSphere(worldPoint, nodeRadius, unwalkableMask)); " seams fine to me :P.
Hope this helps.
@@smilos99 I have double checked all that, but what I found changed it was adding the normal Box Colliders (non 2D) to the 2D boxes and that seemed to work so I'm not sure why it wouldn't work in the 2D space, thanks though :)
@@Seanld98 I'm currently going through this tutorial. This worked for me: bool walkable = !(Physics2D.CircleCast(worldPoint, nodeRadius, Vector3.forward, nodeRadius, unwalkableMask)); 2D and 3D colliders don't collide, so you gotta go 2D!
Thanks
PixelMannen! I had the same issue and your comment solved it.
How would you change this to make it work with 2d sprites instead of cubes? So far my best idea is to hide cubes behind the sprites which has worked but seems like it might cause lag with lots of obstacles.
Edit: Looking over it it seems that it is the boxes collision that causes the detection so I just need some way to add collision to sprites.
Thanks !! you saved my proyect
Thank u for this tutorial. How can I implement this in 2d top down?
just change vector.forward to vector.up and instead of spherecast use
bool walkable = !(Physics2D.OverlapBox(worldPoint, new Vector2(nodeDiameter, nodeDiameter), unwalkableMask));
or at least it seems to work for me at this lesson's stage of implementing
and
Gizmos.DrawWireCube(transform.position, new Vector3(gridWorldSize.x, gridWorldSize.y));
for grid
Thank you so much 💕💕
@@ZZaGGrrUzz Thanks buddy, i am currently banging my head over this haha.
I don't know if it is because of a recent update but the methode OnDrawGizmos() is being callsed before the start function, which means that the grid variable stays null and the grid is never drawn even if the CreateGrid() function works correctly, i will probably try to save the grid in an external file and import it in the Asset folder
Did you find a solution? I'm sturggling with this too
Hey - you are amazing! I love your teaching style! Thank you for these videos. I just wanted to ask - does the grid know how to detect sprites? I have no trouble getting the grid set up the way you have it, and it works fine with cubes as long as they're under the layer "unwalkable", or with newly imported quads etc. But not sprites, it seems.
Do you have any advice? Is there something about the sprite renderer that acts differently than a mesh renderer?
Thanks again!
Perhaps it's something to do with the "bool walkable = !(Physics.CheckSphere (worldPoint,nodeRadius,unwalkablemask)); ?
Because sprites are 2d, does it have to be a different physics check?
that's my guess anyway.
+Anna Leonid
Yup yup.
For 2D,
Change,
bool walkable = !(Physics.CheckSphere (worldPoint,nodeRadius,unwalkablemask));
to
bool walkable = !(Physics2D.OverlapCircle(worldPoint, nodeRadius, unwalkableMask));
After this, it will still not work because, the sprite have no collider to detect collision (Physics2D.OverlapCircle)
Therefore, add a 2D collider to the sprite.
Worked on mine.
+Muhd Amirul Thanks!! That totally works!! One more question.
How would I set walkable so that it can detect both sprites and 3d objects?
bool walkable = !(Physics2D.OverlapCircle(worldPoint, nodeRadius, unwalkableMask)) || !(Physics.CheckSphere (worldPoint, nodeRadius, unwalkableMask));
Am I missing some parentheses? I'm unable to get the grid to detect both.
+Anna Leonid
Yo yo,
Sorry for late reply. I was addicted to a specific game and yeah...
I apologize, as this time, I am unable to explain why the following code work.
Change,
bool walkable = !(Physics2D.OverlapCircle(worldPoint, nodeRadius, unwalkableMask)) || !(Physics.CheckSphere (worldPoint, nodeRadius, unwalkableMask));
to
bool walkable = !( (Physics2D.OverlapCircle(worldPoint, nodeRadius, unwalkableMask)) || (Physics.CheckSphere(worldPoint, nodeRadius, unwalkableMask)) );
It would seems that it has something to do with the ''!''.
If it still doesnt detect the 3D object, make sure that the 3D object is touching the Grid.
If it still doesnt work, then all the best.
Im not sure if the new code would affect the pathfinding, because I already ditch my plan of using this tutorial because it doesnt provide me with smooth pathfinding, and dynamic pathfinding.
"dynamic pathfinding"? Dude, for it to be "dynamic", you should just call the appropriate code in an update function.
Hello there! I know this video is quite old, but I'd like to ask something... for some unknown reason, the nodes that are at the corners of my objects don't turn red, unless I change the value of the node size... it's weird because I can clearly see the object tresspassing the node's limits... well, thanks in advance, and keep up with the great work!
Any suggestions for me to find the best way to learn C# like that??? have been struggling for a while now, quite a complex lang.
is it possible to use this in a game in unity where your scene is so smalll that your node points to world points need to get small floats/doubles? I'm trying to use this in a game but sometimes my enemies go to spots they shouldn't be able to and get stuck, i think its something with the conversion but not sure.
Useful! Love it! Keep it going man! :D
This is an excellent presentation. But... around 18:45 the clamping protection is weak. I.e. a 10 element array indexed with 1.0 will attempt to access element 10 - but only 0 though 9 are valid. Of course if I watch the rest of this excellent video and this problem is addressed I will be embarrassed.
I'm encountering a problem with the code. I have written everything down like it was done in the video, but when i run the program in Unity, no grid is drawn at all. Console doesn't return any errors either.
MrRemorc same problem here
I had the same problem and it was being caused by a missing decimal point so triple check your code!
I'm also having this problem - can't see any of my grid!
If somebody has the same problem : you certainly don't have active Gizmos in your Scene view. Check on Google.
Thank you!
I wonder why you use the sphere check instead of a boxcheck, isn't that more efficient?
Good Tutorial! Do you know a way how to detect touch gestures?
Sebastian Lague
If I wanted to make the cyan colored detection cube for the player to work properly, does the plane have to be centered at 0,0,0? I've tested this out and that seems to be the case. What's a good solution to have the player detection working properly for planes positioned at any world position? Thanks in advance.
Im am trying to do this in UE4 and C++ i really wonder where you guys
learn this stuff because i wantto learn it and atm i have no idea
what i have to change in my code so this works. I also have no idea what
all the position calculations do . so if anyone has some websites where
i can learn this stuff pls let me know.
17:29
float percentX = (worldPosition.x + gridWorldSize.x / 2) / gridWorldSize.x;
is actually:
float percentX = (worldPosition.x / gridWorldSize.x) + .5f;
means that you are taking the world position, dividing it with entire grid and adding a half.
I think both versions will work and return the correct value or not? Im too sleepy to think more about it for now
@@r1pfake521 Same math but I tried to make it look more simple.
Hey Sebastian, great Video !!! But I have a question about the Node-Constructor in the Node class. I am a starter-programmer so forgive me any stupidity. Here is my Question : Why didn't you create the Node-Constructor in the grid-script and would this be possible too ? BR, Ben.
I'm currently struggling really really hard to make this sort of grid work and also have climbable terrain. I'd need 3 dimensions, obviously, but I'd also need a way to tell the code that it's not ok to climb up into thin air.
+80 Proof Gameplay are you using the built in terrain system? if so this might help: docs.unity3d.com/ScriptReference/Terrain.SampleHeight.html
alternatively (and I am kind of guessing here) you could try a 3d gride and a layer called "walkable". basically if the node does not touch an area defined as walkable it will be marked either as unwalkable or as "air" if you want to be more dynamic with your flags. But this risks a lot of extra unnecessary nodes. depending on height.
In part it depends on the specifics of what you are trying to do as it will change the ways you want to enact specific restraints.
I didn't really understand the 'nodefromworldposition' method that you created, if you or somebody else could please explain this part I would really appreciate it.