Ejemplo n.º 1
0
        /// <summary>
        /// Draws a debug visualization of the specified navigation mesh tile.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method is safe to call on empty tile locations.
        /// </para>
        /// </remarks>
        /// <param name="mesh">The mesh.</param>
        /// <param name="tx">The tile grid x-location.</param>
        /// <param name="tz">The tile grid z-location.</param>
        /// <param name="layer">The tile layer.</param>
        /// <param name="colorByArea">
        /// If true, will be colored by polygon area. If false, will be colored by tile index.
        /// </param>
        public static void Draw(Navmesh mesh, int tx, int tz, int layer, bool colorByArea)
        {
            NavmeshTile tile = mesh.GetTile(tx, tz, layer);

            if (tile == null)
            {
                // No tile at grid location.
                return;
            }

            Draw(tile, null, null, 0
                 , colorByArea ? -1 : tx.GetHashCode() ^ tz.GetHashCode() ^ layer.GetHashCode());
        }
Ejemplo n.º 2
0
        private void UpdateTileType(NavmeshTile tile)
        {
            int  x            = tile.x;
            int  z            = tile.z;
            Int3 tileSize     = (Int3) new Vector3(this.graph.TileWorldSizeX, 0f, this.graph.TileWorldSizeZ);
            Int3 centerOffset = -((Int3)this.graph.GetTileBoundsInGraphSpace(x, z, 1, 1).min + new Int3(tileSize.x * tile.w / 2, 0, tileSize.z * tile.d / 2));

            TileHandler.TileType tileType = new TileHandler.TileType(tile.vertsInGraphSpace, tile.tris, tileSize, centerOffset, tile.w, tile.d);
            int num = x + z * this.tileXCount;

            this.activeTileTypes[num]     = tileType;
            this.activeTileRotations[num] = 0;
            this.activeTileOffsets[num]   = 0;
        }
Ejemplo n.º 3
0
    private void SetConfigFromTargetIntern(Navmesh navmesh)
    {
        NavmeshBuildInfo targetConfig = BuildTarget.BuildInfo;
        NMGenParams      currConfig   = mConfig.GetConfig();

        // Note: Must ensure exact match with original configuration.
        // So this process is using the fields and trusting the
        // original configuration to have valid values.

        currConfig.tileSize       = targetConfig.tileSize;
        currConfig.walkableHeight = targetConfig.walkableHeight;
        currConfig.walkableRadius = targetConfig.walkableRadius;
        currConfig.walkableStep   = targetConfig.walkableStep;
        currConfig.xzCellSize     = targetConfig.xzCellSize;
        currConfig.yCellSize      = targetConfig.yCellSize;
        currConfig.borderSize     = targetConfig.borderSize;

        mBoundsMin = navmesh.GetConfig().origin;

        int maxTiles = navmesh.GetMaxTiles();

        // Make sure the maximum bounds fits the target mesh.
        // Note: Will not shrink the existing max bounds.
        for (int i = 0; i < maxTiles; i++)
        {
            NavmeshTile tile = navmesh.GetTile(i);

            if (tile == null)
            {
                continue;
            }

            NavmeshTileHeader tileHeader = tile.GetHeader();

            if (tileHeader.polyCount == 0)
            {
                continue;
            }

            mBoundsMax = Vector3.Max(mBoundsMax, tileHeader.boundsMax);
        }

        mConfig.SetConfig(currConfig);

        mIsDirty = true;
    }
Ejemplo n.º 4
0
        /// <summary>
        /// Gets the centroids for the polygons that are part of the tile.
        /// </summary>
        private static int GetCentroids(NavmeshTile tile
                                        , uint[] polyRefs
                                        , int polyCount
                                        , UnityEngine.Vector3[] centroids)
        {
            NavmeshTileHeader header = tile.GetHeader();

            if (header.polyCount < 1)
            {
                return(0);
            }

            uint polyBase = tile.GetBasePolyRef();

            NavmeshPoly[] polys = new NavmeshPoly[header.polyCount];
            tile.GetPolys(polys);

            Vector3[] verts = new Vector3[header.vertCount];
            tile.GetVerts(verts);
            UnityEngine.Vector3[] vverts = VectorHelper.ToUnityVector3Array(ref verts);


            int resultCount = 0;

            for (int i = 0; i < header.polyCount; i++)
            {
                uint polyRef = polyBase | ( uint )i;

                int iResult = IsInList(polyRef, polyRefs, polyCount);

                if (iResult == -1)
                {
                    continue;
                }

                resultCount++;

                NavmeshPoly poly = polys[i];

                centroids[iResult] = GetCentroid(vverts, poly.indices, poly.vertCount);
            }

            return(resultCount);
        }
Ejemplo n.º 5
0
 public void CreateTileTypesFromGraph()
 {
     NavmeshTile[] tiles = this.graph.GetTiles();
     if (tiles == null)
     {
         return;
     }
     if (!this.isValid)
     {
         throw new InvalidOperationException("Graph tiles are invalid (number of tiles is not equal to width*depth of the graph). You need to create a new tile handler if you have changed the graph.");
     }
     for (int i = 0; i < this.tileZCount; i++)
     {
         for (int j = 0; j < this.tileXCount; j++)
         {
             NavmeshTile tile = tiles[j + i * this.tileXCount];
             this.UpdateTileType(tile);
         }
     }
 }
Ejemplo n.º 6
0
    public static void OutputVertices()
    {
        NavmeshTile tile = navmesh.GetTile(0);

        float[] headerVerts            = new float[tile.GetHeader().vertCount * 3];
        org.critterai.Vector3[] buffer = new org.critterai.Vector3[tile.GetHeader().vertCount * 3];
        tile.GetVerts(buffer);

        string filename = "Vertices.txt";

        if (File.Exists(filename))
        {
            File.Delete(filename);
        }
        File.AppendAllText(filename, "Left List is Raw (vertcount = " + vertCount +
                           "), Right List is From Header (vertcount = " + tile.GetHeader().vertCount + ") (you might see data loss, as converted in/out of grid space.) \n\n");

        for (int i = 0; i < vertCount; i++)
        {
            File.AppendAllText(filename, "Vertex " + i + ": x: " + vertices[i].x + " y: " + vertices[i].y + " z: " + vertices[i].z + "\t\t|");
            File.AppendAllText(filename, "Vertex " + i + ": x: " + buffer[3 * i + 0].x + " y: " + headerVerts[3 * i + 1] + " z: " + headerVerts[3 * i + 2] + "\n");
        }
    }
Ejemplo n.º 7
0
        /// <summary>
        /// Draws a debug visualization of an individual navmesh tile.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The tile will be checked to see if it is in use before it is drawn.  So there is no
        /// need for caller to do so.
        /// </para>
        /// </remarks>
        private static void Draw(NavmeshTile tile
                                 , NavmeshQuery query, uint[] markPolys, int markPolyCount
                                 , int colorId)
        {
            NavmeshTileHeader header = tile.GetHeader();

            // Keep this check.  Less trouble for clients.
            if (header.polyCount < 1)
            {
                return;
            }

            DebugDraw.SimpleMaterial.SetPass(0);

            uint polyBase = tile.GetBasePolyRef();

            NavmeshPoly[] polys = new NavmeshPoly[header.polyCount];
            tile.GetPolys(polys);

            Vector3[] verts = new Vector3[header.vertCount];
            tile.GetVerts(verts);

            NavmeshDetailMesh[] meshes =
                new NavmeshDetailMesh[header.detailMeshCount];
            tile.GetDetailMeshes(meshes);

            byte[] detailTris = new byte[header.detailTriCount * 4];
            tile.GetDetailTris(detailTris);

            Vector3[] detailVerts = new Vector3[header.detailVertCount];
            tile.GetDetailVerts(detailVerts);

            GL.Begin(GL.TRIANGLES);
            for (int i = 0; i < header.polyCount; i++)
            {
                NavmeshPoly poly = polys[i];

                if (poly.Type == NavmeshPolyType.OffMeshConnection)
                {
                    continue;
                }

                NavmeshDetailMesh mesh = meshes[i];

                Color color = GetStandardColor(polyBase | (uint)i
                                               , poly.Area, colorId
                                               , query, markPolys, markPolyCount);

                GL.Color(color);

                for (int j = 0; j < mesh.triCount; j++)
                {
                    int pTri = (int)(mesh.triBase + j) * 4;

                    for (int k = 0; k < 3; k++)
                    {
                        // Note: iVert and pVert refer to different
                        // arrays.
                        int iVert = detailTris[pTri + k];
                        if (iVert < poly.vertCount)
                        {
                            // Get the vertex from the main vertices.
                            int pVert = poly.indices[iVert];
                            GL.Vertex(verts[pVert]);
                        }
                        else
                        {
                            // Get the vertex from the detail vertices.
                            int pVert = (int)
                                        (mesh.vertBase + iVert - poly.vertCount);
                            GL.Vertex(detailVerts[pVert]);
                        }
                    }
                }
            }
            GL.End();

            NavmeshLink[] links = new NavmeshLink[header.maxLinkCount];
            tile.GetLinks(links);

            GL.Begin(GL.LINES);

            DrawPolyBoundaries(header
                               , polys
                               , verts
                               , meshes
                               , detailTris
                               , detailVerts
                               , links
                               , new Color(0, 0.2f, 0.25f, 0.13f)
                               , true);

            DrawPolyBoundaries(header
                               , polys
                               , verts
                               , meshes
                               , detailTris
                               , detailVerts
                               , links
                               , new Color(0.65f, 0.2f, 0, 0.9f)
                               , false);

            if (header.connCount == 0)
            {
                GL.End();
                return;
            }

            NavmeshConnection[] conns = new NavmeshConnection[header.connCount];
            tile.GetConnections(conns);

            for (int i = 0; i < header.polyCount; i++)
            {
                NavmeshPoly poly = polys[i];

                if (poly.Type != NavmeshPolyType.OffMeshConnection)
                {
                    continue;
                }

                Color color = GetStandardColor(polyBase | (uint)i
                                               , poly.Area, colorId
                                               , query, markPolys, markPolyCount);

                // Note: Alpha of less than one doesn't look good because connections tend to
                // overlay a lot of geometry, resulting is off color transitions.
                color.a = 1;

                GL.Color(color);

                NavmeshConnection conn = conns[i - header.connBase];

                Vector3 va = verts[poly.indices[0]];
                Vector3 vb = verts[poly.indices[1]];

                // Check to see if start and end end-points have links.
                bool startSet = false;
                bool endSet   = false;
                for (uint k = poly.firstLink; k != Navmesh.NullLink; k = links[k].next)
                {
                    if (links[k].edge == 0)
                    {
                        startSet = true;
                    }
                    if (links[k].edge == 1)
                    {
                        endSet = true;
                    }
                }

                // For linked endpoints: Draw a line between on-mesh location and endpoint,
                // and draw circle at the endpoint.
                // For un-linked endpoints: Draw a small red x-marker.

                if (startSet)
                {
                    GL.Vertex(va);
                    GL.Vertex(conn.endpoints[0]);
                    DebugDraw.AppendCircle(conn.endpoints[0], conn.radius);
                }
                else
                {
                    GL.Color(Color.red);
                    DebugDraw.AppendXMarker(conn.endpoints[0], 0.1f);
                    GL.Color(color);
                }

                if (endSet)
                {
                    GL.Vertex(vb);
                    GL.Vertex(conn.endpoints[1]);
                    DebugDraw.AppendCircle(conn.endpoints[1], conn.radius);
                }
                else
                {
                    GL.Color(Color.red);
                    DebugDraw.AppendXMarker(conn.endpoints[1], 0.1f);
                    GL.Color(color);
                }

                DebugDraw.AppendArc(conn.endpoints[0], conn.endpoints[1]
                                    , 0.25f
                                    , conn.IsBiDirectional ? 0.6f : 0
                                    , 0.6f);
            }

            GL.End();
        }
Ejemplo n.º 8
0
		public void ReplaceTile (int x, int z, int w, int d, Int3[] verts, int[] tris, bool worldSpace) {
			
			if(x + w > tileXCount || z+d > tileZCount || x < 0 || z < 0) {
				throw new System.ArgumentException ("Tile is placed at an out of bounds position or extends out of the graph bounds ("+x+", " + z + " [" + w + ", " + d+ "] " + tileXCount + " " + tileZCount + ")");
			}
			
			if (w < 1 || d < 1) throw new System.ArgumentException ("width and depth must be greater or equal to 1");
			
			//Remove previous tiles
			for (int cz=z; cz < z+d;cz++) {
				for (int cx=x; cx < x+w;cx++) {
					
					NavmeshTile otile = tiles[cx + cz*tileXCount];
					if (otile == null) continue;
					
					//Remove old tile connections
					RemoveConnectionsFromTile (otile);
					
					for (int i=0;i<otile.nodes.Length;i++) {
						otile.nodes[i].Destroy();
					}
					
					for (int qz=otile.z; qz < otile.z+otile.d;qz++) {
						for (int qx=otile.x; qx < otile.x+otile.w;qx++) {
							NavmeshTile qtile = tiles[qx + qz*tileXCount];
							if (qtile == null || qtile != otile) throw new System.Exception("This should not happen");
							
							if (qz < z || qz >= z+d || qx < x || qx >= x+w) {
								//if out of this tile's bounds, replace with empty tile
								tiles[qx + qz*tileXCount] = NewEmptyTile(qx,qz);
								
								if (batchTileUpdate) {
									batchUpdatedTiles.Add (qx + qz*tileXCount);
								}
							} else {
								//Will be replaced by the new tile
								tiles[qx + qz*tileXCount] = null;
							}
						}
					}
				}
			}
			
			//Create a new navmesh tile and assign its settings
			NavmeshTile tile = new NavmeshTile();
			
			tile.x = x;
			tile.z = z;
			tile.w = w;
			tile.d = d;
			tile.tris = tris;
			tile.verts = verts;
			tile.bbTree = new BBTree(tile);
			
			if (tile.tris.Length % 3 != 0) throw new System.ArgumentException ("Triangle array's length must be a multiple of 3 (tris)");
			
			if (tile.verts.Length > 0xFFFF) throw new System.ArgumentException ("Too many vertices per tile (more than 65535)");
			
			if (!worldSpace) {
				if (!Mathf.Approximately (x*tileSizeX*cellSize*Int3.FloatPrecision, (float)System.Math.Round(x*tileSizeX*cellSize*Int3.FloatPrecision))) Debug.LogWarning ("Possible numerical imprecision. Consider adjusting tileSize and/or cellSize");
				if (!Mathf.Approximately (z*tileSizeZ*cellSize*Int3.FloatPrecision, (float)System.Math.Round(z*tileSizeZ*cellSize*Int3.FloatPrecision))) Debug.LogWarning ("Possible numerical imprecision. Consider adjusting tileSize and/or cellSize");
			
				Int3 offset = (Int3)(new Vector3((x * tileSizeX * cellSize),0,(z * tileSizeZ * cellSize)) + forcedBounds.min);
				
				for (int i=0;i<verts.Length;i++) {
					verts[i] += offset;
				}
				
			}
			
			TriangleMeshNode[] nodes = new TriangleMeshNode[tile.tris.Length/3];
			tile.nodes = nodes;
			
			//Here we are faking a new graph
			//The tile is not added to any graphs yet, but to get the position querys from the nodes
			//to work correctly (not throw exceptions because the tile is not calculated) we fake a new graph
			//and direct the position queries directly to the tile
			int graphIndex = AstarPath.active.astarData.graphs.Length;
			
			TriangleMeshNode.SetNavmeshHolder (graphIndex, tile);
			
			//This index will be ORed to the triangle indices
			int tileIndex = x + z*tileXCount;
			tileIndex <<= TileIndexOffset;
			
			//Create nodes and assign triangle indices
			for (int i=0;i<nodes.Length;i++) {
				TriangleMeshNode node = new TriangleMeshNode(active);
				nodes[i] = node;
				node.GraphIndex = (uint)graphIndex;
				node.v0 = tile.tris[i*3+0] | tileIndex;
				node.v1 = tile.tris[i*3+1] | tileIndex;
				node.v2 = tile.tris[i*3+2] | tileIndex;
				
				//Degenerate triangles might ocurr, but they will not cause any large troubles anymore
				//if (Polygon.IsColinear (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
				//	Debug.Log ("COLINEAR!!!!!!");
				//}
				
				//Make sure the triangle is clockwise
				if (!Polygon.IsClockwise (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
					int tmp = node.v0;
					node.v0 = node.v2;
					node.v2 = tmp;
				}
				
				node.Walkable = true;
				node.Penalty = initialPenalty;
				node.UpdatePositionFromVertices();
				
				tile.bbTree.Insert (node);
			}
			
			CreateNodeConnections (tile.nodes);
			
			//Set tile
			for (int cz=z; cz < z+d;cz++) {
				for (int cx=x; cx < x+w;cx++) {
					tiles[cx + cz*tileXCount] = tile;
				}
			}
			
			if (batchTileUpdate) {
				batchUpdatedTiles.Add (x + z*tileXCount);
			} else {
				ConnectTileWithNeighbours(tile);
				/*if (x > 0) ConnectTiles (tiles[(x-1) + z*tileXCount], tile);
				if (z > 0) ConnectTiles (tiles[x + (z-1)*tileXCount], tile);
				if (x < tileXCount-1) ConnectTiles (tiles[(x+1) + z*tileXCount], tile);
				if (z < tileZCount-1) ConnectTiles (tiles[x + (z+1)*tileXCount], tile);*/
			}
			
			//Remove the fake graph
			TriangleMeshNode.SetNavmeshHolder (graphIndex, null);
			
			//Real graph index
			//TODO, could this step be changed for this function, is a fake index required?
			graphIndex = AstarPath.active.astarData.GetGraphIndex (this);
			
			for (int i=0;i<nodes.Length;i++) nodes[i].GraphIndex = (uint)graphIndex;			
			
		}
Ejemplo n.º 9
0
		public void RemoveConnectionsFromTo (NavmeshTile a, NavmeshTile b) {
			if (a == null || b == null) return;
			//Same tile, possibly from a large tile (one spanning several x,z tile coordinates)
			if (a == b) return;
			
			int tileIdx = b.x + b.z*tileXCount;
			
			for (int i=0;i<a.nodes.Length;i++) {
				TriangleMeshNode node = a.nodes[i];
				if (node.connections == null) continue;
				for (int j=0;;j++) {
					//Length will not be constant if connections are removed
					if (j >= node.connections.Length) break;
					
					TriangleMeshNode other = node.connections[j] as TriangleMeshNode;
					
					//Only evaluate TriangleMeshNodes
					if (other == null) continue;
					
					int tileIdx2 = other.GetVertexIndex(0);
					tileIdx2 = (tileIdx2 >> TileIndexOffset) & TileIndexMask;
					
					if (tileIdx2 == tileIdx) {
						node.RemoveConnection (node.connections[j]);
						j--;
					}
				}
			}
			
		}
Ejemplo n.º 10
0
        /// <summary>
        /// Draws a debug visualization of an individual navmesh tile.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The tile will be checked to see if it is in use before it is drawn.  So there is no 
        /// need for caller to do so.
        /// </para>
        /// </remarks>
        private static void Draw(NavmeshTile tile
            , NavmeshQuery query, uint[] markPolys, int markPolyCount
            , int colorId)
        {
            NavmeshTileHeader header = tile.GetHeader();

            // Keep this check.  Less trouble for clients.
            if (header.polyCount < 1)
                return;

            DebugDraw.SimpleMaterial.SetPass(0);

            uint polyBase = tile.GetBasePolyRef();

            NavmeshPoly[] polys = new NavmeshPoly[header.polyCount];
            tile.GetPolys(polys);
             
            Vector3[] verts = new Vector3[header.vertCount];
            tile.GetVerts(verts);

            NavmeshDetailMesh[] meshes = 
                new NavmeshDetailMesh[header.detailMeshCount];
            tile.GetDetailMeshes(meshes);

            byte[] detailTris = new byte[header.detailTriCount * 4];
            tile.GetDetailTris(detailTris);

            Vector3[] detailVerts = new Vector3[header.detailVertCount];
            tile.GetDetailVerts(detailVerts);

            GL.Begin(GL.TRIANGLES);
            for (int i = 0; i < header.polyCount; i++)
            {
                NavmeshPoly poly = polys[i];

                if (poly.Type == NavmeshPolyType.OffMeshConnection)
                    continue;

                NavmeshDetailMesh mesh = meshes[i];

                Color color = GetStandardColor(polyBase | (uint)i
                    , poly.Area, colorId
                    , query, markPolys, markPolyCount);

                GL.Color(color);

                for (int j = 0; j < mesh.triCount; j++)
                {
                    int pTri = (int)(mesh.triBase + j) * 4;

                    for (int k = 0; k < 3; k++)
                    {
                        // Note: iVert and pVert refer to different
                        // arrays.
                        int iVert = detailTris[pTri + k];
                        if (iVert < poly.vertCount)
                        {
                            // Get the vertex from the main vertices.
                            int pVert = poly.indices[iVert];
                            GL.Vertex(verts[pVert]);
                        }
                        else
                        {
                            // Get the vertex from the detail vertices.
                            int pVert = (int)
                                (mesh.vertBase + iVert - poly.vertCount);
                            GL.Vertex(detailVerts[pVert]);
                        }
                    }
                }
            }
            GL.End();

            NavmeshLink[] links = new NavmeshLink[header.maxLinkCount];
            tile.GetLinks(links);

            GL.Begin(GL.LINES);

            DrawPolyBoundaries(header
                , polys
                , verts
                , meshes
                , detailTris
                , detailVerts
                , links
                , new Color(0, 0.2f, 0.25f, 0.13f)
                , true);

            DrawPolyBoundaries(header
                , polys
                , verts
                , meshes
                , detailTris
                , detailVerts
                , links
                , new Color(0.65f, 0.2f, 0, 0.9f)
                , false);

            if (header.connCount == 0)
            {
                GL.End();
                return;
            }

            NavmeshConnection[] conns = new NavmeshConnection[header.connCount];
            tile.GetConnections(conns);

            for (int i = 0; i < header.polyCount; i++)
            {
                NavmeshPoly poly = polys[i];

                if (poly.Type != NavmeshPolyType.OffMeshConnection)
                    continue;

                Color color = GetStandardColor(polyBase | (uint)i
                    , poly.Area, colorId
                    , query, markPolys, markPolyCount);

                // Note: Alpha of less than one doesn't look good because connections tend to
                // overlay a lot of geometry, resulting is off color transitions.
                color.a = 1;

                GL.Color(color);

                NavmeshConnection conn = conns[i - header.connBase];

			    Vector3 va = verts[poly.indices[0]];
			    Vector3 vb = verts[poly.indices[1]];

			    // Check to see if start and end end-points have links.
			    bool startSet = false;
			    bool endSet = false;
			    for (uint k = poly.firstLink; k != Navmesh.NullLink; k = links[k].next)
			    {
				    if (links[k].edge == 0)
					    startSet = true;
				    if (links[k].edge == 1)
					    endSet = true;
			    }
    			
                // For linked endpoints: Draw a line between on-mesh location and endpoint, 
                // and draw circle at the endpoint.
                // For un-linked endpoints: Draw a small red x-marker.

                if (startSet)
                {
                    GL.Vertex(va);
                    GL.Vertex(conn.endpoints[0]);
                    DebugDraw.AppendCircle(conn.endpoints[0], conn.radius);
                }
                else
                {
                    GL.Color(Color.red);
                    DebugDraw.AppendXMarker(conn.endpoints[0], 0.1f);
                    GL.Color(color);
                }

                if (endSet)
                {
                    GL.Vertex(vb);
                    GL.Vertex(conn.endpoints[1]);
                    DebugDraw.AppendCircle(conn.endpoints[1], conn.radius);
                }
                else
                {
                    GL.Color(Color.red);
                    DebugDraw.AppendXMarker(conn.endpoints[1], 0.1f);
                    GL.Color(color);
                }

                DebugDraw.AppendArc(conn.endpoints[0], conn.endpoints[1]
                    , 0.25f
                    , conn.IsBiDirectional ? 0.6f : 0
                    , 0.6f);
            }

            GL.End();
        }
Ejemplo n.º 11
0
		public void ConnectTileWithNeighbours (NavmeshTile tile) {
			if (tile.x > 0) {
				int x = tile.x-1;
				for (int z=tile.z;z<tile.z+tile.d;z++) ConnectTiles (tiles[x + z*tileXCount], tile);
			}
			if (tile.x+tile.w < tileXCount) {
				int x = tile.x+tile.w;
				for (int z=tile.z;z<tile.z+tile.d;z++) ConnectTiles (tiles[x + z*tileXCount], tile);
			}
			if (tile.z > 0) {
				int z = tile.z-1;
				for (int x=tile.x;x<tile.x+tile.w;x++) ConnectTiles (tiles[x + z*tileXCount], tile);
			}
			if (tile.z+tile.d < tileZCount) {
				int z = tile.z+tile.d;
				for (int x=tile.x;x<tile.x+tile.w;x++) ConnectTiles (tiles[x + z*tileXCount], tile);
			}
		}
Ejemplo n.º 12
0
		public void RemoveConnectionsFromTile (NavmeshTile tile) {
			if (tile.x > 0) {
				int x = tile.x-1;
				for (int z=tile.z;z<tile.z+tile.d;z++) RemoveConnectionsFromTo (tiles[x + z*tileXCount], tile);
			}
			if (tile.x+tile.w < tileXCount) {
				int x = tile.x+tile.w;
				for (int z=tile.z;z<tile.z+tile.d;z++) RemoveConnectionsFromTo (tiles[x + z*tileXCount], tile);
			}
			if (tile.z > 0) {
				int z = tile.z-1;
				for (int x=tile.x;x<tile.x+tile.w;x++) RemoveConnectionsFromTo (tiles[x + z*tileXCount], tile);
			}
			if (tile.z+tile.d < tileZCount) {
				int z = tile.z+tile.d;
				for (int x=tile.x;x<tile.x+tile.w;x++) RemoveConnectionsFromTo (tiles[x + z*tileXCount], tile);
			}
			//if (tile.z > 0) 			RemoveConnectionsFromTo (tiles[tile.x   + (tile.z-1)*tileXCount], tile);
			//if (tile.x < tileXCount-1) 	RemoveConnectionsFromTo (tiles[tile.x+1 + tile.z*tileXCount], tile);
			//if (tile.z < tileZCount-1) 	RemoveConnectionsFromTo (tiles[tile.x   + (tile.z+1)*tileXCount], tile);
		}
Ejemplo n.º 13
0
		static NavmeshTile NewEmptyTile (int x, int z) {
			NavmeshTile tile = new NavmeshTile();
			tile.x = x;
			tile.z = z;
			tile.w = 1;
			tile.d = 1;
			tile.verts = new Int3[0];
			tile.tris = new int[0];
			tile.nodes = new TriangleMeshNode[0];
			tile.bbTree = new BBTree(tile);
			return tile;
		}
Ejemplo n.º 14
0
        /// <summary>
        /// Gets the centroids for the polygons that are part of the tile.
        /// </summary>
        private static int GetCentroids(NavmeshTile tile
            , uint[] polyRefs
            , int polyCount
            , Vector3[] centroids)
        {
            NavmeshTileHeader header = tile.GetHeader();

            if (header.polyCount < 1)
                return 0;

            uint polyBase = tile.GetBasePolyRef();

            NavmeshPoly[] polys = new NavmeshPoly[header.polyCount];
            tile.GetPolys(polys);

            Vector3[] verts = new Vector3[header.vertCount];
            tile.GetVerts(verts);

            int resultCount = 0;

            for (int i = 0; i < header.polyCount; i++)
            {
                uint polyRef = polyBase | (uint)i;

                int iResult = IsInList(polyRef, polyRefs, polyCount);

                if (iResult == -1)
                    continue;

                resultCount++;

                NavmeshPoly poly = polys[i];

                centroids[iResult] = GetCentroid(verts, poly.indices, poly.vertCount);
            }

            return resultCount;
        }
Ejemplo n.º 15
0
    internal bool CanLoadFromTarget(BuildContext context, bool fullCheck)
    {
        INavmeshData target = BuildTarget;

        if (target == null || !target.HasNavmesh)
        {
            if (context != null)
            {
                context.LogError("Build target does not have an existing navigation mesh.", this);
            }
            return(false);
        }

        NavmeshBuildInfo targetConfig = target.BuildInfo;

        // Note: The tile size is checked since the original builder
        // may have supported a tile size not supported by the the standard build.
        if (targetConfig == null ||
            targetConfig.tileSize >= 0 && targetConfig.tileSize < MinAllowedTileSize)
        {
            if (context != null)
            {
                context.LogError("Unavailable or unsupported build target configuration.", this);
            }
            return(false);
        }

        if (!fullCheck)
        {
            return(true);
        }

        Navmesh nm = target.GetNavmesh();

        if (nm == null)
        {
            if (context != null)
            {
                context.LogError(
                    "Build target does not have an existing navigation mesh. (It lied.)", this);
            }
            return(false);
        }

        NavmeshParams nmConfig = nm.GetConfig();

        if (nmConfig.maxTiles < 2)
        {
            if (context != null)
            {
                context.LogError("Target navigation mesh is not tiled.", this);
            }
            return(false);
        }

        int tileCount = 0;

        for (int i = 0; i < nmConfig.maxTiles; i++)
        {
            NavmeshTile tile = nm.GetTile(i);

            if (tile == null)
            {
                continue;
            }

            NavmeshTileHeader header = tile.GetHeader();

            if (header.polyCount == 0)
            {
                continue;
            }

            tileCount++;

            if (header.layer > 0)
            {
                if (context != null)
                {
                    context.LogError(
                        "Target navigation mesh contains layered tiles. (Not supported.)", this);
                }
                return(false);
            }
        }

        if (tileCount < 2)
        {
            if (context != null)
            {
                context.LogError(
                    "Target navigation mesh is either not tiled or has no tiles loaded.", this);
            }
            return(false);
        }

        return(true);
    }
Ejemplo n.º 16
0
		/** Generate connections between the two tiles.
		 * The tiles must be adjacent.
		 */
		void ConnectTiles (NavmeshTile tile1, NavmeshTile tile2) {
			if (tile1 == null) return;//throw new System.ArgumentNullException ("tile1");
			if (tile2 == null) return;//throw new System.ArgumentNullException ("tile2");
			
			if (tile1.nodes == null) throw new System.ArgumentException ("tile1 does not contain any nodes");
			if (tile2.nodes == null) throw new System.ArgumentException ("tile2 does not contain any nodes");
			
			int t1x = Mathf.Clamp(tile2.x,tile1.x,tile1.x+tile1.w-1);
			int t2x = Mathf.Clamp(tile1.x,tile2.x,tile2.x+tile2.w-1);
			int t1z = Mathf.Clamp(tile2.z,tile1.z,tile1.z+tile1.d-1);
			int t2z = Mathf.Clamp(tile1.z,tile2.z,tile2.z+tile2.d-1);
			
			int coord, altcoord;
			int t1coord, t2coord;
			
			float tcs;
			
			if (t1x == t2x) {
				coord = 2;
				altcoord = 0;
				t1coord = t1z;
				t2coord = t2z;
				tcs = tileSizeZ*cellSize;
			} else if (t1z == t2z) {
				coord = 0;
				altcoord = 2;
				t1coord = t1x;
				t2coord = t2x;
				tcs = tileSizeX*cellSize;
			} else {
				throw new System.ArgumentException ("Tiles are not adjacent (neither x or z coordinates match)");
			}
			
			if (System.Math.Abs (t1coord-t2coord) != 1) {
							
				Debug.Log (tile1.x + " " + tile1.z + " " + tile1.w + " " + tile1.d + "\n"+
				tile2.x + " " + tile2.z + " " + tile2.w + " " + tile2.d+"\n"+
				t1x + " " + t1z + " " + t2x + " " + t2z);
				throw new System.ArgumentException ("Tiles are not adjacent (tile coordinates must differ by exactly 1. Got '" + t1coord + "' and '" + t2coord + "')");
			}
			
			//Midpoint between the two tiles
			int midpoint = (int)System.Math.Round ((System.Math.Max(t1coord, t2coord) * tcs + forcedBounds.min[coord]) * Int3.Precision);
			
#if ASTARDEBUG
			Vector3 v1 = new Vector3(-100,0,-100);
			Vector3 v2 = new Vector3(100,0,100);
			v1[coord] = midpoint*Int3.PrecisionFactor;
			v2[coord] = midpoint*Int3.PrecisionFactor;
			
			Debug.DrawLine (v1,v2,Color.magenta);
#endif
			
			TriangleMeshNode[] nodes1 = tile1.nodes;
			TriangleMeshNode[] nodes2 = tile2.nodes;
			
			//Find adjacent nodes on the border between the tiles
			for (int i=0;i<nodes1.Length;i++) {
				TriangleMeshNode node = nodes1[i];
				int av = node.GetVertexCount ();
				
				for (int a=0;a<av;a++) {
					Int3 ap1 = node.GetVertex (a);
					Int3 ap2 = node.GetVertex ((a+1) % av);
					if (System.Math.Abs(ap1[coord] - midpoint) < 2 && System.Math.Abs (ap2[coord] - midpoint) < 2) {
#if ASTARDEBUG
						Debug.DrawLine ((Vector3)ap1, (Vector3)ap2, Color.red);
#endif
						
						int minalt = System.Math.Min (ap1[altcoord], ap2[altcoord]);
						int maxalt = System.Math.Max (ap1[altcoord], ap2[altcoord]);
						
						//Degenerate edge
						if (minalt == maxalt) continue;
						
						for (int j=0;j<nodes2.Length;j++) {
							TriangleMeshNode other = nodes2[j];
							int bv = other.GetVertexCount ();
							for (int b=0;b<bv;b++) {
								Int3 bp1 = other.GetVertex(b);
								Int3 bp2 = other.GetVertex((b+1) % av);
								if(System.Math.Abs(bp1[coord] - midpoint) < 2 && System.Math.Abs(bp2[coord] - midpoint) < 2) {
									
									int minalt2 = System.Math.Min (bp1[altcoord], bp2[altcoord]);
									int maxalt2 = System.Math.Max (bp1[altcoord], bp2[altcoord]);
									
									//Degenerate edge
									if (minalt2 == maxalt2) continue;
									
									if (maxalt > minalt2 && minalt < maxalt2) {
										
										//Adjacent
										
										//Test shortest distance between the segments (first test if they are equal since that is much faster)
										if ((ap1 == bp1 && ap2 == bp2) || (ap1 == bp2 && ap2 == bp1) ||
											Polygon.DistanceSegmentSegment3D ((Vector3)ap1, (Vector3)ap2, (Vector3)bp1, (Vector3)bp2) < walkableClimb*walkableClimb) {
											
											uint cost = (uint)(node.position - other.position).costMagnitude;
											
											node.AddConnection (other, cost);
											other.AddConnection (node, cost);
										}
									}
								}
							}
						}
							
					}
				}
			}
		}
Ejemplo n.º 17
0
		/** Create a tile at tile index \a x , \a z from the mesh.
		 * \warning This implementation is not thread safe. It uses cached variables to improve performance
		 */
		NavmeshTile CreateTile (Voxelize vox, VoxelMesh mesh, int x, int z) {
			
			if (mesh.tris == null) throw new System.ArgumentNullException ("The mesh must be valid. tris is null.");
			if (mesh.verts == null) throw new System.ArgumentNullException ("The mesh must be valid. verts is null.");
			
			//Create a new navmesh tile and assign its settings
			NavmeshTile tile = new NavmeshTile();
			
			tile.x = x;
			tile.z = z;
			tile.w = 1;
			tile.d = 1;
			tile.tris = mesh.tris;
			tile.verts = mesh.verts;
			tile.bbTree = new BBTree(tile);
			
			if (tile.tris.Length % 3 != 0) throw new System.ArgumentException ("Indices array's length must be a multiple of 3 (mesh.tris)");
			
			if (tile.verts.Length >= VertexIndexMask) throw new System.ArgumentException ("Too many vertices per tile (more than "+VertexIndexMask+")." +
				"\nTry enabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* Inspector");
			
			//Dictionary<Int3, int> firstVerts = new Dictionary<Int3, int> ();
			Dictionary<Int3, int> firstVerts = cachedInt3_int_dict;
			firstVerts.Clear();
			
			int[] compressedPointers = new int[tile.verts.Length];
			
			int count = 0;
			for (int i=0;i<tile.verts.Length;i++) {
				try {
					firstVerts.Add (tile.verts[i], count);
					compressedPointers[i] = count;
					tile.verts[count] = tile.verts[i];
					count++;
				} catch {
					//There are some cases, rare but still there, that vertices are identical
					compressedPointers[i] = firstVerts[tile.verts[i]];
				}
			}
			
			for (int i=0;i<tile.tris.Length;i++) {
				tile.tris[i] = compressedPointers[tile.tris[i]];
			}
			
			Int3[] compressed = new Int3[count];
			for (int i=0;i<count;i++) compressed[i] = tile.verts[i];
			
			tile.verts = compressed;
			
			TriangleMeshNode[] nodes = new TriangleMeshNode[tile.tris.Length/3];
			tile.nodes = nodes;
			
			//Here we are faking a new graph
			//The tile is not added to any graphs yet, but to get the position querys from the nodes
			//to work correctly (not throw exceptions because the tile is not calculated) we fake a new graph
			//and direct the position queries directly to the tile
			int graphIndex = AstarPath.active.astarData.graphs.Length;
			
			TriangleMeshNode.SetNavmeshHolder (graphIndex, tile);
			
			//This index will be ORed to the triangle indices
			int tileIndex = x + z*tileXCount;
			tileIndex <<= TileIndexOffset;
			
			//Create nodes and assign triangle indices
			for (int i=0;i<nodes.Length;i++) {
				TriangleMeshNode node = new TriangleMeshNode(active);
				nodes[i] = node;
				node.GraphIndex = (uint)graphIndex;
				node.v0 = tile.tris[i*3+0] | tileIndex;
				node.v1 = tile.tris[i*3+1] | tileIndex;
				node.v2 = tile.tris[i*3+2] | tileIndex;
				
				//Degenerate triangles might ocurr, but they will not cause any large troubles anymore
				//if (Polygon.IsColinear (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
				//	Debug.Log ("COLINEAR!!!!!!");
				//}
				
				//Make sure the triangle is clockwise
				if (!Polygon.IsClockwise (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
					int tmp = node.v0;
					node.v0 = node.v2;
					node.v2 = tmp;
				}
				
				node.Walkable = true;
				node.Penalty = initialPenalty;
				node.UpdatePositionFromVertices();
				tile.bbTree.Insert (node);
			}
			
			CreateNodeConnections (tile.nodes);
			
			//Remove the fake graph
			TriangleMeshNode.SetNavmeshHolder (graphIndex, null);
			
			return tile;
		}
Ejemplo n.º 18
0
		public override void DeserializeExtraInfo (GraphSerializationContext ctx) {
			//NavMeshGraph.DeserializeMeshNodes (this,nodes,bytes);
			
			System.IO.BinaryReader reader = ctx.reader;
			
			tileXCount = reader.ReadInt32();
			
			if (tileXCount < 0) return;
				
			tileZCount = reader.ReadInt32();
			
			tiles = new NavmeshTile[tileXCount * tileZCount];
			
			//Make sure mesh nodes can reference this graph
			TriangleMeshNode.SetNavmeshHolder (ctx.graphIndex, this);
			
			for (int z=0;z<tileZCount;z++) {
				for (int x=0;x<tileXCount;x++) {
					
					int tileIndex = x + z*tileXCount;
					int tx = reader.ReadInt32();
					if (tx < 0) throw new System.Exception ("Invalid tile coordinates (x < 0)");
					
					int tz = reader.ReadInt32();
					if (tz < 0) throw new System.Exception ("Invalid tile coordinates (z < 0)");
					
					// This is not the origin of a large tile. Refer back to that tile.
					if (tx != x || tz != z) {
						tiles[tileIndex] = tiles[tz*tileXCount + tx];
						continue;
					}
					
					NavmeshTile tile = new NavmeshTile ();
					
					tile.x = tx;
					tile.z = tz;
					tile.w = reader.ReadInt32();
					tile.d = reader.ReadInt32();
					tile.bbTree = new BBTree (tile);
					
					tiles[tileIndex] = tile;
					
					int trisCount = reader.ReadInt32 ();
					
					if (trisCount % 3 != 0) throw new System.Exception ("Corrupt data. Triangle indices count must be divisable by 3. Got " + trisCount);
					
					tile.tris = new int[trisCount];
					for (int i=0;i<tile.tris.Length;i++) tile.tris[i] = reader.ReadInt32();
					
					tile.verts = new Int3[reader.ReadInt32()];
					for (int i=0;i<tile.verts.Length;i++) {
						tile.verts[i] = new Int3 (reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32());
					}
					
					int nodeCount = reader.ReadInt32();
					tile.nodes = new TriangleMeshNode[nodeCount];
					
					//Prepare for storing in vertex indices
					tileIndex <<= TileIndexOffset;
					
					for (int i=0;i<tile.nodes.Length;i++) {
						TriangleMeshNode node = new TriangleMeshNode (active);
						tile.nodes[i] = node;
						node.GraphIndex = (uint)ctx.graphIndex;
						
						node.DeserializeNode (ctx);
						node.v0 = tile.tris[i*3+0] | tileIndex;
						node.v1 = tile.tris[i*3+1] | tileIndex;
						node.v2 = tile.tris[i*3+2] | tileIndex;
						node.UpdatePositionFromVertices();
						
						tile.bbTree.Insert (node);
					}
				}
			}
		}
Ejemplo n.º 19
0
    public void CreateQuery(float fMoveSpeed, float fTurnSpeed)
    {
        this.mTurnSpeed = fTurnSpeed;
        this.mMoveSpeed = fMoveSpeed;
        NavStatus status = NavmeshQuery.Create(navmesh, mMaxQueryNodes, out query);

        if ((status & NavStatus.Sucess) == 0)
        {
            Debug.LogError(
                fileName + ": Aborted initialization. Failed query creation: " + status.ToString());
            mCrowdManager = null;
            return;
        }

        mCrowdManager = CrowdManager.Create(mMaxCrowdAgents, mMaxAgentRadius, navmesh);
        if (mCrowdManager == null)
        {
            Debug.LogError(fileName + ": Aborted initialization. Failed crowd creation.");
        }

        CrowdAvoidanceParams mCrowdParam = CrowdAvoidanceParams.CreateStandardMedium();

        mCrowdManager.SetAvoidanceConfig(0, mCrowdParam);
        mCrowdAgentParams = new CrowdAgentParams();
        mCrowdAgentParams.avoidanceType       = 0;
        mCrowdAgentParams.collisionQueryRange = 3.2f;
        mCrowdAgentParams.height                = 1.8f;
        mCrowdAgentParams.maxAcceleration       = 8.0f;
        mCrowdAgentParams.maxSpeed              = this.mMoveSpeed;
        mCrowdAgentParams.pathOptimizationRange = 12.0f;
        mCrowdAgentParams.radius                = 1.0f;
        mCrowdAgentParams.separationWeight      = 2.0f;
        mCrowdAgentParams.updateFlags           = CrowdUpdateFlags.AnticipateTurns | CrowdUpdateFlags.ObstacleAvoidance | CrowdUpdateFlags.CrowdSeparation | CrowdUpdateFlags.OptimizeVis | CrowdUpdateFlags.OptimizeTopo;

        polyResult        = new uint[300];
        pointResult       = new Vector3[300];
        tileBufferPoints  = new Vector3[3000];
        pointResultBuffer = new Vector3[300];
        polyResultBuffer  = new uint[300];
        NavmeshTile tile  = navmesh.GetTile(0);
        int         count = tile.GetVerts(tileBufferPoints);

        Debug.Log("Tile " + tile.GetTileRef() + " count:" + count);
        if (count > 3000)
        {
            tileBufferPoints = new Vector3[count];
        }
        tileBufferRef = -1;

        //NavmeshPoly[] polys=new NavmeshPoly[3000];
        //int polyCount;
        //polyCount=tile.GetPolys(polys);
        //for (int i = 0; i < polyCount; i++)
        //{
        //    NavmeshPoly poly = polys[i];
        //    //if (poly.Type == NavmeshPolyType.OffMeshConnection)
        //    {
        //        Debug.Log("Poly" + i+"type"+poly.Type.ToString());
        //    }
        //}
    }