public override TiledNavMesh Deserialize(string path) { JObject root = JObject.Parse(File.ReadAllText(path)); if (root["meta"]["version"]["snj"].ToObject <int>() != FormatVersion) { throw new ArgumentException("The version of the file does not match the version of the parser. Consider using an older version of SharpNav or re-generating your .snj meshes."); } Vector3 origin = root["origin"].ToObject <Vector3>(serializer); float tileWidth = root["tileWidth"].ToObject <float>(serializer); float tileHeight = root["tileHeight"].ToObject <float>(serializer); int maxTiles = root["maxTiles"].ToObject <int>(serializer); int maxPolys = root["maxPolys"].ToObject <int>(serializer); var mesh = new TiledNavMesh(origin, tileWidth, tileHeight, maxTiles, maxPolys); JArray tilesToken = (JArray)root["tiles"]; List <NavTile> tiles = new List <NavTile>(); foreach (JToken tileToken in tilesToken) { NavPolyId tileRef; NavTile tile = DeserializeMeshTile(tileToken, mesh.IdManager, out tileRef); mesh.AddTileAt(tile, tileRef); } return(mesh); }
public void AddTileAt(NavTile tile, NavPolyId id) { if (!idManager.HasSameConfigAs(tile.IdManager)) { throw new ArgumentException("Added tile has a different id manager. This likely means it came from another nav mesh"); } //TODO more error checking, what if tile already exists? Vector2i loc = tile.Location; List <NavTile> locList; if (!tileSet.TryGetValue(loc, out locList)) { locList = new List <NavTile>(); locList.Add(tile); tileSet.Add(loc, locList); } else { locList.Add(tile); } tileRefs.Add(tile, id); int index = idManager.DecodeTileIndex(ref id); tileIndices.Add(index, tile); ++totalSpawnedTiles; }
private JObject SerializeMeshTile(NavTile tile, NavPolyId id) { var result = new JObject(); result.Add("polyId", JToken.FromObject(id, serializer)); result.Add("location", JToken.FromObject(tile.Location, serializer)); result.Add("layer", JToken.FromObject(tile.Layer, serializer)); result.Add("salt", JToken.FromObject(tile.Salt, serializer)); result.Add("bounds", JToken.FromObject(tile.Bounds, serializer)); result.Add("polys", JToken.FromObject(tile.Polys, serializer)); result.Add("verts", JToken.FromObject(tile.Verts, serializer)); result.Add("detailMeshes", JToken.FromObject(tile.DetailMeshes, serializer)); result.Add("detailVerts", JToken.FromObject(tile.DetailVerts, serializer)); result.Add("detailTris", JToken.FromObject(tile.DetailTris, serializer)); result.Add("offMeshConnections", JToken.FromObject(tile.OffMeshConnections, serializer)); JObject treeObject = new JObject(); JArray treeNodes = new JArray(); for (int i = 0; i < tile.BVTree.Count; i++) { treeNodes.Add(JToken.FromObject(tile.BVTree[i], serializer)); } treeObject.Add("nodes", treeNodes); result.Add("bvTree", treeObject); result.Add("bvQuantFactor", JToken.FromObject(tile.BvQuantFactor, serializer)); result.Add("bvNodeCount", JToken.FromObject(tile.BvNodeCount, serializer)); result.Add("walkableClimb", JToken.FromObject(tile.WalkableClimb, serializer)); return(result); }
private NavTile DeserializeMeshTile(JToken token, NavPolyIdManager manager, out NavPolyId refId) { refId = token["polyId"].ToObject <NavPolyId>(serializer); Vector2i location = token["location"].ToObject <Vector2i>(serializer); int layer = token["layer"].ToObject <int>(serializer); NavTile result = new NavTile(location, layer, manager, refId); result.Salt = token["salt"].ToObject <int>(serializer); result.Bounds = token["bounds"].ToObject <BBox3>(serializer); result.Polys = token["polys"].ToObject <NavPoly[]>(serializer); result.PolyCount = result.Polys.Length; result.Verts = token["verts"].ToObject <Vector3[]>(serializer); result.DetailMeshes = token["detailMeshes"].ToObject <PolyMeshDetail.MeshData[]>(serializer); result.DetailVerts = token["detailVerts"].ToObject <Vector3[]>(serializer); result.DetailTris = token["detailTris"].ToObject <PolyMeshDetail.TriangleData[]>(serializer); result.OffMeshConnections = token["offMeshConnections"].ToObject <OffMeshConnection[]>(serializer); result.OffMeshConnectionCount = result.OffMeshConnections.Length; result.BvNodeCount = token["bvNodeCount"].ToObject <int>(serializer); result.BvQuantFactor = token["bvQuantFactor"].ToObject <float>(serializer); result.WalkableClimb = token["walkableClimb"].ToObject <float>(serializer); var treeObject = (JObject)token["bvTree"]; var nodes = treeObject.GetValue("nodes").ToObject <BVTree.Node[]>(); result.BVTree = new BVTree(nodes); return(result); }
public void AddTileAt(NavTile tile, NavPolyId id) { //TODO more error checking, what if tile already exists? Vector2i loc = tile.Location; List <NavTile> locList; if (!tileSet.TryGetValue(loc, out locList)) { locList = new List <NavTile>(); locList.Add(tile); tileSet.Add(loc, locList); } else { locList.Add(tile); } tileRefs.Add(tile, id); int index = idManager.DecodeTileIndex(ref id); //HACK this is pretty bad but only way to insert at index //TODO tileIndex should have a level of indirection from the list? while (index >= tileList.Count) { tileList.Add(null); } tileList[index] = tile; }
private void UnconnectLinks(NavTile tile, NavTile target) { if (tile == null || target == null) { return; } foreach (NavPoly poly in tile.Polys) { for (int n = 0; n < poly.Links.Count; ++n) { Link link = poly.Links[n]; NavTile linkTile; NavPoly linkPoly; TryGetTileAndPolyByRefUnsafe(link.Reference, out linkTile, out linkPoly); if (linkTile == target) { poly.Links.RemoveAt(n); --n; } } } }
// Use this for initialization public List <Node> FindPath(GameObject obj1, GameObject obj2) { //Preload values mapHeight = backgroundContainer.transform.childCount; mapWidth = backgroundContainer.transform.GetChild(0).childCount; //Parse the map nodeMap = new Node[mapWidth, mapHeight]; Node start = null; Node goal = null; for (int y = 0; y < mapHeight; y++) { Transform backgroundRow = backgroundContainer.transform.GetChild(y); for (int x = 0; x < mapWidth; x++) { NavTile tile = backgroundRow.GetChild(x).GetComponent <NavTile>(); Node node = new Node(x, y); node.value = tile; nodeMap[x, y] = node; } } start = FindNode(obj1); goal = FindNode(obj2); //Execute AStar algorithm List <Node> nodePath = ExecuteAStar(start, goal); nodePath.Reverse(); return(nodePath); }
public virtual float GetCost(Vector3 a, Vector3 b, NavPolyId prevRef, NavTile prevTile, NavPoly prevPoly, NavPolyId curRef, NavTile curTile, NavPoly curPoly, NavPolyId nextRef, NavTile nextTile, NavPoly nextPoly) { return (a - b).Length() * areaCost[(int)curPoly.Area.Id]; }
//find the node the obj is on private Node FindNode(GameObject obj) { Collider2D[] collidingObjects = Physics2D.OverlapCircleAll(obj.transform.position, 0.2f); foreach (Collider2D collidingObject in collidingObjects) { if (collidingObject.gameObject.GetComponent <NavTile>() != null) { //tile obj is on NavTile tile = collidingObject.gameObject.GetComponent <NavTile>(); //find node that contains the tile for (int y = 0; y < mapHeight; y++) { for (int x = 0; x < mapWidth; x++) { Node node = nodeMap[x, y]; if (node.value == tile) { return(node); } } } } } return(null); }
/// <summary> /// Only use this function if it is known that the provided polygon reference is valid. /// </summary> /// <param name="reference">Polygon reference</param> /// <param name="tile">Resulting tile</param> /// <param name="poly">Resulting poly</param> public void TryGetTileAndPolyByRefUnsafe(NavPolyId reference, out NavTile tile, out NavPoly poly) { int salt, polyIndex, tileIndex; idManager.Decode(ref reference, out polyIndex, out tileIndex, out salt); tile = tileIndices[tileIndex]; poly = tileIndices[tileIndex].Polys[polyIndex]; }
public static TileBase DefaultTile(Sprite sprite) { NavTile tile = CreateDefaultNavTile(); tile.name = sprite.name; tile.sprite = sprite; tile.color = Color.white; return(tile); }
public void SelectMovementDestination(NavTile goal) { Physics.Raycast(transform.position + Vector3.up * 0.001f, Vector3.down, out RaycastHit startHitInfo, float.MaxValue, LayerMask.GetMask("NavGrid")); NavTile start = startHitInfo.collider.GetComponent <NavTile>(); List <NavTile> pathTiles = FindObjectOfType <NavGrid>().FindPath(start, goal); if (pathTiles != null && pathTiles[pathTiles.Count - 1] != start) { StartCoroutine(Animate(pathTiles)); } }
/// <summary> /// Retrieve the endpoints of the offmesh connection at the specified polygon /// </summary> /// <param name="prevRef">The previous polygon reference</param> /// <param name="polyRef">The current polygon reference</param> /// <param name="startPos">The starting position</param> /// <param name="endPos">The ending position</param> /// <returns>True if endpoints found, false if not</returns> public bool GetOffMeshConnectionPolyEndPoints(NavPolyId prevRef, NavPolyId polyRef, ref Vector3 startPos, ref Vector3 endPos) { int salt = 0, indexTile = 0, indexPoly = 0; if (polyRef == NavPolyId.Null) { return(false); } //get current polygon idManager.Decode(ref polyRef, out indexPoly, out indexTile, out salt); if (indexTile >= maxTiles) { return(false); } if (tileList[indexTile].Salt != salt) { return(false); } NavTile tile = tileList[indexTile]; if (indexPoly >= tile.PolyCount) { return(false); } NavPoly poly = tile.Polys[indexPoly]; if (poly.PolyType != NavPolyType.OffMeshConnection) { return(false); } int idx0 = 0, idx1 = 1; //find the link that points to the first vertex foreach (Link link in poly.Links) { if (link.Edge == 0) { if (link.Reference != prevRef) { idx0 = 1; idx1 = 0; } break; } } startPos = tile.Verts[poly.Verts[idx0]]; endPos = tile.Verts[poly.Verts[idx1]]; return(true); }
public NavTilemap(BoundsInt bounds) { navBounds = bounds; tiles = new NavTile[bounds.size.x, bounds.size.y]; for (int x = 0; x < tiles.GetLength(0); x++) { for (int y = 0; y < tiles.GetLength(1); y++) { tiles[x, y] = new NavTile(new Vector3Int(x, y, 0)); } } }
public List <NavTile> FindNodesInRange(NavTile startNode, float range) { HashSet <NavTile> closedSet = new HashSet <NavTile>(); HashSet <NavTile> openSet = new HashSet <NavTile>() { startNode }; Dictionary <NavTile, float> gCost = new Dictionary <NavTile, float> { [startNode] = 0 }; while (openSet.Count > 0) { NavTile current = openSet.OrderBy(n => gCost[n]).First(); if (gCost[current] > range) { return(new List <NavTile>(closedSet)); } openSet.Remove(current); closedSet.Add(current); foreach (NavTile.Edge edge in current.Edges) { NavTile neighbor = edge.tile; float edgeWeight = edge.weight; if (closedSet.Contains(neighbor)) { continue; } float gCostTemp = gCost[current] + edgeWeight; if (!openSet.Contains(neighbor)) { openSet.Add(neighbor); } else if (gCostTemp >= gCost[neighbor]) { continue; } gCost[neighbor] = gCostTemp; } } return(new List <NavTile>(closedSet)); }
/// <summary> /// Get the tile reference /// </summary> /// <param name="tile">Tile to look for</param> /// <returns>Tile reference</returns> public NavPolyId GetTileRef(NavTile tile) { if (tile == null) { return(NavPolyId.Null); } NavPolyId id; if (!tileRefs.TryGetValue(tile, out id)) { id = NavPolyId.Null; } return(id); }
private List <NavTile> ReconstructPath(Dictionary <NavTile, NavTile> cameFrom, NavTile goal) { List <NavTile> path = new List <NavTile>(); NavTile current = goal; path.Add(current); while (cameFrom.ContainsKey(current)) { current = cameFrom[current]; path.Add(current); } path.Reverse(); return(path); }
/// <summary> /// Retrieve the tile and poly based off of a polygon reference /// </summary> /// <param name="reference">Polygon reference</param> /// <param name="tile">Resulting tile</param> /// <param name="poly">Resulting poly</param> /// <returns>True if tile and poly successfully retrieved</returns> public bool TryGetTileAndPolyByRef(NavPolyId reference, out NavTile tile, out NavPoly poly) { tile = null; poly = null; if (reference == NavPolyId.Null) { return(false); } //Get tile and poly indices int salt, polyIndex, tileIndex; idManager.Decode(ref reference, out polyIndex, out tileIndex, out salt); //Make sure indices are valid if (tileIndex >= maxTiles) { return(false); } NavTile foundTile; if (!tileIndices.TryGetValue(tileIndex, out foundTile)) { return(false); } if (foundTile.Salt != salt) { return(false); } if (polyIndex >= foundTile.PolyCount) { return(false); } //Retrieve tile and poly tile = tileIndices[tileIndex]; poly = tileIndices[tileIndex].Polys[polyIndex]; return(true); }
public bool RemoveTile(NavTile tile) { List <NavTile> tiles; if (tileSet.TryGetValue(tile.Location, out tiles)) { tiles.Remove(tile); } else { return(false); } foreach (NavTile neighbourTile in GetTilesAt(tile.Location)) { if (tile != neighbourTile) { UnconnectLinks(neighbourTile, tile); } } for (int n = 0; n < 8; ++n) { foreach (NavTile neighbourTile in GetNeighborTilesAt(tile.Location, (BoundarySide)n)) { UnconnectLinks(neighbourTile, tile); } } NavPolyId id = tileRefs[tile]; int index = idManager.DecodeTileIndex(ref id); tileIndices.Remove(index); tileRefs.Remove(tile); return(true); }
private JObject SerializeMeshTile(NavTile tile, NavPolyId id) { var result = new JObject(); result.Add("polyId", JToken.FromObject(id, serializer)); result.Add("location", JToken.FromObject(tile.Location, serializer)); result.Add("layer", JToken.FromObject(tile.Layer, serializer)); result.Add("salt", JToken.FromObject(tile.Salt, serializer)); result.Add("bounds", JToken.FromObject(tile.Bounds, serializer)); result.Add("polys", JToken.FromObject(tile.Polys, serializer)); result.Add("verts", JToken.FromObject(tile.Verts, serializer)); result.Add("detailMeshes", JToken.FromObject(tile.DetailMeshes, serializer)); result.Add("detailVerts", JToken.FromObject(tile.DetailVerts, serializer)); result.Add("detailTris", JToken.FromObject(tile.DetailTris, serializer)); result.Add("offMeshConnections", JToken.FromObject(tile.OffMeshConnections, serializer)); JObject treeObject = new JObject(); JArray treeNodes = new JArray(); for (int i = 0; i < tile.BVTree.Count; i++) treeNodes.Add(JToken.FromObject(tile.BVTree[i], serializer)); treeObject.Add("nodes", treeNodes); result.Add("bvTree", treeObject); result.Add("bvQuantFactor", JToken.FromObject(tile.BvQuantFactor, serializer)); result.Add("bvNodeCount", JToken.FromObject(tile.BvNodeCount, serializer)); result.Add("walkableClimb", JToken.FromObject(tile.WalkableClimb, serializer)); return result; }
public List <NavTile> FindPath(NavTile startNode, NavTile goalNode, float range) { HashSet <NavTile> closedSet = new HashSet <NavTile>(); HashSet <NavTile> openSet = new HashSet <NavTile>() { startNode }; Dictionary <NavTile, float> gCost = new Dictionary <NavTile, float> { [startNode] = 0 }; Dictionary <NavTile, float> fCost = new Dictionary <NavTile, float> { [startNode] = HeuristicFunction(startNode, goalNode) }; Dictionary <NavTile, NavTile> cameFrom = new Dictionary <NavTile, NavTile>(); while (openSet.Count > 0) { NavTile current = openSet.OrderBy(n => fCost[n]).First(); if (gCost[current] > range) { return(null); } if (current == goalNode) { return(ReconstructPath(cameFrom, goalNode)); } openSet.Remove(current); closedSet.Add(current); foreach (NavTile.Edge edge in current.Edges) { NavTile neighbor = edge.tile; float edgeWeight = edge.weight; if (closedSet.Contains(neighbor)) { continue; } float gCostTemp = gCost[current] + edgeWeight; if (!openSet.Contains(neighbor)) { openSet.Add(neighbor); } else if (gCostTemp >= gCost[neighbor]) { continue; } gCost[neighbor] = gCostTemp; fCost[neighbor] = gCost[neighbor] + HeuristicFunction(neighbor, goalNode); cameFrom[neighbor] = current; } } return(null); }
public static void HandleTileMouseDown(NavTile tile) { OnTileMouseDown?.Invoke(tile); }
private NavTile DeserializeMeshTile(JToken token, NavPolyIdManager manager, out NavPolyId refId) { refId = token["polyId"].ToObject<NavPolyId>(serializer); Vector2i location = token["location"].ToObject<Vector2i>(serializer); int layer = token["layer"].ToObject<int>(serializer); NavTile result = new NavTile(location, layer, manager, refId); result.Salt = token["salt"].ToObject<int>(serializer); result.Bounds = token["bounds"].ToObject<BBox3>(serializer); result.Polys = token["polys"].ToObject<NavPoly[]>(serializer); result.PolyCount = result.Polys.Length; result.Verts = token["verts"].ToObject<Vector3[]>(serializer); result.DetailMeshes = token["detailMeshes"].ToObject<PolyMeshDetail.MeshData[]>(serializer); result.DetailVerts = token["detailVerts"].ToObject<Vector3[]>(serializer); result.DetailTris = token["detailTris"].ToObject<PolyMeshDetail.TriangleData[]>(serializer); result.OffMeshConnections = token["offMeshConnections"].ToObject<OffMeshConnection[]>(serializer); result.OffMeshConnectionCount = result.OffMeshConnections.Length; result.BvNodeCount = token["bvNodeCount"].ToObject<int>(serializer); result.BvQuantFactor = token["bvQuantFactor"].ToObject<float>(serializer); result.WalkableClimb = token["walkableClimb"].ToObject<float>(serializer); var treeObject = (JObject) token["bvTree"]; var nodes = treeObject.GetValue("nodes").ToObject<BVTree.Node[]>(); result.BVTree = new BVTree(nodes); return result; }
public List <NavTile> FindPath(NavTile startNode, NavTile goalNode) { return(FindPath(startNode, goalNode, float.MaxValue)); }
public static void HandleTileMouseOver(NavTile tile) { OnTileMouseOver?.Invoke(tile); }
public List <NavTile> FindPath(NavTile start, NavTile goal) { return(pathfinder.FindPath(start, goal)); }
/// <summary> /// Build a tile and link all the polygons togther, both internally and externally. /// Make sure to link off-mesh connections as well. /// </summary> /// <param name="data">Navigation Mesh data</param> /// <param name="lastRef">Last polygon reference</param> /// <param name="result">Last tile reference</param> public NavPolyId AddTile(NavMeshBuilder data) { //make sure data is in right format PathfindingCommon.NavMeshInfo header = data.Header; //make sure location is free if (GetTileAt(header.X, header.Y, header.Layer) != null) { return(NavPolyId.Null); } NavPolyId newTileId = GetNextTileRef(); NavTile tile = new NavTile(new Vector2i(header.X, header.Y), header.Layer, idManager, newTileId); tile.Salt = idManager.DecodeSalt(ref newTileId); if (header.BvNodeCount == 0) { tile.BVTree = null; } //patch header tile.Verts = data.NavVerts; tile.Polys = data.NavPolys; tile.PolyCount = header.PolyCount; tile.DetailMeshes = data.NavDMeshes; tile.DetailVerts = data.NavDVerts; tile.DetailTris = data.NavDTris; tile.BVTree = data.NavBvTree; tile.OffMeshConnections = data.OffMeshCons; tile.OffMeshConnectionCount = header.OffMeshConCount; tile.BvQuantFactor = header.BvQuantFactor; tile.BvNodeCount = header.BvNodeCount; tile.Bounds = header.Bounds; tile.WalkableClimb = header.WalkableClimb; //create connections within tile tile.ConnectIntLinks(); tile.BaseOffMeshLinks(); //create connections with neighbor tiles //connect with layers in current tile foreach (NavTile layerTile in GetTilesAt(header.X, header.Y)) { if (layerTile != tile) { tile.ConnectExtLinks(layerTile, BoundarySide.Internal); layerTile.ConnectExtLinks(tile, BoundarySide.Internal); } tile.ConnectExtOffMeshLinks(layerTile, BoundarySide.Internal); layerTile.ConnectExtOffMeshLinks(tile, BoundarySide.Internal); } //connect with neighbor tiles for (int i = 0; i < 8; i++) { BoundarySide b = (BoundarySide)i; BoundarySide bo = b.GetOpposite(); foreach (NavTile neighborTile in GetNeighborTilesAt(header.X, header.Y, b)) { tile.ConnectExtLinks(neighborTile, b); neighborTile.ConnectExtLinks(tile, bo); tile.ConnectExtOffMeshLinks(neighborTile, b); neighborTile.ConnectExtOffMeshLinks(tile, bo); } } AddTileAt(tile, GetNextTileRef()); return(newTileId); }
public void AddTileAt(NavTile tile, NavPolyId id) { //TODO more error checking, what if tile already exists? Vector2i loc = tile.Location; List<NavTile> locList; if (!tileSet.TryGetValue(loc, out locList)) { locList = new List<NavTile>(); locList.Add(tile); tileSet.Add(loc, locList); } else { locList.Add(tile); } tileRefs.Add(tile, id); int index = idManager.DecodeTileIndex(ref id); //HACK this is pretty bad but only way to insert at index //TODO tileIndex should have a level of indirection from the list? while (index >= tileList.Count) tileList.Add(null); tileList[index] = tile; }
/// <summary> /// Build a tile and link all the polygons togther, both internally and externally. /// Make sure to link off-mesh connections as well. /// </summary> /// <param name="data">Navigation Mesh data</param> /// <param name="lastRef">Last polygon reference</param> /// <param name="result">Last tile reference</param> public NavPolyId AddTile(NavMeshBuilder data) { //make sure data is in right format PathfindingCommon.NavMeshInfo header = data.Header; //make sure location is free if (GetTileAt(header.X, header.Y, header.Layer) != null) return NavPolyId.Null; NavPolyId newTileId = GetNextTileRef(); NavTile tile = new NavTile(new Vector2i(header.X, header.Y), header.Layer, idManager, newTileId); tile.Salt = idManager.DecodeSalt(ref newTileId); if (header.BvNodeCount == 0) tile.BVTree = null; //patch header tile.Verts = data.NavVerts; tile.Polys = data.NavPolys; tile.PolyCount = header.PolyCount; tile.DetailMeshes = data.NavDMeshes; tile.DetailVerts = data.NavDVerts; tile.DetailTris = data.NavDTris; tile.BVTree = data.NavBvTree; tile.OffMeshConnections = data.OffMeshCons; tile.OffMeshConnectionCount = header.OffMeshConCount; tile.BvQuantFactor = header.BvQuantFactor; tile.BvNodeCount = header.BvNodeCount; tile.Bounds = header.Bounds; tile.WalkableClimb = header.WalkableClimb; //create connections within tile tile.ConnectIntLinks(); tile.BaseOffMeshLinks(); //create connections with neighbor tiles //connect with layers in current tile foreach (NavTile layerTile in GetTilesAt(header.X, header.Y)) { if (layerTile != tile) { tile.ConnectExtLinks(layerTile, BoundarySide.Internal); layerTile.ConnectExtLinks(tile, BoundarySide.Internal); } tile.ConnectExtOffMeshLinks(layerTile, BoundarySide.Internal); layerTile.ConnectExtOffMeshLinks(tile, BoundarySide.Internal); } //connect with neighbor tiles for (int i = 0; i < 8; i++) { BoundarySide b = (BoundarySide)i; BoundarySide bo = b.GetOpposite(); foreach (NavTile neighborTile in GetNeighborTilesAt(header.X, header.Y, b)) { tile.ConnectExtLinks(neighborTile, b); neighborTile.ConnectExtLinks(tile, bo); tile.ConnectExtOffMeshLinks(neighborTile, b); neighborTile.ConnectExtOffMeshLinks(tile, bo); } } AddTileAt(tile, GetNextTileRef()); return newTileId; }
/// <summary> /// Get the tile reference /// </summary> /// <param name="tile">Tile to look for</param> /// <returns>Tile reference</returns> public NavPolyId GetTileRef(NavTile tile) { if (tile == null) return NavPolyId.Null; NavPolyId id; if (!tileRefs.TryGetValue(tile, out id)) id = NavPolyId.Null; return id; }
/// <summary> /// Retrieve the tile and poly based off of a polygon reference /// </summary> /// <param name="reference">Polygon reference</param> /// <param name="tile">Resulting tile</param> /// <param name="poly">Resulting poly</param> /// <returns>True if tile and poly successfully retrieved</returns> public bool TryGetTileAndPolyByRef(NavPolyId reference, out NavTile tile, out NavPoly poly) { tile = null; poly = null; if (reference == NavPolyId.Null) return false; //Get tile and poly indices int salt, polyIndex, tileIndex; idManager.Decode(ref reference, out polyIndex, out tileIndex, out salt); //Make sure indices are valid if (tileIndex >= maxTiles) return false; if (tileList[tileIndex].Salt != salt) return false; if (polyIndex >= tileList[tileIndex].PolyCount) return false; //Retrieve tile and poly tile = tileList[tileIndex]; poly = tileList[tileIndex].Polys[polyIndex]; return true; }
/// <summary> /// Only use this function if it is known that the provided polygon reference is valid. /// </summary> /// <param name="reference">Polygon reference</param> /// <param name="tile">Resulting tile</param> /// <param name="poly">Resulting poly</param> public void TryGetTileAndPolyByRefUnsafe(NavPolyId reference, out NavTile tile, out NavPoly poly) { int salt, polyIndex, tileIndex; idManager.Decode(ref reference, out polyIndex, out tileIndex, out salt); tile = tileList[tileIndex]; poly = tileList[tileIndex].Polys[polyIndex]; }
private byte[] SerializeMeshTile(NavTile tile, NavPolyId baseRef) { var memoryStream = new MemoryStream(); using (var binaryWriter = new BinaryWriter(memoryStream)) { binaryWriter.Write(baseRef.Id); binaryWriter.Write(tile.Location.X); binaryWriter.Write(tile.Location.Y); binaryWriter.Write(tile.Layer); binaryWriter.Write(tile.Salt); binaryWriter.Write(tile.Bounds.Min.X); binaryWriter.Write(tile.Bounds.Min.Y); binaryWriter.Write(tile.Bounds.Min.Z); binaryWriter.Write(tile.Bounds.Max.X); binaryWriter.Write(tile.Bounds.Max.Y); binaryWriter.Write(tile.Bounds.Max.Z); var polys = new List <NavPoly>(tile.Polys); binaryWriter.Write(polys.Count); foreach (var poly in polys) { binaryWriter.Write((byte)poly.PolyType); var polyLinks = new List <Link>(poly.Links); binaryWriter.Write(polyLinks.Count); foreach (var polyLink in polyLinks) { binaryWriter.Write(polyLink.Reference.Id); binaryWriter.Write(polyLink.Edge); binaryWriter.Write((byte)polyLink.Side); binaryWriter.Write(polyLink.BMin); binaryWriter.Write(polyLink.BMax); } var polyVerts = new List <int>(poly.Verts); binaryWriter.Write(polyVerts.Count); foreach (var polyVert in polyVerts) { binaryWriter.Write(polyVert); } var polyNeis = new List <int>(poly.Neis); binaryWriter.Write(polyNeis.Count); foreach (var polyNei in polyNeis) { binaryWriter.Write(polyNei); } if (poly.Tag == null) { binaryWriter.Write((byte)0xFE); } else { binaryWriter.Write((byte)poly.Tag); } binaryWriter.Write(poly.VertCount); binaryWriter.Write(poly.Area.Id); } var verts = new List <Vector3>(tile.Verts); binaryWriter.Write(verts.Count); foreach (var vert in verts) { binaryWriter.Write(vert.X); binaryWriter.Write(vert.Y); binaryWriter.Write(vert.Z); } var detailMeshes = new List <PolyMeshDetail.MeshData>(tile.DetailMeshes); binaryWriter.Write(detailMeshes.Count); foreach (var detailMesh in detailMeshes) { binaryWriter.Write(detailMesh.VertexIndex); binaryWriter.Write(detailMesh.VertexCount); binaryWriter.Write(detailMesh.TriangleIndex); binaryWriter.Write(detailMesh.TriangleCount); } var detailVerts = new List <Vector3>(tile.DetailVerts); binaryWriter.Write(detailVerts.Count); foreach (var detailVert in detailVerts) { binaryWriter.Write(detailVert.X); binaryWriter.Write(detailVert.Y); binaryWriter.Write(detailVert.Z); } var detailTris = new List <PolyMeshDetail.TriangleData>(tile.DetailTris); binaryWriter.Write(detailTris.Count); foreach (var detailTri in detailTris) { binaryWriter.Write(detailTri.VertexHash0); binaryWriter.Write(detailTri.VertexHash1); binaryWriter.Write(detailTri.VertexHash2); binaryWriter.Write(detailTri.Flags); } var offMeshConnections = new List <OffMeshConnection>(tile.OffMeshConnections); binaryWriter.Write(offMeshConnections.Count); foreach (var offMeshConnection in offMeshConnections) { } binaryWriter.Write(tile.BVTree.Count); for (var i = 0; i < tile.BVTree.Count; i++) { var node = tile.BVTree[i]; binaryWriter.Write(node.Bounds.Min.X); binaryWriter.Write(node.Bounds.Min.Y); binaryWriter.Write(node.Bounds.Min.Z); binaryWriter.Write(node.Bounds.Max.X); binaryWriter.Write(node.Bounds.Max.Y); binaryWriter.Write(node.Bounds.Max.Z); binaryWriter.Write(node.Index); } binaryWriter.Write(tile.BvQuantFactor); binaryWriter.Write(tile.BvNodeCount); binaryWriter.Write(tile.WalkableClimb); } return(memoryStream.ToArray()); }
public virtual bool PassFilter(NavPolyId polyId, NavTile tile, NavPoly poly) { return true; }
private NavTile DeserializeMeshTile(ref Stream stream, NavPolyIdManager manager, out NavPolyId baseRef) { NavTile tile; using (var binaryReader = new BinaryReader(stream)) { var id = binaryReader.ReadInt32(); baseRef = new NavPolyId(id); var x = binaryReader.ReadInt32(); var y = binaryReader.ReadInt32(); var location = new Vector2i(x, y); var layer = binaryReader.ReadInt32(); tile = new NavTile(location, layer, manager, baseRef); tile.Salt = binaryReader.ReadInt32(); var minX = binaryReader.ReadSingle(); var minY = binaryReader.ReadSingle(); var minZ = binaryReader.ReadSingle(); var maxX = binaryReader.ReadSingle(); var maxY = binaryReader.ReadSingle(); var maxZ = binaryReader.ReadSingle(); tile.Bounds = new BBox3(minX, minY, minZ, maxX, maxY, maxZ); var polysCount = binaryReader.ReadInt32(); var polys = new NavPoly[polysCount]; for (var i = 0; i < polysCount; i++) { var poly = new NavPoly(); poly.PolyType = (NavPolyType)binaryReader.ReadByte(); var polyLinksCount = binaryReader.ReadInt32(); for (var j = 0; j < polyLinksCount; j++) { var navPolyId = binaryReader.ReadInt32(); var link = new Link(); link.Reference = new NavPolyId(navPolyId); link.Edge = binaryReader.ReadInt32(); link.Side = (BoundarySide)binaryReader.ReadByte(); link.BMin = binaryReader.ReadInt32(); link.BMax = binaryReader.ReadInt32(); poly.Links.Add(link); } var polyVertsCount = binaryReader.ReadInt32(); poly.Verts = new int[polyVertsCount]; for (var j = 0; j < polyVertsCount; j++) { poly.Verts[j] = binaryReader.ReadInt32(); } var polyNeisCount = binaryReader.ReadInt32(); poly.Neis = new int[polyNeisCount]; for (var j = 0; j < polyNeisCount; j++) { poly.Neis[j] = binaryReader.ReadInt32(); } var polyTag = binaryReader.ReadByte(); if (polyTag == 0xFE) { poly.Tag = null; } else { poly.Tag = (OffMeshConnectionFlags)polyTag; } poly.VertCount = binaryReader.ReadInt32(); var areaId = binaryReader.ReadByte(); poly.Area = new Area(areaId); polys[i] = poly; } tile.Polys = polys; tile.PolyCount = polysCount; var vertsCount = binaryReader.ReadInt32(); var verts = new Vector3[vertsCount]; for (var i = 0; i < vertsCount; i++) { var vx = binaryReader.ReadSingle(); var vy = binaryReader.ReadSingle(); var vz = binaryReader.ReadSingle(); var vert = new Vector3(vx, vy, vz); verts[i] = vert; } tile.Verts = verts; var detailMeshesCount = binaryReader.ReadInt32(); var detailMeshes = new PolyMeshDetail.MeshData[detailMeshesCount]; for (var i = 0; i < detailMeshesCount; i++) { var detailMesh = new PolyMeshDetail.MeshData(); detailMesh.VertexIndex = binaryReader.ReadInt32(); detailMesh.VertexCount = binaryReader.ReadInt32(); detailMesh.TriangleIndex = binaryReader.ReadInt32(); detailMesh.TriangleCount = binaryReader.ReadInt32(); detailMeshes[i] = detailMesh; } tile.DetailMeshes = detailMeshes; var detailVertsCount = binaryReader.ReadInt32(); var detailVerts = new Vector3[detailVertsCount]; for (var i = 0; i < detailVertsCount; i++) { var vx = binaryReader.ReadSingle(); var vy = binaryReader.ReadSingle(); var vz = binaryReader.ReadSingle(); var detailVert = new Vector3(vx, vy, vz); detailVerts[i] = detailVert; } tile.DetailVerts = detailVerts; var detailTrisCount = binaryReader.ReadInt32(); var detailTris = new PolyMeshDetail.TriangleData[detailTrisCount]; for (var i = 0; i < detailTrisCount; i++) { var hash0 = binaryReader.ReadInt32(); var hash1 = binaryReader.ReadInt32(); var hash2 = binaryReader.ReadInt32(); var flags = binaryReader.ReadInt32(); var detailTri = new PolyMeshDetail.TriangleData(hash0, hash1, hash2, flags); detailTris[i] = detailTri; } tile.DetailTris = detailTris; var offMeshConnectionsCount = binaryReader.ReadInt32(); for (var i = 0; i < offMeshConnectionsCount; i++) { } var nodesCount = binaryReader.ReadInt32(); var nodes = new BVTree.Node[nodesCount]; for (var i = 0; i < nodesCount; i++) { var node = new BVTree.Node(); node.Bounds.Min.X = binaryReader.ReadInt32(); node.Bounds.Min.Y = binaryReader.ReadInt32(); node.Bounds.Min.Z = binaryReader.ReadInt32(); node.Bounds.Max.X = binaryReader.ReadInt32(); node.Bounds.Max.Y = binaryReader.ReadInt32(); node.Bounds.Max.Z = binaryReader.ReadInt32(); node.Index = binaryReader.ReadInt32(); nodes[i] = node; } tile.BVTree = new BVTree(nodes); tile.BvQuantFactor = binaryReader.ReadSingle(); tile.BvNodeCount = binaryReader.ReadInt32(); tile.WalkableClimb = binaryReader.ReadSingle(); } return(tile); }
/// <summary> /// Get edge midpoint between two prolygons /// </summary> /// <param name="from">"From" polygon reference</param> /// <param name="fromPoly">"From" polygon data</param> /// <param name="fromTile">"From" mesh tile</param> /// <param name="to">"To" polygon reference</param> /// <param name="toPoly">"To" polygon data</param> /// <param name="toTile">"To" mesh tile</param> /// <param name="mid">Edge midpoint</param> /// <returns>True, if midpoint found. False, if otherwise.</returns> public bool GetEdgeMidPoint(NavPolyId from, NavPoly fromPoly, NavTile fromTile, NavPolyId to, NavPoly toPoly, NavTile toTile, ref Vector3 mid) { Vector3 left = new Vector3(); Vector3 right = new Vector3(); if (!GetPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, ref left, ref right)) return false; mid = (left + right) * 0.5f; return true; }
/// <summary> /// Find points on the left and right side. /// </summary> /// <param name="from">"From" polygon reference</param> /// <param name="fromPoly">"From" polygon data</param> /// <param name="fromTile">"From" mesh tile</param> /// <param name="to">"To" polygon reference</param> /// <param name="toPoly">"To" polygon data</param> /// <param name="toTile">"To" mesh tile</param> /// <param name="left">Resulting point on the left side</param> /// <param name="right">Resulting point on the right side</param> /// <returns>True, if points found. False, if otherwise.</returns> public bool GetPortalPoints(NavPolyId from, NavPoly fromPoly, NavTile fromTile, NavPolyId to, NavPoly toPoly, NavTile toTile, ref Vector3 left, ref Vector3 right) { //find the link that points to the 'to' polygon Link link = null; foreach (Link fromLink in fromPoly.Links) { if (fromLink.Reference == to) { link = fromLink; break; } } if (link == null) return false; //handle off-mesh connections if (fromPoly.PolyType == NavPolyType.OffMeshConnection) { //find link that points to first vertex foreach (Link fromLink in fromPoly.Links) { if (fromLink.Reference == to) { int v = fromLink.Edge; left = fromTile.Verts[fromPoly.Verts[v]]; right = fromTile.Verts[fromPoly.Verts[v]]; return true; } } return false; } if (toPoly.PolyType == NavPolyType.OffMeshConnection) { //find link that points to first vertex foreach (Link toLink in toPoly.Links) { if (toLink.Reference == from) { int v = toLink.Edge; left = toTile.Verts[toPoly.Verts[v]]; right = toTile.Verts[toPoly.Verts[v]]; return true; } } return false; } //find portal vertices int v0 = fromPoly.Verts[link.Edge]; int v1 = fromPoly.Verts[(link.Edge + 1) % fromPoly.VertCount]; left = fromTile.Verts[v0]; right = fromTile.Verts[v1]; //if the link is at the tile boundary, clamp the vertices to tile width if (link.Side != BoundarySide.Internal) { //unpack portal limits if (link.BMin != 0 || link.BMax != 255) { float s = 1.0f / 255.0f; float tmin = link.BMin * s; float tmax = link.BMax * s; left = Vector3.Lerp(fromTile.Verts[v0], fromTile.Verts[v1], tmin); right = Vector3.Lerp(fromTile.Verts[v0], fromTile.Verts[v1], tmax); } } return true; }
private float HeuristicFunction(NavTile source, NavTile dest) { return(Vector3.Distance(source.transform.position, dest.transform.position)); }