Beispiel #1
0
        private void DynamicNavigationMeshSystemOnNavigationMeshUpdatedUpdated(object sender, NavigationMeshUpdatedEventArgs eventArgs)
        {
            var newNavigationMesh = eventArgs.BuildResult.NavigationMesh;
            NavigationMeshData data;

            if (eventArgs.OldNavigationMesh != null && loadedNavigationMeshes.TryGetValue(eventArgs.OldNavigationMesh, out data))
            {
                // Move to new navigation mesh
                loadedNavigationMeshes.Remove(eventArgs.OldNavigationMesh);
                loadedNavigationMeshes.Add(newNavigationMesh, data);

                data.NavigationMesh = newNavigationMesh;

                // Replace tiles in recast navigation mesh for all loaded groups
                var updatedLayers = eventArgs.BuildResult.UpdatedLayers.ToDictionary(x => x.GroupId);
                var oldGroupKeys  = data.LoadedGroups.Keys.ToList();
                foreach (var oldGroupKey in oldGroupKeys)
                {
                    var loadedGroup = data.LoadedGroups[oldGroupKey];

                    // See if this layer was updated
                    NavigationMeshLayerUpdateInfo layerUpdateInfo;
                    if (!updatedLayers.TryGetValue(oldGroupKey, out layerUpdateInfo))
                    {
                        continue;
                    }

                    // Check if the new navigation mesh contains this layer
                    //  if it does not, that means it was removed completely and we
                    //  will remove all the loaded tiles in the loop below
                    NavigationMeshLayer newLayer = null;
                    newNavigationMesh.Layers.TryGetValue(oldGroupKey, out newLayer);

                    foreach (var updatedTileCoord in layerUpdateInfo.UpdatedTiles)
                    {
                        NavigationMeshTile newTile = null;
                        if (newLayer != null)
                        {
                            if (!newLayer.Tiles.TryGetValue(updatedTileCoord, out newTile))
                            {
                                continue;
                            }
                        }

                        // Either add the tile if it is contained in the new navigation mesh or
                        //  try to remove it if it does not
                        if (newTile != null)
                        {
                            loadedGroup.RecastNavigationMesh.AddOrReplaceTile(newTile.Data);
                        }
                        else
                        {
                            loadedGroup.RecastNavigationMesh.RemoveTile(updatedTileCoord);
                        }
                    }
                }
            }

            // Update loaded navigation meshes for components that are useing it,
            //  in case a group was added
            var componentsToUpdate = ComponentDatas.Values.Where(x => x.Component.NavigationMesh == null).ToArray();

            foreach (var component in componentsToUpdate)
            {
                UpdateNavigationMesh(component);
            }
        }
Beispiel #2
0
        private NavigationMeshDebugVisual CreateDebugVisual(NavigationMesh navigationMesh, NavigationMesh previousNavigationMesh)
        {
            NavigationMeshDebugVisual ret = new NavigationMeshDebugVisual();

            ret.DebugEntity = new Entity($"Debug entity for navigation mesh");

            // Create a visual for every layer with a separate color
            using (var layers = navigationMesh.Layers.GetEnumerator())
            {
                while (layers.MoveNext())
                {
                    Model model = new Model();

                    var currentLayer = layers.Current.Value;
                    var currentId    = layers.Current.Key;

                    NavigationMeshDisplayGroup displayGroup;
                    if (!groupDisplaySettings.TryGetValue(currentId, out displayGroup))
                    {
                        continue; // No display settings for this group
                    }
                    model.Add(displayGroup.Material);
                    model.Add(displayGroup.HighlightMaterial);

                    foreach (var p in currentLayer.Tiles)
                    {
                        bool updated = true;

                        NavigationMeshTile tile = p.Value;

                        // Extract vertex data
                        List <Vector3> tileVertexList = new List <Vector3>();
                        List <int>     tileIndexList  = new List <int>();
                        if (!tile.GetTileVertices(tileVertexList, tileIndexList))
                        {
                            continue;
                        }

                        // Check if updated
                        NavigationMeshLayer sourceLayer;
                        if (previousNavigationMesh != null && previousNavigationMesh.Layers.TryGetValue(currentId, out sourceLayer))
                        {
                            NavigationMeshTile oldTile = sourceLayer.FindTile(p.Key);
                            if (oldTile != null && oldTile.Data.SequenceEqual(tile.Data))
                            {
                                updated = false;
                            }
                        }

                        // Stack layers vertically
                        Vector3 offset = new Vector3(0.0f, LayerHeightMultiplier * displayGroup.Index, 0.0f);

                        // Calculate mesh bounding box from navigation mesh points
                        BoundingBox bb = BoundingBox.Empty;

                        List <VertexPositionNormalTexture> meshVertices = new List <VertexPositionNormalTexture>();
                        for (int i = 0; i < tileVertexList.Count; i++)
                        {
                            Vector3 position = tileVertexList[i] + offset;
                            BoundingBox.Merge(ref bb, ref position, out bb);

                            VertexPositionNormalTexture vert = new VertexPositionNormalTexture();
                            vert.Position          = position;
                            vert.Normal            = Vector3.UnitY;
                            vert.TextureCoordinate = new Vector2(0.5f, 0.5f);
                            meshVertices.Add(vert);
                        }

                        MeshDraw draw;
                        using (var meshData = new GeometricMeshData <VertexPositionNormalTexture>(meshVertices.ToArray(), tileIndexList.ToArray(), true))
                        {
                            GeometricPrimitive primitive = new GeometricPrimitive(game.GraphicsDevice, meshData);
                            ret.GeneratedDynamicPrimitives.Add(primitive);
                            draw = primitive.ToMeshDraw();
                        }

                        Mesh mesh = new Mesh
                        {
                            Draw          = draw,
                            MaterialIndex = updated ? 1 : 0,
                            BoundingBox   = bb
                        };
                        model.Add(mesh);
                    }

                    // Create an entity per layer
                    var layerEntity = new Entity($"Navigation group {currentId}");

                    // Add a new model component
                    var modelComponent = new ModelComponent(model);
                    layerEntity.Add(modelComponent);
                    modelComponent.Enabled = displayGroup.IsVisible;
                    ret.ModelComponents.Add(currentId, modelComponent);

                    ret.DebugEntity.AddChild(layerEntity);
                }
            }

            return(ret);
        }
        /// <summary>
        /// Builds a single tile for a given layer without adding it
        /// </summary>
        /// <param name="inputVertices">Input vertex data for the input mesh</param>
        /// <param name="inputIndices">Input index data for the input mesh</param>
        /// <param name="boundingBox">Bounding box of the tile</param>
        /// <param name="tileCoordinate">Tile coordinate to of the tile to build</param>
        /// <returns>Teh tile that was built</returns>
        private unsafe NavigationMeshTile BuildTileInternal(Vector3[] inputVertices, int[] inputIndices,
            BoundingBox boundingBox, Point tileCoordinate)
        {
            // Turn settings into native structure format
            NavigationAgentSettings agentSettings = AgentSettings;
            NavigationMeshTile tile = new NavigationMeshTile();

            // Initialize navigation builder
            IntPtr nav = Navigation.CreateBuilder();

            // Turn build settings into native structure format
            Navigation.BuildSettings internalBuildSettings = new Navigation.BuildSettings
            {
                // Tile settings
                BoundingBox = boundingBox,
                TilePosition = tileCoordinate,
                TileSize = BuildSettings.TileSize,

                // General build settings
                CellHeight = BuildSettings.CellHeight,
                CellSize = BuildSettings.CellSize,
                RegionMinArea = BuildSettings.MinRegionArea,
                RegionMergeArea = BuildSettings.RegionMergeArea,
                EdgeMaxLen = BuildSettings.MaxEdgeLen,
                EdgeMaxError = BuildSettings.MaxEdgeError,
                DetailSampleDist = BuildSettings.DetailSamplingDistance,
                DetailSampleMaxError = BuildSettings.MaxDetailSamplingError,

                // Agent settings
                AgentHeight = agentSettings.Height,
                AgentRadius = agentSettings.Radius,
                AgentMaxClimb = agentSettings.MaxClimb,
                AgentMaxSlope = agentSettings.MaxSlope.Degrees
            };
            Navigation.SetSettings(nav, new IntPtr(&internalBuildSettings));

            // Generate mesh
            Navigation.GeneratedData data;
            IntPtr ret = Navigation.Build(nav, inputVertices.ToArray(), inputVertices.Length, inputIndices.ToArray(), inputIndices.Length);
            Navigation.GeneratedData* dataPtr = (Navigation.GeneratedData*)ret;
            data = *dataPtr;

            // Copy output data on success
            if (data.Success)
            {
                List<Vector3> outputVerts = new List<Vector3>();
                if (data.NumNavmeshVertices > 0)
                {
                    Vector3* navmeshVerts = (Vector3*)data.NavmeshVertices;
                    for (int j = 0; j < data.NumNavmeshVertices; j++)
                    {
                        outputVerts.Add(navmeshVerts[j]);
                    }

                    tile.MeshVertices = outputVerts.ToArray();
                }

                // Copy the generated navigationMesh data
                tile.Data = new byte[data.NavmeshDataLength];
                Marshal.Copy(data.NavmeshData, tile.Data, 0, data.NavmeshDataLength);
            }

            // Cleanup builder
            Navigation.DestroyBuilder(nav);

            return tile;
        }