A* Pathfinding (E02: node grid)

Поделиться
HTML-код
  • Опубликовано: 20 сен 2024
  • Welcome to the second part in a series on pathfinding in Unity. In this episode we look at how to create the grid of nodes required to begin using the A* search algorithm -
    (explained in detail in part one: • A* Pathfinding (E01: a... )
    Source code: github.com/Seb...
    If you'd like to support these videos, you can do so with a recurring pledge on Patreon, or a one-time donation through PayPal. / sebastianlague
    www.paypal.me/...

Комментарии • 552

  • @synvian8212
    @synvian8212 8 лет назад +307

    I could listen to this guys voice all day, strangely relaxing . . .

    • @eleos5
      @eleos5 5 лет назад +2

      Not me, for sure!

    • @louissherwood5221
      @louissherwood5221 5 лет назад +1

      he pays hugh grant to do his voice overs xD

    • @peterbengtson7406
      @peterbengtson7406 4 года назад

      @@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.

    • @joshual3486
      @joshual3486 4 года назад

      @@peterbengtson7406 To me it's really not RP, it's more from mainland Europe (pretty sure he's Danish)

    • @gobblestheturkey1413
      @gobblestheturkey1413 3 года назад +1

      A* asmr

  • @Garbaz
    @Garbaz 9 лет назад +287

    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".

    • @SebastianLague
      @SebastianLague  9 лет назад +139

      Good optimization, thanks for pointing that out.

    • @MrMineHeads.
      @MrMineHeads. 6 лет назад +1

      why the fuck would you do that? this is a float.

    • @scholes8734615
      @scholes8734615 6 лет назад +2

      Not the same fact

    • @brainlow
      @brainlow 6 лет назад +40

      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)

    • @QuestionMark43
      @QuestionMark43 6 лет назад +19

      Did you mean:
      Mathf.FloorToInt(Mathf.Min(gridSizeX * percentX, gridSizeX - 1))

  • @FranciscoAmorim
    @FranciscoAmorim 7 лет назад +65

    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/

    • @zoetechandme
      @zoetechandme 3 года назад +5

      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];
      }

    • @DancingManson
      @DancingManson 3 года назад +4

      @@zoetechandme Can you please elaborate this little bit more. Why do you need to add +1 to int y?

    • @umarfaroukabdulmutallab4451
      @umarfaroukabdulmutallab4451 2 года назад

      o/

    • @dumbcow-j97
      @dumbcow-j97 Год назад +1

      This!

    • @camo_man
      @camo_man Год назад +1

      THANK U

  • @mr_donutz
    @mr_donutz 4 года назад +36

    just finished watching this tutorial, now gotta do it 99 more times for me to get it

  • @bejoscha
    @bejoscha 5 лет назад +8

    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.

  • @damien5266
    @damien5266 8 лет назад +46

    You're an amazing programmer. Thanks for the videos.

  • @MACHINEBUILDER
    @MACHINEBUILDER 3 года назад +3

    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

  • @bwegrzyn
    @bwegrzyn 3 года назад +1

    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!

  • @burhanuddin9047
    @burhanuddin9047 4 года назад

    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. 😇😊

  • @moduntilitbreaks
    @moduntilitbreaks 4 года назад +3

    This guy is the reason i requested .1x playing speed from RUclips.

  • @jessejones6756
    @jessejones6756 5 лет назад +16

    No idea what you're talking about but I'm still interested.

  • @levonravel3698
    @levonravel3698 3 года назад +11

    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.

    • @impact3373
      @impact3373 Год назад +1

      you literally saved my life thanks

    • @juicedup14
      @juicedup14 Год назад +1

      This needs to get pinned

    • @diggerpy
      @diggerpy Год назад +1

      thanks

    • @dumitrascumihai-cosmin1615
      @dumitrascumihai-cosmin1615 Год назад +1

      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!

    • @sanmaro91
      @sanmaro91 Год назад +1

      thank you you are great dad

  • @lamdasoftworks1165
    @lamdasoftworks1165 6 лет назад +11

    I'd love to see an update on this, using unity's new Tilemap Grid system.

  • @pixeldustinteractive
    @pixeldustinteractive 5 лет назад +2

    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.

  • @MrNintendeion
    @MrNintendeion 3 года назад

    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 RUclipsr (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.

  • @web_tutorials_for_beginners
    @web_tutorials_for_beginners 9 лет назад +2

    Sebastian Lague More, and more videos please, you are a great tutor!!!
    More videos about anything! In every video I learn something new.

  • @PatrickWilliamsphd
    @PatrickWilliamsphd 6 лет назад +2

    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.

  • @BlockerofDoom
    @BlockerofDoom 7 лет назад +2

    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 :)

    • @Tevan1n
      @Tevan1n 3 года назад +1

      Hey there, I know it's 3 years late, but how would you go about doing this? Could you clarify? Thanks.

  • @gadgetboyplaysmc
    @gadgetboyplaysmc 4 года назад +3

    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.

  • @Undead2k
    @Undead2k 7 лет назад +2

    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.

    • @dead2gamer
      @dead2gamer Год назад

      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

  • @10chaos1
    @10chaos1 9 лет назад +1

    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

  • @tshichan
    @tshichan 4 года назад +2

    I wish the youtube has another LIKE button !! thank you Sebastian for this piece of magic code :)

  • @danny3man
    @danny3man 5 лет назад +48

    Can you enable the subtitles ? some of us are deaf.Thanks.

    • @grandpas-stuff
      @grandpas-stuff 11 месяцев назад

      You’re deaf?

    • @scoreandspore.5606
      @scoreandspore.5606 7 месяцев назад +1

      No

    • @braedenL29221
      @braedenL29221 2 месяца назад

      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

    • @pureatheistic
      @pureatheistic 7 дней назад +1

      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.

  • @Ensiferum888
    @Ensiferum888 9 лет назад

    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!

  • @naipeadicto
    @naipeadicto 9 лет назад

    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...

  • @worempie
    @worempie 7 лет назад

    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();
    }

  • @RoutineJustice
    @RoutineJustice 9 лет назад +4

    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.

    • @windowsxseven
      @windowsxseven 3 года назад +1

      lmao gay

    • @Phagocytosis
      @Phagocytosis 2 года назад

      ​@@windowsxseven I love you

    • @windowsxseven
      @windowsxseven 2 года назад +1

      @@Phagocytosis 💝💝💘💋💋💌💓💕💞❤️‍🔥💟💚💙💜😘😘😙🥰💕💗💖

  • @JakeDownsWuzHere
    @JakeDownsWuzHere 8 лет назад +1

    worked perfectly for me. really enjoying this series. :D thanks for sharing it

  • @tumankito7776
    @tumankito7776 3 года назад

    I am a big fan of you! Great way to explain the logic of your code, thanx for the amazing tutorial.

  • @MrSquishedsquashed
    @MrSquishedsquashed 9 лет назад

    Really great tutorial!
    Quick, to the point and clear.
    Thanks!

  • @sits
    @sits 8 лет назад +49

    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);

    • @ukaszw7924
      @ukaszw7924 8 лет назад +1

      +Alexander Sorokin Thanks!

    • @ashleytwo
      @ashleytwo 8 лет назад

      +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 :)

    • @sits
      @sits 8 лет назад

      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

    • @FeuerfallFan
      @FeuerfallFan 8 лет назад +1

      Helped me, thank you very much! :)

    • @TheTwyker
      @TheTwyker 7 лет назад +1

      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.

  • @MangaPianet
    @MangaPianet 2 года назад

    Talk about A(*) programmers! Great video and great code, I love all your videos!

  • @FeuerfallFan
    @FeuerfallFan 8 лет назад +2

    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)

  • @MrDavidCollins
    @MrDavidCollins 3 года назад

    Just implemented this for my infinite world map! I love GMS2's new class/object programming

    • @kevinmolinari8953
      @kevinmolinari8953 11 месяцев назад

      what?... how? seriously, im lost how do u do it for an infinite map

  • @davidpike5959
    @davidpike5959 7 лет назад +86

    wow, copying this guy makes me feel clever :O

  • @MrCheliab
    @MrCheliab 9 лет назад +5

    Hello Sebastian.
    I have problem with your code in function NodeFromWorldPoint(). They get incorrect coodinates of node.
    This is my solution, if sobody have same problem:
    public Node NodeFromWorldPoint(Vector3 worldPosition)
    {
    // Move coordinates in right position
    float linearPosX = worldPosition.x - worldBottomLeft.x;
    float linearPosY = worldPosition.y - worldBottomLeft.y;
    // Get float value of positions in new coordinates
    float floatPosX = (linearPosX / nodeDiameter) - nodeRadius;
    float floatPosY = (linearPosY / nodeDiameter) - nodeRadius;
    int x = Mathf.RoundToInt(floatPosX);
    int y = Mathf.RoundToInt(floatPosY);
    x = Mathf.Clamp(x, 0, gridSizeX - 1);
    y = Mathf.Clamp(y, 0, gridSizeY - 1);
    return grid[x, y];
    }

  • @itsybitsypixel
    @itsybitsypixel 8 лет назад +6

    *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.

    • @Seanld98
      @Seanld98 5 лет назад

      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?

    • @smilos99
      @smilos99 5 лет назад +1

      @@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.

    • @Seanld98
      @Seanld98 5 лет назад

      @@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 :)

    • @MaskedImposter
      @MaskedImposter 5 лет назад +2

      @@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!

    • @darkopeninger1915
      @darkopeninger1915 5 лет назад

      Thanks
      PixelMannen! I had the same issue and your comment solved it.

  • @kureysalp
    @kureysalp 11 месяцев назад +1

    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.

  • @klevialushi571
    @klevialushi571 3 года назад +1

    its an old video but gotta love the fact that you got stockfish there

  • @DriitzzCabal
    @DriitzzCabal 6 лет назад

    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.

  • @trinketos
    @trinketos 9 лет назад +3

    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

    • @shezfroze7137
      @shezfroze7137 9 лет назад

      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.

    • @trinketos
      @trinketos 9 лет назад

      no, that's bad for me xD, maybe I have to ask to some "experts" in unity xD

    • @shezfroze7137
      @shezfroze7137 9 лет назад

      trinketos Ooo :|

    • @trinketos
      @trinketos 9 лет назад

      :D

    • @Mrpngu
      @Mrpngu 8 лет назад

      +trinketos You managed to get this part working?

  • @AA-vf4fv
    @AA-vf4fv 7 лет назад

    Thanks for the great Tutorial. It helped me very much.
    Also good explanation and easy to follow.

  • @dennischan2263
    @dennischan2263 6 лет назад

    excellent tutorial, thank you very much dude, you save my FYP and my life

  • @zhaoxuefei3829
    @zhaoxuefei3829 2 года назад

    omg, what a amazing video for a star, thank you very much

  • @catanator123654
    @catanator123654 8 лет назад +48

    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" 😑

    • @Villfuk02
      @Villfuk02 7 лет назад +18

      that's 40% of being programmer - fixing simple mistakes ¯\_(ツ)_/¯

    • @elektro36
      @elektro36 5 лет назад +7

      A CLASSIC

    • @chappie3642
      @chappie3642 4 года назад +7

      How did you not see that on the error log lmao

    • @alexanderrupp1209
      @alexanderrupp1209 4 года назад +1

      That’s a mood

    • @daksheshgupta7045
      @daksheshgupta7045 4 года назад

      get a linter

  • @videomasters2468
    @videomasters2468 9 лет назад +7

    if possible i would really like to see a tutorial/tutorial series on procedural level generation :)

    • @SebastianLague
      @SebastianLague  9 лет назад +10

      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..

    • @videomasters2468
      @videomasters2468 9 лет назад +1

      Sebastian Lague
      Yeah, either your suggested cave generation or some kind of race track, which would be of greater interest to you ?

    • @JoshD22
      @JoshD22 9 лет назад

      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.

    • @trevor7066
      @trevor7066 9 лет назад +1

      Sebastian Lague
      I think something along the lines of Terraria style map generation would be extremely useful.

    • @BrainRobo
      @BrainRobo 9 лет назад

      Sebastian Lague
      Also, if possible random planet generation, using spheres as the planet for space exploration, would be very intriguing.

  • @alexandergilbert7572
    @alexandergilbert7572 9 лет назад

    It might be a fun little project to get A* path finding to work on your spherical world.

  • @pedicagames3729
    @pedicagames3729 7 лет назад

    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()

  • @yuuryu2394
    @yuuryu2394 7 лет назад +1

    exactly what i was looking for, thanks a lot! :D

  • @jasperh6618
    @jasperh6618 9 лет назад +1

    I absolutely love this ^^ such a clear explanation :)

  • @3personal5me8
    @3personal5me8 3 года назад

    Me, about to go to bed because I work tomorrow: "Well, guess I'm watching this whole series first".

  • @Leniaal
    @Leniaal 8 лет назад +6

    For me it was mirrored
    My solution;
    float percentX = (worldPosition.x) / gridWorldSize.x;
    float percentY = (worldPosition.z) / gridWorldSize.y;
    percentX = Mathf.Clamp01(percentX);
    percentY = Mathf.Clamp01(percentY);
    int x = Mathf.RoundToInt((gridSizeX-1) * percentX);
    int y = Mathf.RoundToInt((gridSizeY-1) * percentY);
    return grid[x,y];

    • @luuk341
      @luuk341 8 лет назад

      +Leniaal you fixed my int to float problem, thank you!

    • @synvian8212
      @synvian8212 8 лет назад

      +Leniaal Cheers dude! This fixed a big problem I was having!!

    • @Leniaal
      @Leniaal 8 лет назад

      +Synvian Happy to help, happy coding!

    • @elianatora
      @elianatora 6 лет назад

      thanks brah you saved me some time

  • @EtherasFox
    @EtherasFox 8 лет назад

    Hi Sebastian,
    You might cover this in a later topic, if so I apologize. But I have a couple questions.
    1. How do you implement the Node Grid on a 3D world, such as a heightmap? Or any other non-flat world?
    2. How do you do A* on characters that cannot pass through eachother? For example, you have moving impassible nodes because they are other characters.
    Thanks!

  • @riteshrobotics9713
    @riteshrobotics9713 3 года назад

    A* Life Saver
    Was a really good video!

  • @nikhilbansode7274
    @nikhilbansode7274 7 лет назад +5

    What does following line means at 9:42 :
    Vector3 worldPoint = worldBottomLeft + Vector3.right * (x * nodeDiameter + nodeRadius) + Vector3.forward * (y * nodeDiameter + nodeRadius);

    • @Phagocytosis
      @Phagocytosis 2 года назад

      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.

  • @hobojoejr2
    @hobojoejr2 27 дней назад

    I know this video is old, but the code still works incase anyone was wondering.

  • @RetroEcoChicken
    @RetroEcoChicken 4 года назад

    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.

  • @S3fR0
    @S3fR0 8 лет назад +19

    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!

    • @Chubzdoomer
      @Chubzdoomer 7 лет назад +3

      Agreed. He doesn't explain each step thoroughly enough.

    • @HaroWorld1
      @HaroWorld1 7 лет назад +1

      I understood fine... :/

    • @nimrat9999
      @nimrat9999 6 лет назад +10

      Probably it's a good idea to go through a basic programming training first.

    • @viniciuslambardozzi4358
      @viniciuslambardozzi4358 6 лет назад +2

      His tutorials are not about programming, so you should learn a bit before and it will become more clear.

    • @maximiliantschuchnig154
      @maximiliantschuchnig154 6 лет назад +6

      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.

  • @AnujRam-f4e
    @AnujRam-f4e 3 дня назад

    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

  • @javiermurarios3960
    @javiermurarios3960 9 лет назад

    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.

  • @skelhain
    @skelhain 5 лет назад +1

    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?

    • @ArtrexSt
      @ArtrexSt 4 года назад

      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;

  • @Ans-wm5sp
    @Ans-wm5sp Год назад

    public Node NodeFromWorldPoint(Vector3 worldPosition) {
    int x = (int)(worldPosition.x+(gridWorldSize.x/2));
    int y = (int)(worldPosition.y+(gridWorldSize.y/2));
    return grid[x,y];
    }
    Changed NodeFromWorldPoint to this and it fixed a lot of bugs for me.

    • @Ans-wm5sp
      @Ans-wm5sp Год назад

      For clarification: I don't use spaces between nodes and my diameter is 1

  • @RetroEcoChicken
    @RetroEcoChicken 4 года назад

    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);
    }

    • @RetroEcoChicken
      @RetroEcoChicken 4 года назад

      then he deleates it in the end of the video. wow like getting my painting ripped from the refrigirator :(

  • @alexter-sarkisov8321
    @alexter-sarkisov8321 7 лет назад +2

    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!

  • @adrianopiro5240
    @adrianopiro5240 8 лет назад

    Pay attention with error Cannot implicitly convert type `Node[,]' to `Node'. I had this problem in this line...
    grid[x,y] = new Node[walkable, worldPoint]
    is not with brackets in new Node[ ], the correct is new Node( ) . Replace [ ] with ( )

  • @mohamedsalbi2759
    @mohamedsalbi2759 3 года назад

    Best channel ever

  • @aidansoles5113
    @aidansoles5113 9 лет назад

    You are a boss at debugging....

  • @Phagocytosis
    @Phagocytosis 2 года назад +1

    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.

    • @marcindathefierce
      @marcindathefierce 2 года назад +1

      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 🙂

    • @Phagocytosis
      @Phagocytosis 2 года назад +2

      @@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.

  • @sallycleverdoggo700
    @sallycleverdoggo700 2 года назад

    This is so good! Thank you!

  • @romainchow5706
    @romainchow5706 6 лет назад +2

    what does the Node[,] variable do in Grid? It's not working for me, do I have to attach the node script?

  • @batomow
    @batomow 7 лет назад +1

    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 :)

  • @michaelveloso
    @michaelveloso 9 лет назад +1

    good clear instructions. thanks

  • @JWY
    @JWY 5 лет назад

    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.

  • @mahmoueco1200
    @mahmoueco1200 4 года назад +2

    wow,just wow dude u r amazing where r u from !!! from land of genuis

  • @jdelaay025
    @jdelaay025 8 лет назад +1

    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

  • @ThePistolWhippets
    @ThePistolWhippets 8 лет назад

    Great tutorial - many thanks

  • @MoloSolo
    @MoloSolo 8 лет назад

    Congratulations, I'm really enjoying your tutorials!
    Just one question. Don't you think it could be better to define variables "worldPoint" and "walkable" (lines 27 and 28) outside of the "for" instructions and assign the new value inside?
    I think it's faster to define these variables just one time instead of creating and destructing them in each loop.
    What do you think?

  • @Erik_Nivala
    @Erik_Nivala 7 лет назад +1

    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.

  • @jessenance8889
    @jessenance8889 4 года назад

    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.

    • @bronze2181
      @bronze2181 4 года назад

      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.

  • @pablokalemba2924
    @pablokalemba2924 5 лет назад

    Thanks !! you saved my proyect

  • @azrailnone
    @azrailnone 3 года назад +1

    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.

  • @CubeFlow_46
    @CubeFlow_46 Год назад

    is anyone else having issues with player node and n both being null when checking if the playernode and n are equal inside of the OnDrawGizmos method? I can't figure out my issue, i have the same code as sebastian and nothing was going wrong before this. inside the NodeFromWorldPoint method, x and y are being updated correctly, but playernode is always null. help?

  • @devlog98
    @devlog98 6 лет назад

    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!

  • @MrJiraiyah
    @MrJiraiyah 9 лет назад +1

    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

    • @nyforandring
      @nyforandring 8 лет назад

      +Alireza Khodakarami Did you get your idea working? I'm trying to do something similar. Please do help me out

    • @MrJiraiyah
      @MrJiraiyah 8 лет назад

      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?

  • @badrballish9328
    @badrballish9328 3 года назад

    Great tutorial thank you very much.

  • @chrisgengr
    @chrisgengr 9 лет назад +1

    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!

    • @PvPNetwork
      @PvPNetwork 5 лет назад +2

      Phyiscs2D.OverlapCircle works. 3 years late answer, but maybe someone else in the future will find it useful.

    • @gustavoguaresi8698
      @gustavoguaresi8698 3 года назад +1

      @@PvPNetwork yeah, thanks. 2 years late, but still... haha

  • @Robsfund
    @Robsfund 8 лет назад +1

    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?

  • @sauliusvincevicius8688
    @sauliusvincevicius8688 5 лет назад +1

    I did 2d(Vector2D) and the NodeFromWorldPoint was showing wrong at somewhere 70% so I did this...
    public Node GetNodeFromWorldPoint(Vector2 worldPosition)
    {
    float percentX = (worldPosition.x + gridWorldSize.x / 2) / gridWorldSize.x;
    float percentY = (worldPosition.y + gridWorldSize.y / 2) / gridWorldSize.y;
    int x = Mathf.RoundToInt((gridSizeX) * percentX);
    int y = Mathf.RoundToInt((gridSizeY) * percentY);
    return grid[x, y];
    }
    works for me.....

    • @christopherrowe7860
      @christopherrowe7860 3 года назад +1

      thank you, sir that was what I was looking for

    • @dead2gamer
      @dead2gamer Год назад

      Hey! I'm trying to implement in 2D as well but for some reason it doesn't do unwalkable areas for me. All my layer masks are set and properly assigned

  • @Krebzonide
    @Krebzonide 6 лет назад +2

    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.

  • @SheepCounting
    @SheepCounting 3 года назад

    I'm trying to understand the layermask part of the Physics.CheckSphere. If I create a new layer called walkable, and i give it to my plane, I would have expected this to work the same way if i were to change the Physics checksphere to (Physics.CheckSphere(worldPoint, nodeRadius, walkableMask). When i do this though, i can walk everywhere. I thought maybe it was the type of colider so i changed my plane to a cube and stretched it out the same size at the plane and this didn't work either.

  • @Ben274722
    @Ben274722 8 лет назад

    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.

  • @alisontaylor4589
    @alisontaylor4589 8 лет назад +1

    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.

  • @amanmahendroo1784
    @amanmahendroo1784 4 года назад

    Awesome videos! But could you please increase the font size of your code? That would be great

  • @MrRemorc
    @MrRemorc 7 лет назад +4

    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.

    • @GrashalmTuts
      @GrashalmTuts 7 лет назад

      MrRemorc same problem here

    • @thejaker1O
      @thejaker1O 7 лет назад +1

      I had the same problem and it was being caused by a missing decimal point so triple check your code!

    • @Ryanks12
      @Ryanks12 7 лет назад

      I'm also having this problem - can't see any of my grid!

    • @RealTheMarco
      @RealTheMarco 7 лет назад +1

      If somebody has the same problem : you certainly don't have active Gizmos in your Scene view. Check on Google.

    • @Ratstail91
      @Ratstail91 6 лет назад

      Thank you!

  • @evachocolat2012
    @evachocolat2012 2 года назад

    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

    • @MolnarSPeter
      @MolnarSPeter Год назад

      Did you find a solution? I'm sturggling with this too

  • @o.429
    @o.429 5 лет назад +1

    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.

    • @r1pfake521
      @r1pfake521 4 года назад

      I think both versions will work and return the correct value or not? Im too sleepy to think more about it for now

    • @o.429
      @o.429 3 года назад

      @@r1pfake521 Same math but I tried to make it look more simple.

  • @nunobartolo2908
    @nunobartolo2908 3 года назад

    Bit* is what you should be learning

  • @DerXavia
    @DerXavia 7 лет назад

    I wonder why you use the sphere check instead of a boxcheck, isn't that more efficient?

  • @annaleonid6095
    @annaleonid6095 8 лет назад +2

    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!

    • @annaleonid6095
      @annaleonid6095 8 лет назад +1

      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.

    • @_graiderz2462
      @_graiderz2462 8 лет назад +4

      +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.

    • @annaleonid6095
      @annaleonid6095 8 лет назад

      +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.

    • @_graiderz2462
      @_graiderz2462 8 лет назад

      +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.

    • @IFrozenFireI
      @IFrozenFireI 8 лет назад

      "dynamic pathfinding"? Dude, for it to be "dynamic", you should just call the appropriate code in an update function.

  • @yagohenriquepereira3367
    @yagohenriquepereira3367 8 лет назад

    amazing tutorial! Thanks