Exemple #1
0
        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;
        }
        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];
        }
Exemple #3
0
        public bool MoveOverOffmeshConnection(NavPolyId offMeshConRef, NavPolyId[] refs, ref Vector3 startPos, ref Vector3 endPos, NavMeshQuery navquery)
        {
            //advance the path up to and over the off-mesh connection
            NavPolyId prevRef = NavPolyId.Null, polyRef = path[0];
            int       npos = 0;

            while (npos < path.Count && polyRef != offMeshConRef)
            {
                prevRef = polyRef;
                polyRef = path[npos];
                npos++;
            }

            if (npos == path.Count)
            {
                //could not find offMeshConRef
                return(false);
            }

            //prune path
            path.RemoveRange(0, npos);

            refs[0] = prevRef;
            refs[1] = polyRef;

            TiledNavMesh nav = navquery.NavMesh;

            if (nav.GetOffMeshConnectionPolyEndPoints(refs[0], refs[1], ref startPos, ref endPos) == true)
            {
                pos = endPos;
                return(true);
            }

            return(false);
        }
Exemple #4
0
        /// <summary>
        /// Check if polygon reference is valid.
        /// </summary>
        /// <param name="reference">Polygon reference</param>
        /// <returns>True if valid</returns>
        public bool IsValidPolyRef(NavPolyId reference)
        {
            if (reference == NavPolyId.Null)
            {
                return(false);
            }

            int salt, polyIndex, tileIndex;

            idManager.Decode(ref reference, out polyIndex, out tileIndex, out salt);

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

            return(true);
        }
        public override void Serialize(string path, TiledNavMesh mesh)
        {
            JObject root = new JObject();

            root.Add("meta", JToken.FromObject(new
            {
                version = new
                {
                    snj      = FormatVersion,
                    sharpnav = Assembly.GetExecutingAssembly().GetCustomAttribute <AssemblyInformationalVersionAttribute>().InformationalVersion
                }
            }));

            root.Add("origin", JToken.FromObject(mesh.Origin, serializer));
            root.Add("tileWidth", JToken.FromObject(mesh.TileWidth, serializer));
            root.Add("tileHeight", JToken.FromObject(mesh.TileHeight, serializer));
            root.Add("maxTiles", JToken.FromObject(mesh.MaxTiles, serializer));
            root.Add("maxPolys", JToken.FromObject(mesh.MaxPolys, serializer));

            var tilesArray = new JArray();

            foreach (NavTile tile in mesh.Tiles)
            {
                NavPolyId id = mesh.GetTileRef(tile);
                tilesArray.Add(SerializeMeshTile(tile, id));
            }

            root.Add("tiles", tilesArray);

            File.WriteAllText(path, root.ToString());
        }
        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 SetPolyIndex(ref NavPolyId polyBase, int newPoly, out NavPolyId result)
        {
            newPoly &= polyMask;

            //first clear poly then OR with new poly
            result = new NavPolyId((polyBase.Id & ~polyMask) | newPoly);
        }
Exemple #9
0
        /// <summary>
        /// Check if polygon reference is valid.
        /// </summary>
        /// <param name="reference">Polygon reference</param>
        /// <returns>True if valid</returns>
        public bool IsValidPolyRef(NavPolyId reference)
        {
            if (reference == NavPolyId.Null)
            {
                return(false);
            }

            int salt, polyIndex, tileIndex;

            idManager.Decode(ref reference, out polyIndex, out tileIndex, out salt);

            if (tileIndex >= maxTiles)
            {
                return(false);
            }

            if (tileList[tileIndex].Salt != salt)
            {
                return(false);
            }

            if (polyIndex >= tileList[tileIndex].PolyCount)
            {
                return(false);
            }

            return(true);
        }
Exemple #10
0
 /// <summary>
 /// Resets the path to the first polygon.
 /// </summary>
 /// <param name="reference">The starting polygon reference</param>
 /// <param name="pos">Starting position</param>
 public void Reset(NavPolyId reference, Vector3 pos)
 {
     this.pos    = pos;
     this.target = pos;
     path.Clear();
     path.Add(reference);
 }
Exemple #11
0
        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;
        }
Exemple #12
0
        public void Reset(NavPolyId reference, Vector3 nearest)
        {
            this.corridor.Reset(reference, nearest);
            this.boundary.Reset();
            this.partial = false;

            this.topologyOptTime  = 0;
            this.TargetReplanTime = 0;
            this.numNeis          = 0;

            this.DesiredVel = new Vector3(0.0f, 0.0f, 0.0f);
            this.NVel       = new Vector3(0.0f, 0.0f, 0.0f);
            this.Vel        = new Vector3(0.0f, 0.0f, 0.0f);
            this.currentPos = nearest;

            this.DesiredSpeed = 0;

            if (reference != NavPolyId.Null)
            {
                this.state = AgentState.Walking;
            }
            else
            {
                this.state = AgentState.Invalid;
            }

            this.TargetState = TargetState.None;
        }
Exemple #13
0
        /// <summary>
        /// Try to find the node. If it doesn't exist, create a new node.
        /// </summary>
        /// <param name="id">Node's id</param>
        /// <returns>The node</returns>
        public NavNode GetNode(NavPolyId id)
        {
            NavNode node;

            if (nodeDict.TryGetValue(id, out node))
            {
                return(node);
            }

            if (nodes.Count >= maxNodes)
            {
                return(null);
            }

            NavNode newNode = new NavNode();

            newNode.ParentIndex = 0;
            newNode.PolyCost    = 0;
            newNode.TotalCost   = 0;
            newNode.Id          = id;
            newNode.Flags       = 0;

            nodes.Add(newNode);
            nodeDict.Add(id, newNode);

            return(newNode);
        }
        /// <summary>
        /// Decode a standard polygon reference.
        /// </summary>
        /// <param name="polyBits">The number of bits to use for the polygon value.</param>
        /// <param name="tileBits">The number of bits to use for the tile value.</param>
        /// <param name="saltBits">The number of bits to use for the salt.</param>
        /// <param name="polyIndex">Resulting poly index.</param>
        /// <param name="tileIndex">Resulting tile index.</param>
        /// <param name="salt">Resulting salt value.</param>
        public void Decode(ref NavPolyId id, out int polyIndex, out int tileIndex, out int salt)
        {
            int bits = id.Id;

            salt      = (bits >> saltOffset) & saltMask;
            tileIndex = (bits >> tileOffset) & tileMask;
            polyIndex = bits & polyMask;
        }
Exemple #15
0
 public NavTile this[NavPolyId id]
 {
     get
     {
         int index = idManager.DecodeTileIndex(ref id);
         return(this[index]);
     }
 }
        /// <summary>
        /// Derive a standard polygon reference, which compresses salt, tile index, and poly index together.
        /// </summary>
        /// <param name="polyBits">The number of bits to use for the polygon value.</param>
        /// <param name="tileBits">The number of bits to use for the tile value.</param>
        /// <param name="salt">Salt value</param>
        /// <param name="tileIndex">Tile index</param>
        /// <param name="polyIndex">Poly index</param>
        /// <returns>Polygon reference</returns>
        public void Encode(int salt, int tileIndex, int polyIndex, out NavPolyId result)
        {
            polyIndex &= polyMask;
            tileIndex &= tileMask;
            salt      &= saltMask;

            result = new NavPolyId((salt << saltOffset) | (tileIndex << tileOffset) | polyIndex);
        }
Exemple #17
0
        /// <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];
        }
        /// <summary>
        /// Decode a standard polygon reference.
        /// </summary>
        /// <param name="polyBits">The number of bits to use for the polygon value.</param>
        /// <param name="tileBits">The number of bits to use for the tile value.</param>
        /// <param name="saltBits">The number of bits to use for the salt.</param>
        /// <param name="polyIndex">Resulting poly index.</param>
        /// <param name="tileIndex">Resulting tile index.</param>
        /// <param name="salt">Resulting salt value.</param>
        public void Decode(ref NavPolyId id, out int polyIndex, out int tileIndex, out int salt)
        {
            int bits = id.Id;

            salt = (bits >> saltOffset) & saltMask;
            tileIndex = (bits >> tileOffset) & tileMask;
            polyIndex = bits & polyMask;
        }
Exemple #19
0
 /// <summary>
 /// Request a new move velocity
 /// </summary>
 /// <param name="vel">The agent's velocity</param>
 public void RequestMoveVelocity(Vector3 vel)
 {
     //initialize request
     this.TargetRef            = NavPolyId.Null;
     this.targetPos            = vel;
     this.TargetPathQueryIndex = PathQueue.Invalid;
     this.TargetReplan         = false;
     this.targetState          = TargetState.Velocity;
 }
Exemple #20
0
 /// <summary>
 /// Reset the move target of an agent
 /// </summary>
 public void ResetMoveTarget()
 {
     //initialize request
     this.TargetRef            = NavPolyId.Null;
     this.targetPos            = new Vector3(0.0f, 0.0f, 0.0f);
     this.TargetPathQueryIndex = PathQueue.Invalid;
     this.TargetReplan         = false;
     this.targetState          = TargetState.None;
 }
Exemple #21
0
        /// <summary>
        /// Try to find a node.
        /// </summary>
        /// <param name="id">Node's id</param>
        /// <returns>The node, if found. Null, if otherwise.</returns>
        public NavNode FindNode(NavPolyId id)
        {
            NavNode node;
            if (nodeDict.TryGetValue(id, out node))
            {
                return node;
            }

            return null;
        }
Exemple #22
0
        /// <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);
        }
Exemple #23
0
        /// <summary>
        /// Try to find a node.
        /// </summary>
        /// <param name="id">Node's id</param>
        /// <returns>The node, if found. Null, if otherwise.</returns>
        public NavNode FindNode(NavPolyId id)
        {
            NavNode node;

            if (nodeDict.TryGetValue(id, out node))
            {
                return(node);
            }

            return(null);
        }
Exemple #24
0
 /// <summary>
 /// Change the move target
 /// </summary>
 /// <param name="reference">The polygon reference</param>
 /// <param name="pos">The target's coordinates</param>
 public void RequestMoveTargetReplan(NavPolyId reference, Vector3 pos)
 {
     //initialize request
     this.TargetRef            = reference;
     this.targetPos            = pos;
     this.TargetPathQueryIndex = PathQueue.Invalid;
     this.TargetReplan         = true;
     if (this.TargetRef != NavPolyId.Null)
     {
         this.TargetState = TargetState.Requesting;
     }
     else
     {
         this.TargetState = TargetState.Failed;
     }
 }
Exemple #25
0
        /// <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);
        }
Exemple #26
0
        /// <summary>
        /// Examine polygons in the NavMeshQuery and add polygon edges
        /// </summary>
        /// <param name="reference">The starting polygon reference</param>
        /// <param name="pos">Current position</param>
        /// <param name="collisionQueryRange">Range to query</param>
        /// <param name="navquery">The NavMeshQuery</param>
        public void Update(NavPolyId reference, Vector3 pos, float collisionQueryRange, NavMeshQuery navquery)
        {
            const int MAX_SEGS_PER_POLY = PathfindingCommon.VERTS_PER_POLYGON;

            if (reference == NavPolyId.Null)
            {
                this.center   = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
                this.segCount = 0;
                this.numPolys = 0;
                return;
            }

            this.center = pos;

            //first query non-overlapping polygons
            NavPolyId[] tempArray   = new NavPolyId[polys.Length];
            NavPoint    centerPoint = new NavPoint(reference, pos);

            navquery.FindLocalNeighborhood(ref centerPoint, collisionQueryRange, polys, tempArray, ref numPolys, MaxLocalPolys);

            //secondly, store all polygon edges
            this.segCount = 0;
            Segment[] segs    = new Segment[MAX_SEGS_PER_POLY];
            int       numSegs = 0;

            for (int j = 0; j < numPolys; j++)
            {
                tempArray = new NavPolyId[segs.Length];
                navquery.GetPolyWallSegments(polys[j], segs, tempArray, ref numSegs, MAX_SEGS_PER_POLY);
                for (int k = 0; k < numSegs; k++)
                {
                    //skip too distant segments
                    float tseg;
                    float distSqr = Distance.PointToSegment2DSquared(ref pos, ref segs[k].Start, ref segs[k].End, out tseg);
                    if (distSqr > collisionQueryRange * collisionQueryRange)
                    {
                        continue;
                    }
                    AddSegment(distSqr, segs[k]);
                }
            }
        }
Exemple #27
0
        /// <summary>
        /// Adjust the beginning of the path
        /// </summary>
        /// <param name="safeRef">The starting polygon reference</param>
        /// <param name="safePos">The starting position</param>
        /// <returns>True if path start changed, false if not</returns>
        public bool FixPathStart(NavPolyId safeRef, Vector3 safePos)
        {
            this.pos = safePos;
            if (path.Count < 3 && path.Count > 0)
            {
                NavPolyId lastPathId = path[path.Count - 1];

                path.Clear();
                path.Add(safeRef);
                path.Add(NavPolyId.Null);
                path.Add(lastPathId);
            }
            else
            {
                path[0] = safeRef;
                path[1] = NavPolyId.Null;
            }

            return(true);
        }
Exemple #28
0
        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);
        }
Exemple #29
0
        /// <summary>
        /// Request a new move target
        /// </summary>
        /// <param name="reference">The polygon reference</param>
        /// <param name="pos">The target's coordinates</param>
        /// <returns>True if request met, false if not</returns>
        public bool RequestMoveTarget(NavPolyId reference, Vector3 pos)
        {
            if (reference == NavPolyId.Null)
            {
                return(false);
            }

            //initialize request
            this.TargetRef            = reference;
            this.targetPos            = pos;
            this.TargetPathQueryIndex = PathQueue.Invalid;
            this.TargetReplan         = false;
            if (this.TargetRef != NavPolyId.Null)
            {
                this.targetState = TargetState.Requesting;
            }
            else
            {
                this.targetState = TargetState.Failed;
            }

            return(true);
        }
Exemple #30
0
        /// <summary>
        /// Try to find the node. If it doesn't exist, create a new node.
        /// </summary>
        /// <param name="id">Node's id</param>
        /// <returns>The node</returns>
        public NavNode GetNode(NavPolyId id)
        {
            NavNode node;
            if (nodeDict.TryGetValue(id, out node))
            {
                return node;
            }

            if (nodes.Count >= maxNodes)
                return null;

            NavNode newNode = new NavNode();
            newNode.ParentIndex = 0;
            newNode.PolyCost = 0;
            newNode.TotalCost = 0;
            newNode.Id = id;
            newNode.Flags = 0;

            nodes.Add(newNode);
            nodeDict.Add(id, newNode);

            return newNode;
        }
Exemple #31
0
        /// <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)
        {
            NavTile tile;
            NavPoly poly;

            if (TryGetTileAndPolyByRef(polyRef, out tile, out poly))
            {
                return(false);
            }

            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);
        }
Exemple #32
0
        private bool GetSteerTarget(NavMeshQuery navMeshQuery, SVector3 startPos, SVector3 endPos, float minTargetDist, SharpNav.Pathfinding.Path path,
                                    ref SVector3 steerPos, ref StraightPathFlags steerPosFlag, ref NavPolyId steerPosRef)
        {
            StraightPath steerPath = new StraightPath();

            navMeshQuery.FindStraightPath(startPos, endPos, path, steerPath, 0);
            int nsteerPath = steerPath.Count;

            if (nsteerPath == 0)
            {
                return(false);
            }

            //find vertex far enough to steer to
            int ns = 0;

            while (ns < nsteerPath)
            {
                if ((steerPath[ns].Flags & StraightPathFlags.OffMeshConnection) != 0 ||
                    !InRange(steerPath[ns].Point.Position, startPos, minTargetDist, 1000.0f))
                {
                    break;
                }

                ns++;
            }

            //failed to find good point to steer to
            if (ns >= nsteerPath)
            {
                return(false);
            }

            steerPos     = steerPath[ns].Point.Position;
            steerPos.Y   = startPos.Y;
            steerPosFlag = steerPath[ns].Flags;
            if (steerPosFlag == StraightPathFlags.None && ns == (nsteerPath - 1))
            {
                steerPosFlag = StraightPathFlags.End; // otherwise seeks path infinitely!!!
            }
            steerPosRef = steerPath[ns].Point.Polygon;

            return(true);
        }
Exemple #33
0
 public void Add(NavPolyId poly)
 {
     polys.Add(poly);
 }
Exemple #34
0
        /// <summary>
        /// Store polygons that are within a certain range from the current polygon
        /// </summary>
        /// <param name="centerPoint">Starting position</param>
        /// <param name="radius">Range to search within</param>
        /// <param name="resultRef">All the polygons within range</param>
        /// <param name="resultParent">Polygon's parents</param>
        /// <param name="resultCount">Number of polygons stored</param>
        /// <param name="maxResult">Maximum number of polygons allowed</param>
        /// <returns>True, unless input is invalid</returns>
        public bool FindLocalNeighborhood(ref NavPoint centerPoint, float radius, NavPolyId[] resultRef, NavPolyId[] resultParent, ref int resultCount, int maxResult)
        {
            resultCount = 0;

            //validate input
            if (centerPoint.Polygon == NavPolyId.Null || !nav.IsValidPolyRef(centerPoint.Polygon))
                return false;

            int MAX_STACK = 48;
            NavNode[] stack = new NavNode[MAX_STACK];
            int nstack = 0;

            tinyNodePool.Clear();

            NavNode startNode = tinyNodePool.GetNode(centerPoint.Polygon);
            startNode.ParentIndex = 0;
            startNode.Id = centerPoint.Polygon;
            startNode.Flags = NodeFlags.Closed;
            stack[nstack++] = startNode;

            float radiusSqr = radius * radius;

            Vector3[] pa = new Vector3[PathfindingCommon.VERTS_PER_POLYGON];
            Vector3[] pb = new Vector3[PathfindingCommon.VERTS_PER_POLYGON];

            int n = 0;
            if (n < maxResult)
            {
                resultRef[n] = startNode.Id;
                resultParent[n] = NavPolyId.Null;
                ++n;
            }

            while (nstack > 0)
            {
                //pop front
                NavNode curNode = stack[0];
                for (int i = 0; i < nstack - 1; i++)
                    stack[i] = stack[i + 1];
                nstack--;

                //get poly and tile
                NavPolyId curRef = curNode.Id;
                NavTile curTile;
                NavPoly curPoly;
                nav.TryGetTileAndPolyByRefUnsafe(curRef, out curTile, out curPoly);

                foreach (Link link in curPoly.Links)
                {
                    NavPolyId neighborRef = link.Reference;

                    //skip invalid neighbors
                    if (neighborRef == NavPolyId.Null)
                        continue;

                    //skip if cannot allocate more nodes
                    NavNode neighborNode = tinyNodePool.GetNode(neighborRef);
                    if (neighborNode == null)
                        continue;

                    //skip visited
                    if ((neighborNode.Flags & NodeFlags.Closed) != 0)
                        continue;

                    //expand to neighbor
                    NavTile neighborTile;
                    NavPoly neighborPoly;
                    nav.TryGetTileAndPolyByRefUnsafe(neighborRef, out neighborTile, out neighborPoly);

                    //skip off-mesh connections
                    if (neighborPoly.PolyType == NavPolyType.OffMeshConnection)
                        continue;

                    //find edge and calculate distance to edge
                    Vector3 va = new Vector3();
                    Vector3 vb = new Vector3();
                    if (!GetPortalPoints(curRef, curPoly, curTile, neighborRef, neighborPoly, neighborTile, ref va, ref vb))
                        continue;

                    //if the circle is not touching the next polygon, skip it
                    float tseg;
                    float distSqr = Distance.PointToSegment2DSquared(ref centerPoint.Position, ref va, ref vb, out tseg);
                    if (distSqr > radiusSqr)
                        continue;

                    //mark node visited
                    neighborNode.Flags |= NodeFlags.Closed;
                    neighborNode.ParentIndex = tinyNodePool.GetNodeIdx(curNode);

                    //check that the polygon doesn't collide with existing polygons

                    //collect vertices of the neighbor poly
                    int npa = neighborPoly.VertCount;
                    for (int k = 0; k < npa; k++)
                        pa[k] = neighborTile.Verts[neighborPoly.Verts[k]];

                    bool overlap = false;
                    for (int j = 0; j < n; j++)
                    {
                        NavPolyId pastRef = resultRef[j];

                        //connected polys do not overlap
                        bool connected = false;
                        foreach (Link link2 in curPoly.Links)
                        {
                            if (link2.Reference == pastRef)
                            {
                                connected = true;
                                break;
                            }
                        }

                        if (connected)
                            continue;

                        //potentially overlapping
                        NavTile pastTile;
                        NavPoly pastPoly;
                        nav.TryGetTileAndPolyByRefUnsafe(pastRef, out pastTile, out pastPoly);

                        //get vertices and test overlap
                        int npb = pastPoly.VertCount;
                        for (int k = 0; k < npb; k++)
                            pb[k] = pastTile.Verts[pastPoly.Verts[k]];

                        if (Intersection.PolyPoly2D(pa, npa, pb, npb))
                        {
                            overlap = true;
                            break;
                        }
                    }

                    if (overlap)
                        continue;

                    //store poly
                    if (n < maxResult)
                    {
                        resultRef[n] = neighborRef;
                        resultParent[n] = curRef;
                        ++n;
                    }

                    if (nstack < MAX_STACK)
                    {
                        stack[nstack++] = neighborNode;
                    }
                }
            }

            resultCount = n;

            return true;
        }
Exemple #35
0
        public bool Raycast(ref NavPoint startPoint, ref Vector3 endPos, NavPolyId prevRef, RaycastOptions options, out RaycastHit hit, Path hitPath)
        {
            hit = new RaycastHit();

            if (hitPath != null)
                hitPath.Clear();

            //validate input
            if (startPoint.Polygon == NavPolyId.Null || !nav.IsValidPolyRef(startPoint.Polygon))
                return false;

            if (prevRef != NavPolyId.Null && !nav.IsValidPolyRef(prevRef))
                return false;

            Vector3[] verts = new Vector3[PathfindingCommon.VERTS_PER_POLYGON];

            NavTile prevTile, curTile, nextTile;
            NavPoly prevPoly, curPoly, nextPoly;

            NavPolyId curRef = startPoint.Polygon;

            nav.TryGetTileAndPolyByRefUnsafe(curRef, out curTile, out curPoly);
            nextTile = prevTile = curTile;
            nextPoly = prevPoly = curPoly;

            if (prevRef != NavPolyId.Null)
                nav.TryGetTileAndPolyByRefUnsafe(prevRef, out prevTile, out prevPoly);

            while (curRef != NavPolyId.Null)
            {
                //collect vertices
                int nv = 0;
                for (int i = 0; i < curPoly.VertCount; i++)
                {
                    verts[nv] = curTile.Verts[curPoly.Verts[i]];
                    nv++;
                }

                float tmin, tmax;
                int segMin, segMax;
                if (!Intersection.SegmentPoly2D(startPoint.Position, endPos, verts, nv, out tmin, out tmax, out segMin, out segMax))
                {
                    //could not hit the polygon, keep the old t and report hit
                    return true;
                }

                hit.EdgeIndex = segMax;

                //keep track of furthest t so far
                if (tmax > hit.T)
                    hit.T = tmax;

                //store visited polygons
                if (hitPath != null)
                    hitPath.Add(curRef);

                //ray end is completely inside the polygon
                if (segMax == -1)
                {
                    hit.T = float.MaxValue;

                    return true;
                }

                //follow neighbors
                NavPolyId nextRef = NavPolyId.Null;

                foreach (Link link in curPoly.Links)
                {
                    //find link which contains the edge
                    if (link.Edge != segMax)
                        continue;

                    //get pointer to the next polygon
                    nav.TryGetTileAndPolyByRefUnsafe(link.Reference, out nextTile, out nextPoly);

                    //skip off-mesh connection
                    if (nextPoly.PolyType == NavPolyType.OffMeshConnection)
                        continue;

                    //TODO QueryFilter

                    //if the link is internal, just return the ref
                    if (link.Side == BoundarySide.Internal)
                    {
                        nextRef = link.Reference;
                        break;
                    }

                    //if the link is at the tile boundary

                    //check if the link spans the whole edge and accept
                    if (link.BMin == 0 && link.BMax == 255)
                    {
                        nextRef = link.Reference;
                        break;
                    }

                    //check for partial edge links
                    int v0 = curPoly.Verts[link.Edge];
                    int v1 = curPoly.Verts[(link.Edge + 1) % curPoly.VertCount];
                    Vector3 left = curTile.Verts[v0];
                    Vector3 right = curTile.Verts[v1];

                    //check that the intersection lies inside the link portal
                    if (link.Side == BoundarySide.PlusX || link.Side == BoundarySide.MinusX)
                    {
                        //calculate link size
                        float s = 1.0f / 255.0f;
                        float lmin = left.Z + (right.Z - left.Z) * (link.BMin * s);
                        float lmax = left.Z + (right.Z - left.Z) * (link.BMax * s);
                        if (lmin > lmax)
                        {
                            //swap
                            float temp = lmin;
                            lmin = lmax;
                            lmax = temp;
                        }

                        //find z intersection
                        float z = startPoint.Position.Z + (endPos.Z - startPoint.Position.Z) * tmax;
                        if (z >= lmin && z <= lmax)
                        {
                            nextRef = link.Reference;
                            break;
                        }
                    }
                    else if (link.Side == BoundarySide.PlusZ || link.Side == BoundarySide.MinusZ)
                    {
                        //calculate link size
                        float s = 1.0f / 255.0f;
                        float lmin = left.X + (right.X - left.X) * (link.BMin * s);
                        float lmax = left.X + (right.X - left.X) * (link.BMax * s);
                        if (lmin > lmax)
                        {
                            //swap
                            float temp = lmin;
                            lmin = lmax;
                            lmax = temp;
                        }

                        //find x intersection
                        float x = startPoint.Position.X + (endPos.X - startPoint.Position.X) * tmax;
                        if (x >= lmin && x <= lmax)
                        {
                            nextRef = link.Reference;
                            break;
                        }
                    }
                }

                if ((options & RaycastOptions.UseCosts) != 0)
                {
                    //TODO add cost
                }

                if (nextRef == NavPolyId.Null)
                {
                    //no neighbor, we hit a wall

                    //calculate hit normal
                    int a = segMax;
                    int b = (segMax + 1) < nv ? segMax + 1 : 0;
                    Vector3 va = verts[a];
                    Vector3 vb = verts[b];
                    float dx = vb.X - va.X;
                    float dz = vb.Z - va.Z;
                    hit.Normal = new Vector3(dz, 0, dx);
                    hit.Normal.Normalize();
                    return true;
                }

                //no hit, advance to neighbor polygon
                prevRef = curRef;
                curRef = nextRef;
                prevTile = curTile;
                curTile = nextTile;
                prevPoly = curPoly;
                curPoly = nextPoly;
            }

            return true;
        }
Exemple #36
0
 public bool IsValidPolyRef(NavPolyId reference)
 {
     NavTile tile;
     NavPoly poly;
     bool status = nav.TryGetTileAndPolyByRef(reference, out tile, out poly);
     if (status == false)
         return false;
     return true;
 }
Exemple #37
0
        /// <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;
        }
Exemple #38
0
        /// <summary>
        /// Collect all the edges from a polygon.
        /// </summary>
        /// <param name="reference">The polygon reference</param>
        /// <param name="segmentVerts">Segment vertices</param>
        /// <param name="segmentRefs">The polygon reference containing the segment</param>
        /// <param name="segmentCount">The number of segments stored</param>
        /// <param name="maxSegments">The maximum number of segments allowed</param>
        /// <returns>True, unless the polygon reference is invalid</returns>
        public bool GetPolyWallSegments(NavPolyId reference, Crowds.LocalBoundary.Segment[] segmentVerts, NavPolyId[] segmentRefs, ref int segmentCount, int maxSegments)
        {
            segmentCount = 0;

            NavTile tile;
            NavPoly poly;
            if (nav.TryGetTileAndPolyByRef(reference, out tile, out poly) == false)
                return false;

            int n = 0;
            int MAX_INTERVAL = 16;
            SegInterval[] ints = new SegInterval[MAX_INTERVAL];
            int nints;

            bool storePortals = segmentRefs.Length != 0;

            for (int i = 0, j = poly.VertCount - 1; i < poly.VertCount; j = i++)
            {
                //skip non-solid edges
                nints = 0;
                if ((poly.Neis[j] & Link.External) != 0)
                {
                    //tile border
                    foreach (Link link in poly.Links)
                    {
                        if (link.Edge == j)
                        {
                            if (link.Reference != NavPolyId.Null)
                            {
                                NavTile neiTile;
                                NavPoly neiPoly;
                                nav.TryGetTileAndPolyByRefUnsafe(link.Reference, out neiTile, out neiPoly);
                                InsertInterval(ints, ref nints, MAX_INTERVAL, link.BMin, link.BMax, link.Reference);
                            }
                        }
                    }
                }
                else
                {
                    //internal edge
                    NavPolyId neiRef = NavPolyId.Null;
                    if (poly.Neis[j] != 0)
                    {
                        int idx = poly.Neis[j] - 1;
                        NavPolyId id = nav.GetTileRef(tile);
                        nav.IdManager.SetPolyIndex(ref id, idx, out neiRef);
                    }

                    //if the edge leads to another polygon and portals are not stored, skip
                    if (neiRef != NavPolyId.Null && !storePortals)
                        continue;

                    if (n < maxSegments)
                    {
                        Vector3 vj = tile.Verts[poly.Verts[j]];
                        Vector3 vi = tile.Verts[poly.Verts[i]];
                        segmentVerts[n].Start = vj;
                        segmentVerts[n].End = vi;
                        segmentRefs[n] = neiRef;
                        n++; //could be n += 2, since segments have 2 vertices
                    }

                    continue;
                }

                //add sentinels
                InsertInterval(ints, ref nints, MAX_INTERVAL, -1, 0, NavPolyId.Null);
                InsertInterval(ints, ref nints, MAX_INTERVAL, 255, 256, NavPolyId.Null);

                //store segments
                Vector3 vj2 = tile.Verts[poly.Verts[j]];
                Vector3 vi2 = tile.Verts[poly.Verts[i]];
                for (int k = 1; k < nints; k++)
                {
                    //portal segment
                    if (storePortals && ints[k].Reference != NavPolyId.Null)
                    {
                        float tmin = ints[k].TMin / 255.0f;
                        float tmax = ints[k].TMax / 255.0f;
                        if (n < maxSegments)
                        {
                            Vector3.Lerp(ref vj2, ref vi2, tmin, out segmentVerts[n].Start);
                            Vector3.Lerp(ref vj2, ref vi2, tmax, out segmentVerts[n].End);
                            segmentRefs[n] = ints[k].Reference;
                            n++;
                        }
                    }

                    //wall segment
                    int imin = ints[k - 1].TMax;
                    int imax = ints[k].TMin;
                    if (imin != imax)
                    {
                        float tmin = imin / 255.0f;
                        float tmax = imax / 255.0f;
                        if (n < maxSegments)
                        {
                            Vector3.Lerp(ref vj2, ref vi2, tmin, out segmentVerts[n].Start);
                            Vector3.Lerp(ref vj2, ref vi2, tmax, out segmentVerts[n].End);
                            segmentRefs[n] = NavPolyId.Null;
                            n++;
                        }
                    }
                }
            }

            segmentCount = n;

            return true;
        }
Exemple #39
0
        /// <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;
        }
Exemple #40
0
 /// <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];
 }
Exemple #41
0
 /// <summary>
 /// Initializes a new instance of the <see cref="NavPoint"/> struct.
 /// </summary>
 /// <param name="poly">The polygon that the point is on.</param>
 /// <param name="pos">The 3d position of the point.</param>
 public NavPoint(NavPolyId poly, Vector3 pos)
 {
     this.Polygon = poly;
     this.Position = pos;
 }
        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;
        }
Exemple #44
0
        /// <summary>
        /// Update the crowd pathfinding periodically 
        /// </summary>
        /// <param name="dt">Th time until the next update</param>
        public void Update(float dt)
        {
            velocitySampleCount = 0;

            int numAgents = GetActiveAgents(agents);

            //check that all agents have valid paths
            CheckPathValidity(agents, numAgents, dt);

            //update async move requests and path finder
            UpdateMoveRequest();

            //optimize path topology
            UpdateTopologyOptimization(agents, numAgents, dt);

            //register agents to proximity grid
            grid.Clear();
            for (int i = 0; i < numAgents; i++)
            {
                Agent a = agents[i];

                Vector3 p = a.Position;
                float r = a.Parameters.Radius;
                grid.AddItem(a, p.X - r, p.Z - r, p.X + r, p.Z + r);
            }

            //get nearby navmesh segments and agents to collide with
            for (int i = 0; i < numAgents; i++)
            {
                if (agents[i].State != AgentState.Walking)
                    continue;

                //update the collision boundary after certain distance has passed or if it has become invalid
                float updateThr = agents[i].Parameters.CollisionQueryRange * 0.25f;
                if (Vector3Extensions.Distance2D(agents[i].Position, agents[i].Boundary.Center) > updateThr * updateThr || !agents[i].Boundary.IsValid(navQuery))
                {
                    agents[i].Boundary.Update(agents[i].Corridor.GetFirstPoly(), agents[i].Position, agents[i].Parameters.CollisionQueryRange, navQuery);
                }

                //query neighbor agents
                agents[i].NeighborCount = GetNeighbors(agents[i].Position, agents[i].Parameters.Height, agents[i].Parameters.CollisionQueryRange, agents[i], agents[i].Neighbors, AgentMaxNeighbors, agents, grid);

                for (int j = 0; j < agents[i].NeighborCount; j++)
                    agents[i].Neighbors[j].Index = GetAgentIndex(agents[agents[i].Neighbors[j].Index]);
            }

            //find the next corner to steer to
            for (int i = 0; i < numAgents; i++)
            {
                if (agents[i].State != AgentState.Walking)
                    continue;
                if (agents[i].TargetState == TargetState.None ||
                    agents[i].TargetState == TargetState.Velocity)
                    continue;

                //find corners for steering
                agents[i].Corridor.FindCorners(agents[i].Corners, navQuery);

                //check to see if the corner after the next corner is directly visible
                if (((agents[i].Parameters.UpdateFlags & UpdateFlags.OptimizeVis) != 0) && agents[i].Corners.Count > 0)
                {
                    Vector3 target = agents[i].Corners[Math.Min(1, agents[i].Corners.Count - 1)].Point.Position;
                    agents[i].Corridor.OptimizePathVisibility(target, agents[i].Parameters.PathOptimizationRange, navQuery);
                }
            }

            //trigger off-mesh connections (depends on corners)
            for (int i = 0; i < numAgents; i++)
            {
                if (agents[i].State != AgentState.Walking)
                    continue;
                if (agents[i].TargetState == TargetState.None ||
                    agents[i].TargetState == TargetState.Velocity)
                    continue;

                //check
                float triggerRadius = agents[i].Parameters.Radius * 2.25f;
                if (OverOffmeshConnection(agents[i], triggerRadius))
                {
                    //prepare to off-mesh connection
                    int idx = i;

                    //adjust the path over the off-mesh connection
                    NavPolyId[] refs = new NavPolyId[2];
                    if (agents[i].Corridor.MoveOverOffmeshConnection(agents[i].Corners[agents[i].Corners.Count - 1].Point.Polygon, refs, ref agentAnims[idx].StartPos, ref agentAnims[idx].EndPos, navQuery))
                    {
                        agentAnims[idx].InitPos = agents[i].Position;
                        agentAnims[idx].PolyRef = refs[1];
                        agentAnims[idx].Active = true;
                        agentAnims[idx].T = 0.0f;
                        agentAnims[idx].TMax = (Vector3Extensions.Distance2D(agentAnims[idx].StartPos, agentAnims[idx].EndPos)
                            / agents[i].Parameters.MaxSpeed) * 0.5f;

                        agents[i].State = AgentState.Offmesh;
                        agents[i].Corners.Clear();
                        agents[i].NeighborCount = 0;
                        continue;
                    }
                }
            }

            //calculate steering
            for (int i = 0; i < numAgents; i++)
            {
                if (agents[i].State != AgentState.Walking)
                    continue;
                if (agents[i].TargetState == TargetState.None)
                    continue;

                Vector3 dvel = new Vector3(0, 0, 0);

                if (agents[i].TargetState == TargetState.Velocity)
                {
                    dvel = agents[i].TargetPosition;
                    agents[i].DesiredSpeed = agents[i].TargetPosition.Length();
                }
                else
                {
                    //calculate steering direction
                    if ((agents[i].Parameters.UpdateFlags & UpdateFlags.AnticipateTurns) != 0)
                        CalcSmoothSteerDirection(agents[i], ref dvel);
                    else
                        CalcStraightSteerDirection(agents[i], ref dvel);

                    //calculate speed scale, which tells the agent to slowdown at the end of the path
                    float slowDownRadius = agents[i].Parameters.Radius * 2;
                    float speedScale = GetDistanceToGoal(agents[i], slowDownRadius) / slowDownRadius;

                    agents[i].DesiredSpeed = agents[i].Parameters.MaxSpeed;
                    dvel = dvel * (agents[i].DesiredSpeed * speedScale);
                }

                //separation
                if ((agents[i].Parameters.UpdateFlags & UpdateFlags.Separation) != 0)
                {
                    float separationDist = agents[i].Parameters.CollisionQueryRange;
                    float invSeparationDist = 1.0f / separationDist;
                    float separationWeight = agents[i].Parameters.SeparationWeight;

                    float w = 0;
                    Vector3 disp = new Vector3(0, 0, 0);

                    for (int j = 0; j < agents[i].NeighborCount; j++)
                    {
                        Agent nei = agents[agents[i].Neighbors[j].Index];

                        Vector3 diff = agents[i].Position - nei.Position;
                        diff.Y = 0;

                        float distSqr = diff.LengthSquared();
                        if (distSqr < 0.00001f)
                            continue;
                        if (distSqr > separationDist * separationDist)
                            continue;
                        float dist = (float)Math.Sqrt(distSqr);
                        float weight = separationWeight * (1.0f - (dist * invSeparationDist) * (dist * invSeparationDist));

                        disp = disp + diff * (weight / dist);
                        w += 1.0f;
                    }

                    if (w > 0.0001f)
                    {
                        //adjust desired veloctiy
                        dvel = dvel + disp * (1.0f / w);

                        //clamp desired velocity to desired speed
                        float speedSqr = dvel.LengthSquared();
                        float desiredSqr = agents[i].DesiredSpeed * agents[i].DesiredSpeed;
                        if (speedSqr > desiredSqr)
                            dvel = dvel * (desiredSqr / speedSqr);
                    }
                }

                //set the desired velocity
                agents[i].DesiredVel = dvel;
            }

            //velocity planning
            for (int i = 0; i < numAgents; i++)
            {
                if (agents[i].State != AgentState.Walking)
                    continue;

                if ((agents[i].Parameters.UpdateFlags & UpdateFlags.ObstacleAvoidance) != 0)
                {
                    this.obstacleQuery.Reset();

                    //add neighhbors as obstacles
                    for (int j = 0; j < agents[i].NeighborCount; j++)
                    {
                        Agent nei = agents[agents[i].Neighbors[j].Index];
                        obstacleQuery.AddCircle(nei.Position, nei.Parameters.Radius, nei.Vel, nei.DesiredVel);
                    }

                    //append neighbor segments as obstacles
                    for (int j = 0; j < agents[i].Boundary.SegCount; j++)
                    {
                        LocalBoundary.Segment s = agents[i].Boundary.Segs[j];
                        if (Triangle3.Area2D(agents[i].Position, s.Start, s.End) < 0.0f)
                            continue;
                        obstacleQuery.AddSegment(s.Start, s.End);
                    }

                    //sample new safe velocity
                    bool adaptive = true;
                    int ns = 0;

                    ObstacleAvoidanceQuery.ObstacleAvoidanceParams parameters = obstacleQueryParams[agents[i].Parameters.ObstacleAvoidanceType];

                    if (adaptive)
                    {
                        ns = obstacleQuery.SampleVelocityAdaptive(agents[i].Position, agents[i].Parameters.Radius, agents[i].DesiredSpeed, agents[i].Vel, agents[i].DesiredVel, ref agents[i].NVel, parameters);
                    }
                    else
                    {
                        ns = obstacleQuery.SampleVelocityGrid(agents[i].Position, agents[i].Parameters.Radius, agents[i].DesiredSpeed, agents[i].Vel, agents[i].DesiredVel, ref agents[i].NVel, parameters);
                    }

                    this.velocitySampleCount += ns;
                }
                else
                {
                    //if not using velocity planning, new velocity is directly the desired velocity
                    agents[i].NVel = agents[i].DesiredVel;
                }
            }

            //integrate
            for (int i = 0; i < numAgents; i++)
            {
                Agent ag = agents[i];

                if (ag.State != AgentState.Walking)
                    continue;

                ag.Integrate(dt);
            }

            //handle collisions
            const float COLLISION_RESOLVE_FACTOR = 0.7f;

            for (int iter = 0; iter < 4; iter++)
            {
                for (int i = 0; i < numAgents; i++)
                {
                    int idx0 = GetAgentIndex(agents[i]);

                    if (agents[i].State != AgentState.Walking)
                        continue;

                    agents[i].Disp = new Vector3(0, 0, 0);

                    float w = 0;

                    for (int j = 0; j < agents[i].NeighborCount; j++)
                    {
                        Agent nei = agents[agents[i].Neighbors[j].Index];
                        int idx1 = GetAgentIndex(nei);

                        Vector3 diff = agents[i].Position - nei.Position;
                        diff.Y = 0;

                        float dist = diff.LengthSquared();
                        if (dist > (agents[i].Parameters.Radius + nei.Parameters.Radius) * (agents[i].Parameters.Radius + nei.Parameters.Radius))
                            continue;
                        dist = (float)Math.Sqrt(dist);
                        float pen = (agents[i].Parameters.Radius + nei.Parameters.Radius) - dist;
                        if (dist < 0.0001f)
                        {
                            //agents on top of each other, try to choose diverging separation directions
                            if (idx0 > idx1)
                                diff = new Vector3(-agents[i].DesiredVel.Z, 0, agents[i].DesiredVel.X);
                            else
                                diff = new Vector3(agents[i].DesiredVel.Z, 0, -agents[i].DesiredVel.X);
                            pen = 0.01f;
                        }
                        else
                        {
                            pen = (1.0f / dist) * (pen * 0.5f) * COLLISION_RESOLVE_FACTOR;
                        }

                        agents[i].Disp = agents[i].Disp + diff * pen;

                        w += 1.0f;
                    }

                    if (w > 0.0001f)
                    {
                        float iw = 1.0f / w;
                        agents[i].Disp = agents[i].Disp * iw;
                    }
                }

                for (int i = 0; i < numAgents; i++)
                {
                    if (agents[i].State != AgentState.Walking)
                        continue;

                    //move along navmesh
                    agents[i].Corridor.MovePosition(agents[i].Position, navQuery);

                    //get valid constrained position back
                    agents[i].Position = agents[i].Corridor.Pos;

                    //if not using path, truncate the corridor to just one poly
                    if (agents[i].TargetState == TargetState.None ||
                        agents[i].TargetState == TargetState.Velocity)
                    {
                        agents[i].Corridor.Reset(agents[i].Corridor.GetFirstPoly(), agents[i].Position);
                        agents[i].IsPartial = false;
                    }
                }

                //update agents using offmesh connections
                for (int i = 0; i < maxAgents; i++)
                {
                    if (!agentAnims[i].Active)
                        continue;

                    agentAnims[i].T += dt;
                    if (agentAnims[i].T > agentAnims[i].TMax)
                    {
                        //reset animation
                        agentAnims[i].Active = false;

                        //prepare agent for walking
                        agents[i].State = AgentState.Walking;

                        continue;
                    }

                    //update position
                    float ta = agentAnims[i].TMax * 0.15f;
                    float tb = agentAnims[i].TMax;
                    if (agentAnims[i].T < ta)
                    {
                        float u = MathHelper.Normalize(agentAnims[i].T, 0.0f, ta);
                        Vector3 lerpOut;
                        Vector3.Lerp(ref agentAnims[i].InitPos, ref agentAnims[i].StartPos, u, out lerpOut);
                        agents[i].Position = lerpOut;
                    }
                    else
                    {
                        float u = MathHelper.Normalize(agentAnims[i].T, ta, tb);
                        Vector3 lerpOut;
                        Vector3.Lerp(ref agentAnims[i].StartPos, ref agentAnims[i].EndPos, u, out lerpOut);
                        agents[i].Position = lerpOut;
                    }

                    agents[i].Vel = new Vector3(0, 0, 0);
                    agents[i].DesiredVel = new Vector3(0, 0, 0);
                }
            }
        }
Exemple #45
0
        /// <summary>
        /// Return false if the provided position is outside the xz-bounds.
        /// </summary>
        /// <param name="reference">Polygon reference</param>
        /// <param name="pos">Current position</param>
        /// <param name="height">Resulting polygon height</param>
        /// <returns>True, if height found. False, if otherwise.</returns>
        public bool GetPolyHeight(NavPolyId reference, Vector3 pos, ref float height)
        {
            if (nav == null)
                return false;

            NavTile tile;
            NavPoly poly;
            if (!nav.TryGetTileAndPolyByRef(reference, out tile, out poly))
                return false;

            //off-mesh connections don't have detail polygons
            if (poly.PolyType == NavPolyType.OffMeshConnection)
            {
                Vector3 closest;
                tile.ClosestPointOnPolyOffMeshConnection(poly, pos, out closest);
                height = closest.Y;
                return true;
            }
            else
            {
                int indexPoly = 0;
                for (int i = 0; i < tile.Polys.Length; i++)
                {
                    if (tile.Polys[i] == poly)
                    {
                        indexPoly = i;
                        break;
                    }
                }

                float h = 0;
                if (tile.ClosestHeight(indexPoly, pos, out h))
                {
                    height = h;
                    return true;
                }
            }

            return false;
        }
Exemple #46
0
        /// <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;
        }
Exemple #47
0
        /// <summary>
        /// Find points on the left and right side.
        /// </summary>
        /// <param name="from">"From" polygon reference</param>
        /// <param name="to">"To" polygon reference</param>
        /// <param name="left">Point on the left side</param>
        /// <param name="right">Point on the right side</param>
        /// <param name="fromType">Polygon type of "From" polygon</param>
        /// <param name="toType">Polygon type of "To" polygon</param>
        /// <returns>True, if points found. False, if otherwise.</returns>
        public bool GetPortalPoints(NavPolyId from, NavPolyId to, ref Vector3 left, ref Vector3 right, ref NavPolyType fromType, ref NavPolyType toType)
        {
            NavTile fromTile;
            NavPoly fromPoly;
            if (nav.TryGetTileAndPolyByRef(from, out fromTile, out fromPoly) == false)
                return false;
            fromType = fromPoly.PolyType;

            NavTile toTile;
            NavPoly toPoly;
            if (nav.TryGetTileAndPolyByRef(to, out toTile, out toPoly) == false)
                return false;
            toType = toPoly.PolyType;

            return GetPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, ref left, ref right);
        }
Exemple #48
0
        /// <summary>
        /// Check if polygon reference is valid.
        /// </summary>
        /// <param name="reference">Polygon reference</param>
        /// <returns>True if valid</returns>
        public bool IsValidPolyRef(NavPolyId reference)
        {
            if (reference == NavPolyId.Null)
                return false;

            int salt, polyIndex, tileIndex;
            idManager.Decode(ref reference, out polyIndex, out tileIndex, out salt);

            if (tileIndex >= maxTiles)
                return false;

            if (tileList[tileIndex].Salt != salt)
                return false;

            if (polyIndex >= tileList[tileIndex].PolyCount)
                return false;

            return true;
        }
Exemple #49
0
        /// <summary>
        /// Insert a segment into the array
        /// </summary>
        /// <param name="ints">The array of segments</param>
        /// <param name="nints">The number of segments</param>
        /// <param name="maxInts">The maximium number of segments allowed</param>
        /// <param name="tmin">Parameter t minimum</param>
        /// <param name="tmax">Parameter t maximum</param>
        /// <param name="reference">Polygon reference</param>
        public void InsertInterval(SegInterval[] ints, ref int nints, int maxInts, int tmin, int tmax, NavPolyId reference)
        {
            if (nints + 1 > maxInts)
                return;

            //find insertion point
            int idx = 0;
            while (idx < nints)
            {
                if (tmax <= ints[idx].TMin)
                    break;
                idx++;
            }

            //move current results
            if (nints - idx > 0)
            {
                for (int i = 0; i < nints - idx; i++)
                    ints[idx + 1 + i] = ints[idx + i];
            }

            //store
            ints[idx].Reference = reference;
            ints[idx].TMin = tmin;
            ints[idx].TMax = tmax;
            nints++;
        }
Exemple #50
0
        /// <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;
        }
Exemple #51
0
        /// <summary>
        /// Given a point on the polygon, find the closest point
        /// </summary>
        /// <param name="reference">Polygon reference</param>
        /// <param name="pos">Current position</param>
        /// <param name="closest">Resulting closest position</param>
        /// <param name="posOverPoly">Determines whether the position can be found on the polygon</param>
        /// <returns>True, if the closest point is found. False, if otherwise.</returns>
        public bool ClosestPointOnPoly(NavPolyId reference, Vector3 pos, out Vector3 closest, out bool posOverPoly)
        {
            posOverPoly = false;
            closest = Vector3.Zero;

            NavTile tile;
            NavPoly poly;
            if (!nav.TryGetTileAndPolyByRef(reference, out tile, out poly))
                return false;
            if (tile == null)
                return false;

            if (poly.PolyType == NavPolyType.OffMeshConnection)
            {
                Vector3 v0 = tile.Verts[poly.Verts[0]];
                Vector3 v1 = tile.Verts[poly.Verts[1]];
                float d0 = (pos - v0).Length();
                float d1 = (pos - v1).Length();
                float u = d0 / (d0 + d1);
                closest = Vector3.Lerp(v0, v1, u);
                return true;
            }

            int indexPoly = 0;
            for (int i = 0; i < tile.Polys.Length; i++)
            {
                if (tile.Polys[i] == poly)
                {
                    indexPoly = i;
                    break;
                }
            }

            PolyMeshDetail.MeshData pd = tile.DetailMeshes[indexPoly];

            //Clamp point to be inside the polygon
            Vector3[] verts = new Vector3[PathfindingCommon.VERTS_PER_POLYGON];
            float[] edgeDistance = new float[PathfindingCommon.VERTS_PER_POLYGON];
            float[] edgeT = new float[PathfindingCommon.VERTS_PER_POLYGON];
            int numPolyVerts = poly.VertCount;
            for (int i = 0; i < numPolyVerts; i++)
                verts[i] = tile.Verts[poly.Verts[i]];

            closest = pos;
            if (!Distance.PointToPolygonEdgeSquared(pos, verts, numPolyVerts, edgeDistance, edgeT))
            {
                //Point is outside the polygon
                //Clamp to nearest edge
                float minDistance = float.MaxValue;
                int minIndex = -1;
                for (int i = 0; i < numPolyVerts; i++)
                {
                    if (edgeDistance[i] < minDistance)
                    {
                        minDistance = edgeDistance[i];
                        minIndex = i;
                    }
                }

                Vector3 va = verts[minIndex];
                Vector3 vb = verts[(minIndex + 1) % numPolyVerts];
                closest = Vector3.Lerp(va, vb, edgeT[minIndex]);
            }
            else
            {
                posOverPoly = false;
            }

            //find height at the location
            for (int j = 0; j < tile.DetailMeshes[indexPoly].TriangleCount; j++)
            {
                PolyMeshDetail.TriangleData t = tile.DetailTris[pd.TriangleIndex + j];
                Vector3 va, vb, vc;

                if (t.VertexHash0 < poly.VertCount)
                    va = tile.Verts[poly.Verts[t.VertexHash0]];
                else
                    va = tile.DetailVerts[pd.VertexIndex + (t.VertexHash0 - poly.VertCount)];

                if (t.VertexHash1 < poly.VertCount)
                    vb = tile.Verts[poly.Verts[t.VertexHash1]];
                else
                    vb = tile.DetailVerts[pd.VertexIndex + (t.VertexHash1 - poly.VertCount)];

                if (t.VertexHash2 < poly.VertCount)
                    vc = tile.Verts[poly.Verts[t.VertexHash2]];
                else
                    vc = tile.DetailVerts[pd.VertexIndex + (t.VertexHash2 - poly.VertCount)];

                float h;
                if (Distance.PointToTriangle(pos, va, vb, vc, out h))
                {
                    closest.Y = h;
                    break;
                }
            }

            return true;
        }
Exemple #52
0
        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;
        }
Exemple #53
0
        /// <summary>
        /// Given a point on a polygon, find the closest point which lies on the polygon boundary.
        /// </summary>
        /// <param name="reference">Polygon reference</param>
        /// <param name="pos">Current position</param>
        /// <param name="closest">Resulting closest point</param>
        /// <returns>True, if the closest point is found. False, if otherwise.</returns>
        public bool ClosestPointOnPolyBoundary(NavPolyId reference, Vector3 pos, ref Vector3 closest)
        {
            NavTile tile;
            NavPoly poly;
            if (nav.TryGetTileAndPolyByRef(reference, out tile, out poly) == false)
                return false;

            tile.ClosestPointOnPolyBoundary(poly, pos, out closest);
            return true;
        }
Exemple #54
0
 public NavTile this[NavPolyId id]
 {
     get
     {
         int index = idManager.DecodeTileIndex(ref id);
         return this[index];
     }
 }
        public Vector2[] GetPath(Vector2 start, Vector2 end)
        {
            NavPoint startPt = navMeshQuery.FindNearestPoly(new SVector3(-start.X, 0, start.Y), new SharpNav.Geometry.Vector3(2f, 2f, 2f));
            NavPoint endPt   = navMeshQuery.FindNearestPoly(new SVector3(-end.X, 0, end.Y), new SharpNav.Geometry.Vector3(2f, 2f, 2f));
            Path     path    = new Path();

            navMeshQuery.FindPath(ref startPt, ref endPt, new NavQueryFilter(), path);

            List <SVector3> smoothPath;

            //find a smooth path over the mesh surface
            int      npolys    = path.Count;
            SVector3 iterPos   = new SVector3();
            SVector3 targetPos = new SVector3();

            navMeshQuery.ClosestPointOnPoly(startPt.Polygon, startPt.Position, ref iterPos);
            navMeshQuery.ClosestPointOnPoly(path[npolys - 1], endPt.Position, ref targetPos);

            smoothPath = new List <SVector3>(2048);
            smoothPath.Add(iterPos);

            float STEP_SIZE = 0.5f;
            float SLOP      = 0.01f;

            while (npolys > 0 && smoothPath.Count < smoothPath.Capacity)
            {
                //find location to steer towards
                SVector3          steerPos     = new SVector3();
                StraightPathFlags steerPosFlag = 0;
                NavPolyId         steerPosRef  = NavPolyId.Null;

                if (!GetSteerTarget(navMeshQuery, iterPos, targetPos, SLOP, path, ref steerPos, ref steerPosFlag, ref steerPosRef))
                {
                    break;
                }

                bool endOfPath         = (steerPosFlag & StraightPathFlags.End) != 0 ? true : false;
                bool offMeshConnection = (steerPosFlag & StraightPathFlags.OffMeshConnection) != 0 ? true : false;

                //find movement delta
                SVector3 delta = steerPos - iterPos;
                float    len   = (float)Math.Sqrt(SVector3.Dot(delta, delta));

                //if steer target is at end of path or off-mesh link
                //don't move past location
                if ((endOfPath || offMeshConnection) && len < STEP_SIZE)
                {
                    len = 1;
                }
                else
                {
                    len = STEP_SIZE / len;
                }

                SVector3 moveTgt = new SVector3();
                VMad(ref moveTgt, iterPos, delta, len);

                //move
                SVector3         result     = new SVector3();
                List <NavPolyId> visited    = new List <NavPolyId>(16);
                NavPoint         startPoint = new NavPoint(path[0], iterPos);
                navMeshQuery.MoveAlongSurface(ref startPoint, ref moveTgt, out result, visited);
                path.FixupCorridor(visited);
                npolys = path.Count;
                float h = 0;
                navMeshQuery.GetPolyHeight(path[0], result, ref h);
                result.Y = h;
                iterPos  = result;

                //handle end of path when close enough
                if (endOfPath && InRange(iterPos, steerPos, SLOP, 1.0f))
                {
                    //reached end of path
                    iterPos = targetPos;
                    if (smoothPath.Count < smoothPath.Capacity)
                    {
                        smoothPath.Add(iterPos);
                    }
                    break;
                }

                //store results
                if (smoothPath.Count < smoothPath.Capacity)
                {
                    smoothPath.Add(iterPos);
                }
            }

            return(smoothPath.Select(x => new Vector2(-x.X, x.Z)).ToArray());
        }
Exemple #56
0
 /// <summary>
 /// Finds a random point on a polygon.
 /// </summary>
 /// <param name="poly">Polygon to find a random point on.</param>
 /// <returns>Resulting random point</returns>
 public Vector3 FindRandomPointOnPoly(NavPolyId poly)
 {
     Vector3 result;
     this.FindRandomPointOnPoly(poly, out result);
     return result;
 }
Exemple #57
0
        private void GeneratePathfinding()
        {
            if (!hasGenerated)
            {
                return;
            }

            NavQueryFilter filter = new NavQueryFilter();

            buildData = new NavMeshBuilder(polyMesh, polyMeshDetail, new SharpNav.Pathfinding.OffMeshConnection[0], settings);

            tiledNavMesh = new TiledNavMesh(buildData);

            for (int i = 0; i < tiledNavMesh.Tiles.Count; ++i)
            {
                for (int j = 0; j < tiledNavMesh.Tiles[i].Verts.Length; ++j)
                {
                    //if (j < tiledNavMesh.Tiles[i].Verts.Length - 1)
                    //    Debug.DrawLine(ExportNavMeshToObj.ToUnityVector(tiledNavMesh.Tiles[i].Verts[j]), ExportNavMeshToObj.ToUnityVector(tiledNavMesh.Tiles[i].Verts[j + 1]), Color.blue, 99);
                }
            }

            navMeshQuery = new NavMeshQuery(tiledNavMesh, 2048);

            //Find random start and end points on the poly mesh

            /*int startRef;
             * navMeshQuery.FindRandomPoint(out startRef, out startPos);*/

            //SVector3 c = new SVector3(10, 0, 0);
            //SVector3 e = new SVector3(5, 5, 5);
            //navMeshQuery.FindNearestPoly(ref c, ref e, out startPt);

            //navMeshQuery.FindRandomPointAroundCircle(ref startPt, 1000, out endPt);

            startPt = navMeshQuery.FindRandomPoint();
            endPt   = navMeshQuery.FindRandomPoint();

            //calculate the overall path, which contains an array of polygon references
            int MAX_POLYS = 256;

            path = new Path();
            navMeshQuery.FindPath(ref startPt, ref endPt, filter, path);

            //find a smooth path over the mesh surface
            int      npolys    = path.Count;
            SVector3 iterPos   = new SVector3();
            SVector3 targetPos = new SVector3();

            navMeshQuery.ClosestPointOnPoly(startPt.Polygon, startPt.Position, ref iterPos);
            navMeshQuery.ClosestPointOnPoly(path[npolys - 1], endPt.Position, ref targetPos);

            smoothPath = new List <SVector3>(2048);
            smoothPath.Add(iterPos);

            float STEP_SIZE = 0.5f;
            float SLOP      = 0.01f;

            while (npolys > 0 && smoothPath.Count < smoothPath.Capacity)
            {
                //find location to steer towards
                SVector3          steerPos     = new SVector3();
                StraightPathFlags steerPosFlag = 0;
                NavPolyId         steerPosRef  = NavPolyId.Null;

                if (!GetSteerTarget(navMeshQuery, iterPos, targetPos, SLOP, path, ref steerPos, ref steerPosFlag, ref steerPosRef))
                {
                    break;
                }

                bool endOfPath         = (steerPosFlag & StraightPathFlags.End) != 0 ? true : false;
                bool offMeshConnection = (steerPosFlag & StraightPathFlags.OffMeshConnection) != 0 ? true : false;

                //find movement delta
                SVector3 delta = steerPos - iterPos;
                float    len   = (float)Math.Sqrt(SVector3.Dot(delta, delta));

                //if steer target is at end of path or off-mesh link
                //don't move past location
                if ((endOfPath || offMeshConnection) && len < STEP_SIZE)
                {
                    len = 1;
                }
                else
                {
                    len = STEP_SIZE / len;
                }

                SVector3 moveTgt = new SVector3();
                VMad(ref moveTgt, iterPos, delta, len);

                //move
                SVector3         result     = new SVector3();
                List <NavPolyId> visited    = new List <NavPolyId>(16);
                NavPoint         startPoint = new NavPoint(path[0], iterPos);
                navMeshQuery.MoveAlongSurface(ref startPoint, ref moveTgt, out result, visited);
                path.FixupCorridor(visited);
                npolys = path.Count;
                float h = 0;
                navMeshQuery.GetPolyHeight(path[0], result, ref h);
                result.Y = h;
                iterPos  = result;

                //handle end of path when close enough
                if (endOfPath && InRange(iterPos, steerPos, SLOP, 1.0f))
                {
                    //reached end of path
                    iterPos = targetPos;
                    if (smoothPath.Count < smoothPath.Capacity)
                    {
                        smoothPath.Add(iterPos);
                    }
                    break;
                }

                //store results
                if (smoothPath.Count < smoothPath.Capacity)
                {
                    smoothPath.Add(iterPos);
                }
            }

            for (int i = 0; i < smoothPath.Count; i++)
            {
                //if (i < smoothPath.Count - 1)
                //    Debug.DrawLine(ExportNavMeshToObj.ToUnityVector(smoothPath[i]), ExportNavMeshToObj.ToUnityVector(smoothPath[i + 1]), Color.red, 99);
            }
        }
Exemple #58
0
        /// <summary>
        /// Finds a random point on a polygon.
        /// </summary>
        /// <param name="polyId">Polygon to find a radom point on.</param>
        /// <param name="randomPt">Resulting random point.</param>
        public void FindRandomPointOnPoly(NavPolyId polyId, out Vector3 randomPt)
        {
            NavTile tile;
            NavPoly poly;
            if (!nav.TryGetTileAndPolyByRef(polyId, out tile, out poly))
                throw new ArgumentException("Invalid polygon ID", "polyId");

            Vector3[] verts = new Vector3[poly.VertCount];
            for (int j = 0; j < poly.VertCount; j++)
                verts[j] = tile.Verts[poly.Verts[j]];

            float s = (float)rand.NextDouble();
            float t = (float)rand.NextDouble();

            PathfindingCommon.RandomPointInConvexPoly(verts, s, t, out randomPt);

            //TODO bad state again.
            float h = 0.0f;
            if (!GetPolyHeight(polyId, randomPt, ref h))
                throw new InvalidOperationException("Outside bounds?");

            randomPt.Y = h;
        }
Exemple #59
0
        private bool GetSteerTarget(NavMeshQuery navMeshQuery, SVector3 startPos, SVector3 endPos, float minTargetDist, SharpNav.Pathfinding.Path path,
			ref SVector3 steerPos, ref StraightPathFlags steerPosFlag, ref NavPolyId steerPosRef)
        {
            StraightPath steerPath = new StraightPath();
            navMeshQuery.FindStraightPath(startPos, endPos, path, steerPath, 0);
            int nsteerPath = steerPath.Count;
            if (nsteerPath == 0)
                return false;

            //find vertex far enough to steer to
            int ns = 0;
            while (ns < nsteerPath)
            {
                if ((steerPath[ns].Flags & StraightPathFlags.OffMeshConnection) != 0 ||
                    !InRange(steerPath[ns].Point.Position, startPos, minTargetDist, 1000.0f))
                    break;

                ns++;
            }

            //failed to find good point to steer to
            if (ns >= nsteerPath)
                return false;

            steerPos = steerPath[ns].Point.Position;
            steerPos.Y = startPos.Y;
            steerPosFlag = steerPath[ns].Flags;
            if (steerPosFlag == StraightPathFlags.None && ns == (nsteerPath - 1))
                steerPosFlag = StraightPathFlags.End; // otherwise seeks path infinitely!!!
            steerPosRef = steerPath[ns].Point.Polygon;

            return true;
        }
Exemple #60
0
        /// <summary>
        /// Examine polygons in the NavMeshQuery and add polygon edges
        /// </summary>
        /// <param name="reference">The starting polygon reference</param>
        /// <param name="pos">Current position</param>
        /// <param name="collisionQueryRange">Range to query</param>
        /// <param name="navquery">The NavMeshQuery</param>
        public void Update(NavPolyId reference, Vector3 pos, float collisionQueryRange, NavMeshQuery navquery)
        {
            const int MAX_SEGS_PER_POLY = PathfindingCommon.VERTS_PER_POLYGON;

            if (reference == NavPolyId.Null)
            {
                this.center = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
                this.segCount = 0;
                this.numPolys = 0;
                return;
            }

            this.center = pos;

            //first query non-overlapping polygons
            NavPolyId[] tempArray = new NavPolyId[polys.Length];
            NavPoint centerPoint = new NavPoint(reference, pos);
            navquery.FindLocalNeighborhood(ref centerPoint, collisionQueryRange, polys, tempArray, ref numPolys, MaxLocalPolys);

            //secondly, store all polygon edges
            this.segCount = 0;
            Segment[] segs = new Segment[MAX_SEGS_PER_POLY];
            int numSegs = 0;
            for (int j = 0; j < numPolys; j++)
            {
                tempArray = new NavPolyId[segs.Length];
                navquery.GetPolyWallSegments(polys[j], segs, tempArray, ref numSegs, MAX_SEGS_PER_POLY);
                for (int k = 0; k < numSegs; k++)
                {
                    //skip too distant segments
                    float tseg;
                    float distSqr = Distance.PointToSegment2DSquared(ref pos, ref segs[k].Start, ref segs[k].End, out tseg);
                    if (distSqr > collisionQueryRange * collisionQueryRange)
                        continue;
                    AddSegment(distSqr, segs[k]);
                }
            }
        }