/* * ==== DESCRIPTION ==== * * A Navigator instance is used by any object that wishes to use pathfinding. * The Navigator acts as a mediator between Tilemaps in a scene and pathfinding algorithms, * and makes extensive use of algorithms in the static MapConverter class to perform conversions. * * The Navigator is used by calling "GetWorldPath". * This provides a suggested path, each entry being a NodeGrid node's world coordinates. * Objects trying to navigate should pass in their current location and their destination, * then attempt to *directly* move to each node in turn (likely moving on to the next node * once arriving within a certain distance of the current node). * Calls should be made roughly every time an object's target destination changes. * This may be very often if chasing a moving object, so effort should be made to limit calls. * * The Navigator is handy because its inputs and outputs are world coordinates, so objects * have an easy time communicating with it. * * The Navigator also generates and stores all important pathfinding data (PathMaps and their contents), * so that each object/actor using pathfinding does not need its own copy, which saves memory. * */ /// <summary> /// Get a world location to walk towards, in order to reach the desired destination. /// </summary> /// <param name="pointA">Entity's current world location.</param></param> /// <param name="PointB">World location of final destination.</param> public Vector3[] GetWorldPath(BlockingType bType, Vector3 pointA, Vector3 pointB) { PathMap pMap = pathMapDict[bType]; Vector3Int pA_vec = MapConverter.WorldToNode(pMap, pointA); Vector3Int pB_vec = MapConverter.WorldToNode(pMap, pointB); Point pA = new Point(pA_vec.x, pA_vec.y); Point pB = new Point(pB_vec.x, pB_vec.y); List <Point> pointList = Pathfinder.FindPath(pMap.nodeGrid, pA, pB); Vector3[] coordsList = new Vector3[pointList.Count]; int i = 0; pointList.ForEach(delegate(Point p){ coordsList[i++] = MapConverter.NodeToWorld(pMap, p.x, p.y); }); return(coordsList); }
public static Vector3Int TileToNode(PathMap pathMap, int x, int y) { return(new Vector3Int(x - pathMap.bounds.xMin, y - pathMap.bounds.yMin, 0)); }
//based on bounds information, and matrix position, returns the TileMap location of a matrix tile //might not ever be used except when getting world coordinates, as in "NodeToWorld" public static Vector3Int NodeToTile(PathMap pathMap, int i, int j) { return(new Vector3Int(pathMap.bounds.xMin + i, pathMap.bounds.yMin + j, 0)); }
//converts a group of tilemaps into a matrix of booleans, for use with 2D pathfinding. //final matrix size is determined by tilemaps' bounds. Needs to expand to include all maps' tiles. //tilemaps are "flattened" into one; each boolean matrix is logically AND'd together: //Cells with tiles are not walkable, and convert to false. Cells without tiles convert to true. public static PathMap TilemapArrToPathMap(Tilemap[] maps, BoundsInt outerBounds) { if (maps == null || maps.Length == 0) { Debug.Log("Error: Navigator was given invalid references. Add maps to it in the Inspector."); return(new PathMap()); //TODO: make this return a completely walkable map } //outerBounds should be big enough to overlay EVERY tilemap, including the background BoundsInt[] bounds = new BoundsInt[maps.Length]; for (int m = 0; m < maps.Length; m++) { bounds[m] = maps[m].cellBounds; if (bounds[m].xMin < outerBounds.xMin) { outerBounds.xMin = bounds[m].xMin; } if (bounds[m].xMax > outerBounds.xMax) { outerBounds.xMax = bounds[m].xMax; } if (bounds[m].yMin < outerBounds.yMin) { outerBounds.yMin = bounds[m].yMin; } if (bounds[m].yMax > outerBounds.yMax) { outerBounds.yMax = bounds[m].yMax; } } int i, j; //preallocate matrix indices; x/y are for map coords, i/j for matrix indices ("nodes") //create bool matrix of proper size bool[,] boolMat = new bool[outerBounds.size.x, outerBounds.size.y]; for (i = 0; i < outerBounds.size.x; i++) { for (j = 0; j < outerBounds.size.y; j++) { boolMat[i, j] = true; //nodes are walkable (true) by default } } //for each map: for (int m = 0; m < maps.Length; m++) { //loop through positions, starting at bottom left x/y in map //NOTE: MAX BOUNDS ARE EXCLUSIVE for (int x = bounds[m].xMin; x < bounds[m].xMax; x++) { for (int y = bounds[m].yMin; y < bounds[m].yMax; y++) { //convert tilemap x/y into node i/j i = x - outerBounds.xMin; j = y - outerBounds.yMin; //set matrix bool value: null => true, else false. //each map is added together: if ANY map has a tile in a location, that node is false (ie not walkable) boolMat[i, j] = (boolMat[i, j] && (maps[m].GetTile(new Vector3Int(x, y, 0)) == null)); } //y loop } //x loop } //m loop //return results PathMap pathMap = new PathMap(); pathMap.referenceTilemap = maps[0]; //all tilemaps passed in should share a parent grid layout pathMap.bounds = outerBounds; pathMap.nodeGrid = new NodeGrid(outerBounds.size.x, outerBounds.size.y, boolMat); return(pathMap); }
public static Vector3Int WorldToNode(PathMap pathMap, Vector3 pos) { Vector3Int point = pathMap.referenceTilemap.WorldToCell(pos); return(TileToNode(pathMap, point.x, point.y)); }
//finds the world coordinates of a given node. very important public static Vector3 NodeToWorld(PathMap pathMap, int i, int j) { return(pathMap.referenceTilemap.GetCellCenterWorld(NodeToTile(pathMap, i, j))); }