public void AddNode(NavMeshNode node, bool skipAABBUpdate) { bool boundingBoxUpdateNeeded = false; if (node.VertexTopLeft < minNodeValue || minNodeValue == SizeInvalid) { minNodeValue = node.VertexTopLeft; boundingBoxUpdateNeeded = true; } if (node.VertexTopLeft > maxNodeValue || maxNodeValue == SizeInvalid) { maxNodeValue = node.VertexTopLeft; boundingBoxUpdateNeeded = true; } if (!skipAABBUpdate && boundingBoxUpdateNeeded) { boundingBox.Min = this.parent.TerrainComp.VertexList[minNodeValue].Position; boundingBox.Min.Y = 0.0f; NavMeshNode maxNode; meshNodes.TryGetValue(maxNodeValue, out maxNode); if (maxNode != null) { boundingBox.Max = this.parent.TerrainComp.VertexList[maxNode.VertexBottomRight].Position; boundingBox.Max.Y = 1000.0f; } } meshNodes.Add(node.VertexTopLeft, node); }
public void GenerateNavMesh(BaseEntity terrain) { this.terrain = terrain; this.terrainComp = this.terrain.GetComponentByType(ComponentType.TerrainComponent) as TerrainComponent; // Process each pixel of the heightmap as a navmeshnode. // Create a navmeshnode, even if the slope is too great. int width = this.terrainComp.Size; int widthMinusOne = width - 1; // Find four vertexs that comprise a node for (int x = 0; x < widthMinusOne; ++x) { for (int z = 0; z < widthMinusOne; ++z) { NavMeshNode newNode = new NavMeshNode((x + (z * width)), width); // Grab the normal of the quad that makes up this NavMeshNode, because the terrain engine organizes triangles into // quads, we don't need to check both triangles in the quad, as they'll have the same normal. So, any corner of the // quad will have the same normal, we'll just take the topleft corner's normal. newNode.Normal = this.terrainComp.normals[newNode.ZCoordTopLeft, newNode.XCoordTopLeft]; nodeDictionary.Add(newNode.VertexTopLeft, newNode); } } // Postprocess step, optimize navmesh by combining navmeshnodes into navmeshchunks. for (int x = 0; x < widthMinusOne; ++x) { for (int z = 0; z < widthMinusOne; ++z) { int topLeftVertex = x + (z * width); // Check if there is a node at this [x, z] location, if there isn't then it has already // been processed into a chunk if (nodeDictionary.ContainsKey(topLeftVertex)) { NavMeshNode node; nodeDictionary.TryGetValue(topLeftVertex, out node); if (node != null) { NavMeshChunk newChunk = new NavMeshChunk(this.parent); ProcessNewChunk(newChunk, node); } else { throw new Exception("Failed to find a value in 'nodeDictionary'"); } } } } // Once all chunks are created, we need to go through each chunk, and create a list of connection points between chunks so we know how // to navigate from chunk to chunk. meshGenerated = true; }
public void RemoveNode(NavMeshNode node) { if (meshNodes.Count == 0) { return; } meshNodes.Remove(node.VertexTopLeft); if (node.VertexTopLeft == minNodeValue || node.VertexTopLeft == maxNodeValue) { // We need to find the new lowest and highest values before RemoveNode() will function properly //minNodeValue = meshNodes.Keys.Min(); //maxNodeValue = meshNodes.Keys.Max(); UpdateAABB(); } }
private void ProcessNewChunk(NavMeshChunk chunk, NavMeshNode startingNode) { bool columnsAvail = true; bool rowsAvail = true; chunk.AddNode(startingNode, true); chunkDictionary.Add(startingNode.VertexTopLeft, chunk); nodeDictionary.Remove(startingNode.VertexTopLeft); if (startingNode.TooSteep) { return; } //// TEMP!!!!!!!!!!!!!!!!!!!! //if (startingNode.VertexTopLeft == 0) //{ // int i = 5; // i++; //} while (columnsAvail || rowsAvail) { if (columnsAvail) { columnsAvail = AddNewColumnToChunk(chunk); } if (rowsAvail) { rowsAvail = AddNewRowToChunk(chunk); } } // Once we've made it here, that means the current chunk cannot expand any more }