Navigation in a Procedurally Generated World | Unity NavMesh Surface and NavMesh Agent Explained

แชร์
ฝัง
  • เผยแพร่เมื่อ 28 พ.ย. 2024

ความคิดเห็น • 20

  • @jellybean4049
    @jellybean4049 10 หลายเดือนก่อน +4

    The Nav in Unity used to be such a pain, I'm happy they're still updating it. Thanks, I didn't know the extent.

    • @KetraGames
      @KetraGames  9 หลายเดือนก่อน +3

      👍😊

  • @midniteoilsoftware
    @midniteoilsoftware ปีที่แล้ว +3

    This looks like a good approach for a rogue-like

  • @bigbothoee8617
    @bigbothoee8617 ปีที่แล้ว +3

    How have u not got more views simple easy to follow instructions

    • @equiaux
      @equiaux ปีที่แล้ว

      The YT algorithm

  • @Kejody53
    @Kejody53 7 หลายเดือนก่อน +2

    wow thanks so much, straight to the point and well explained!

    • @KetraGames
      @KetraGames  7 หลายเดือนก่อน +1

      Thanks very much for this comment 😊

  • @dreamcatforgotten8435
    @dreamcatforgotten8435 ปีที่แล้ว +1

    Thank you very much for another outstanding video Ketra Games!
    One thing I noticed is that you are using LTS version 2022.3.4f1
    I vaguely recall that there was a bug with the UI Canvas in versions 2022.3.3f1 and 2022.3.4f1, so you may want to upgrade to 5f1 or higher when you can, since the bug should be fixed by then.

  • @notakk
    @notakk 5 หลายเดือนก่อน

    Excellent video, I really liked it, but missing an opening to the end of the maze, how would I do that?

  • @hawkeyejal2426
    @hawkeyejal2426 ปีที่แล้ว +1

    Could you make a tutorial that has the player start at a randomly generated start point (preferably as far away from the exist as possible) or the ability to put a predetermined spawnpoint as well as a randomly generated end point like at the end of the maze generatation spawn a door or chest or such?

  • @GemTappX
    @GemTappX 9 หลายเดือนก่อน

    I searched online and it seems this is one of the most recent pieces of content about the Nav Mesh in Unity. It seems not too many people are discussing the Nav Mesh these days. Tutorials less then a year back seem outdated. It’s hard to find Nav Mesh content and I have so many questions.

  • @moviedudes5387
    @moviedudes5387 11 หลายเดือนก่อน

    Please make a video on moving platform with navmesh surface.

  • @cvg1399
    @cvg1399 10 หลายเดือนก่อน

    hi can we do it in unreal with blueprint ?

  • @fesr9974
    @fesr9974 ปีที่แล้ว

    Top down tutorial!!!!

  • @alextravine9422
    @alextravine9422 2 วันที่ผ่านมา

    Ive tried to watch your videos many times, but can not do it. Adhd attention span makes it difficult. Oh wel

    • @KetraGames
      @KetraGames  7 ชั่วโมงที่ผ่านมา

      Sorry to hear this 😢

  • @EllenJoyChannel
    @EllenJoyChannel 5 หลายเดือนก่อน

    if you are explaining NavMesh why are you confusing others with scaling issues and maze generating stuff! i just dont get it!

    • @KetraGames
      @KetraGames  5 หลายเดือนก่อน +1

      Sorry for the confusion. This is part of a series on procedural generation and continues from the previous video where the maze was generated

  • @dprazo
    @dprazo 3 หลายเดือนก่อน +1

    Hi, there, I'm currently building my own maze with my own setup, for starters my own maze has the floor inside the mazecellprefab so It spawns the floor for each mazecell, you have a seperate 'floor' gameobject. While I have my floor game object within the mazecellprefab, I tried adding the navmeshsurface to the floor prefab in my mazecellprefab hoping the navmesh will automatically just creat itself as the maze spawns, but that doesn't work. Please could anyone help me? @ketragames

    • @dprazo
      @dprazo 3 หลายเดือนก่อน +1

      This is my own MazeGenerator script:
      using System;
      using System.Collections.Generic;
      using Unity.AI.Navigation;
      using UnityEngine;
      using Random = UnityEngine.Random;
      public class MazeGenerator : MonoBehaviour {
      [Range(5, 500)] // 500, The higher the number the longer the maze will generate
      public int mazeWidth = 5, mazeHeight = 5; // The dimensions of the maze
      public int startX, startY; // The position our algorithm will start from.
      MazeCell[,] maze; // An array of maze cells representing the maze grid
      Vector2Int currentCell; // The maze cell we are currently looking at
      public MazeCell[,] GetMaze()
      {
      // Logic for generating the maze
      GenerateMaze();
      GetComponent().BuildNavMesh();
      return maze;
      }
      void GenerateMaze()
      {
      maze = new MazeCell[mazeWidth, mazeHeight];
      for (int x = 0; x < mazeWidth; x++)
      {
      for (int y = 0; y < mazeHeight; y++)
      {
      maze[x, y] = new MazeCell(x, y);
      }
      }
      // Start carving our maze path
      CarvePath(startX, startY);
      // Log a message when the maze generation is complete
      Debug.Log("Maze Generation Completed!");
      }
      List directions = new List {
      Direction.Up, Direction.Down, Direction.Left, Direction.Right,

      };
      List GetRandomDirections() {
      // Make a copy of our directions list that we can mess around with
      List dir = new List(directions);
      // Make a directions list to put our randomised directions into
      List rndDir = new List();
      while (dir.Count > 0) {
      int rnd = Random.Range(0, dir.Count); // Get random index in list
      rndDir.Add(dir[rnd]); // Add the random direction to our list
      dir.RemoveAt(rnd); // Remove that direction so we can't choose it again
      }
      // When we've got all four directions in a random order, return the queue
      return rndDir;
      }
      bool IsCellValid (int x, int y) {

      // If the cell is outside of the map or has already been visited, we consider it not valid
      if (x < 0 || y < 0 || x > mazeWidth - 1 || y > mazeHeight - 1 || maze[x, y].visited) return false;
      else return true;
      }
      Vector2Int CheckNeighbours () {

      List rndDir = GetRandomDirections();
      for (int i = 0; i < rndDir.Count; i++) {

      // Set neighbour coordinates to current cell for now
      Vector2Int neighbour = currentCell;
      switch (rndDir[i]) {
      case Direction.Up:
      neighbour.y++;
      break;
      case Direction.Down:
      neighbour.y--;
      break;
      case Direction.Right:
      neighbour.x++;
      break;
      case Direction.Left:
      neighbour.x--;
      break;
      }
      // if the neighbour we just tried is valid, we can return that neighbour. If not, we go again
      if (IsCellValid(neighbour.x, neighbour.y)) return neighbour;

      }
      // we tried all directions and didn't fina a valid neighbour, we return the currentCell values
      return currentCell;
      }
      void BreakWalls ( Vector2Int primaryCell, Vector2Int secondaryCell) {
      // We can only go in one direction at a time so we can handle this using if else statements
      if (primaryCell.x > secondaryCell.x) { // Primary Cell is Left Wall

      maze[primaryCell.x, primaryCell.y].leftWall = false;

      } else if (primaryCell.x < secondaryCell.x) { // Secondary Cell is Left Wall

      maze[secondaryCell.x, secondaryCell.y].leftWall = false;

      } else if (primaryCell.y < secondaryCell.y) { // Primary Cell is Top Wall

      maze[primaryCell.x, primaryCell.y].topWall = false;

      } else if (primaryCell.y > secondaryCell.y) { // Secondary Cell is Top Wall

      maze[secondaryCell.x, secondaryCell.y].topWall = false;

      }
      }
      // Starting at the x, y passed in, carves a path through the maze until it encounters a "dead end"
      // ( A dead end is a cell with no valid neighbours)
      void CarvePath (int x, int y) {
      // Perform a quick check to make sure our start position is within the boundaries of the map
      // if not, set them to a default (I'm using 0) and throw a little warning up.
      if (x < 0 || y < 0 || x > mazeWidth - 1 || y > mazeHeight - 1) {
      x = y = 0;
      Debug.LogWarning("Starting position is out of bounds, defaulting to 0, 0");
      }
      // Set current cell to the starting position we were passed
      currentCell = new Vector2Int(x, y);
      // A list to keep track of our current path
      List path = new List();
      // Loop until we encounter a dead end
      bool deadEnd = false;
      while (!deadEnd) {

      // Get the next cell we're going to try
      Vector2Int nextCell = CheckNeighbours();
      // If that cell has no valid neighbhours, set deadend to true so we break out of the loop
      if (nextCell == currentCell) {

      // If that cell has no valid neighbours, set deadend to true so we break out of the loop
      for (int i = path.Count - 1; i >= 0; i--) {

      currentCell = path[i]; // Set currentCell to the next step back along our path
      path.RemoveAt(i); // Remove this step from the path
      nextCell = CheckNeighbours(); // Check that cell to see if any other neighbouts are valid
      // If we find a valid neighbour, break out of the loop
      if (nextCell != currentCell) break;
      }
      if (nextCell == currentCell)
      deadEnd = true;

      } else {

      BreakWalls(currentCell, nextCell); // Set wall flags on these two cells
      maze[currentCell.x, currentCell.y].visited = true; // Set cell to visited before moving on
      currentCell = nextCell; // Set current cell to the valid neighbour we fond
      path.Add(currentCell); // Add this cell to our path
      }
      }
      }
      }
      public enum Direction {
      Up,
      Down,
      Left,
      Right
      }
      public class MazeCell {
      public bool visited;
      public int x, y;
      public bool topWall;
      public bool leftWall;
      // Return x and y as a Vector2Int for convenience sake
      public Vector2Int position {
      get {
      return new Vector2Int(x, y);

      }
      }
      public MazeCell (int x, int y) {
      // The coordinates of this cell in the maze grid
      this.x = x;
      this.y = y;
      // Whethere the algorithm has visited this cell or not - false to start
      visited = false;
      // All walls are present until the algorirthm removes them
      topWall = leftWall = true;
      }
      }