/// <summary> /// Find the closest polygon possible in the tile under certain constraints. /// </summary> /// <param name="tile">Current tile</param> /// <param name="center">Center starting point</param> /// <param name="extents">Range of search</param> /// <param name="nearestPt">Resulting nearest point</param> /// <returns>Polygon Reference which contains nearest point</returns> public PolyId FindNearestPolyInTile(MeshTile tile, Vector3 center, Vector3 extents, ref Vector3 nearestPt) { BBox3 bounds; bounds.Min = center - extents; bounds.Max = center + extents; //Get nearby polygons from proximity grid List <PolyId> polys = new List <PolyId>(128); int polyCount = QueryPolygonsInTile(tile, bounds, polys); //Find nearest polygon amongst the nearby polygons PolyId nearest = PolyId.Null; float nearestDistanceSqr = float.MaxValue; //Iterate throuh all the polygons for (int i = 0; i < polyCount; i++) { PolyId reference = polys[i]; Vector3 closestPtPoly = new Vector3(); tile.ClosestPointOnPoly(reference.DecodePolyIndex(polyBits), center, ref closestPtPoly); float d = (center - closestPtPoly).LengthSquared(); if (d < nearestDistanceSqr) { nearestPt = closestPtPoly; nearestDistanceSqr = d; nearest = reference; } } return(nearest); }
/// <summary> /// Connect Off-Mesh links between polygons from two different tiles. /// </summary> /// <param name="tile">Current Tile</param> /// <param name="target">Target Tile</param> /// <param name="side">Polygon edge</param> public void ConnectExtOffMeshLinks(ref MeshTile tile, ref MeshTile target, BoundarySide side) { if (tile == null) { return; } //Connect off-mesh links, specifically links which land from target tile to this tile BoundarySide oppositeSide = side.GetOpposite(); //Iterate through all the off-mesh connections of target tile for (int i = 0; i < target.Header.OffMeshConCount; i++) { OffMeshConnection targetCon = target.OffMeshConnections[i]; if (targetCon.Side != oppositeSide) { continue; } Poly targetPoly = target.Polys[targetCon.Poly]; //Skip off-mesh connections which start location could not be connected at all if (!IsLinkAllocated(targetPoly.FirstLink)) { continue; } Vector3 extents = new Vector3(targetCon.Radius, target.Header.WalkableClimb, targetCon.Radius); //Find polygon to connect to Vector3 p = targetCon.Pos1; Vector3 nearestPt = new Vector3(); PolyId reference = FindNearestPolyInTile(tile, p, extents, ref nearestPt); if (reference == PolyId.Null) { continue; } //Further checks if ((nearestPt.X - p.X) * (nearestPt.X - p.X) + (nearestPt.Z - p.Z) * (nearestPt.Z - p.Z) > (targetCon.Radius * targetCon.Radius)) { continue; } //Make sure the location is on the current mesh target.Verts[targetPoly.Verts[1]] = nearestPt; //Link off-mesh connection to target poly int idx = AllocLink(target); if (IsLinkAllocated(idx)) { target.Links[idx].Reference = reference; target.Links[idx].Edge = i; target.Links[idx].Side = oppositeSide; target.Links[idx].BMin = target.Links[idx].BMax = 0; //add to linked list target.Links[idx].Next = target.Polys[i].FirstLink; target.Polys[i].FirstLink = idx; } //link target poly to off-mesh connection if ((targetCon.Flags & OffMeshConnectionFlags.Bidirectional) != 0) { int tidx = AllocLink(tile); if (IsLinkAllocated(tidx)) { int landPolyIdx = reference.DecodePolyIndex(polyBits); PolyId id; id = GetPolyRefBase(target); PolyId.SetPolyIndex(ref id, targetCon.Poly, out id); tile.Links[tidx].Reference = id; tile.Links[tidx].Edge = 0xff; tile.Links[tidx].Side = side; tile.Links[tidx].BMin = tile.Links[tidx].BMax = 0; //add to linked list tile.Links[tidx].Next = tile.Polys[landPolyIdx].FirstLink; tile.Polys[landPolyIdx].FirstLink = tidx; } } } }
/// <summary> /// Begin creating off-mesh links between the tile polygons. /// </summary> /// <param name="tile">Current Tile</param> public void BaseOffMeshLinks(ref MeshTile tile) { if (tile == null) { return; } PolyId polyBase = GetPolyRefBase(tile); //Base off-mesh connection start points for (int i = 0; i < tile.Header.OffMeshConCount; i++) { int con = i; int poly = tile.OffMeshConnections[con].Poly; Vector3 extents = new Vector3(tile.OffMeshConnections[con].Radius, tile.Header.WalkableClimb, tile.OffMeshConnections[con].Radius); //Find polygon to connect to Vector3 p = tile.OffMeshConnections[con].Pos0; Vector3 nearestPt = new Vector3(); PolyId reference = FindNearestPolyInTile(tile, p, extents, ref nearestPt); if (reference == PolyId.Null) { continue; } //Do extra checks if ((nearestPt.X - p.X) * (nearestPt.X - p.X) + (nearestPt.Z - p.Z) * (nearestPt.Z - p.Z) > tile.OffMeshConnections[con].Radius * tile.OffMeshConnections[con].Radius) { continue; } //Make sure location is on current mesh tile.Verts[tile.Polys[poly].Verts[0]] = nearestPt; //Link off-mesh connection to target poly int idx = AllocLink(tile); if (IsLinkAllocated(idx)) { //Initialize a new link tile.Links[idx].Reference = reference; tile.Links[idx].Edge = 0; tile.Links[idx].Side = BoundarySide.Internal; tile.Links[idx].BMin = tile.Links[idx].BMax = 0; //Add to polygon's links list tile.Links[idx].Next = tile.Polys[poly].FirstLink; tile.Polys[poly].FirstLink = idx; } //Start end-point always conects back to off-mesh connection int tidx = AllocLink(tile); if (IsLinkAllocated(tidx)) { //Initialize a new link int landPolyIdx = reference.DecodePolyIndex(polyBits); PolyId id; PolyId.SetPolyIndex(ref polyBase, tile.OffMeshConnections[con].Poly, out id); tile.Links[idx].Reference = id; tile.Links[idx].Edge = 0xff; tile.Links[idx].Side = BoundarySide.Internal; tile.Links[idx].BMin = tile.Links[idx].BMax = 0; //Add to polygon's links list tile.Links[idx].Next = tile.Polys[landPolyIdx].FirstLink; tile.Polys[landPolyIdx].FirstLink = tidx; } } }