Exemplo n.º 1
0
        private void OnFloorWithDynamicObjectsChanged()
        {
            FloorWithDynamicObjects.CalculateConstrainedEdges();
            NavigationMesh.Initialize(FloorWithDynamicObjects);
            Pathfinding = new AStar(NavigationMesh, FloorWithDynamicObjects);

            foreach (var unit in AllUnits)
            {
                unit.OnPathRecalculationNeeded();
            }
        }
Exemplo n.º 2
0
            protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext)
            {
                var intermediateDataId = ComputeAssetIntermediateDataId();

                // Build cache items to build incrementally
                currentBuild = new NavigationMeshCachedBuild();
                oldBuild     = LoadIntermediateData(intermediateDataId);

                // The output object of the compilation
                NavigationMesh generatedNavigationMesh = new NavigationMesh();

                // No scene specified, result in failure
                if (asset.Scene == null)
                {
                    return(Task.FromResult(ResultStatus.Failed));
                }

                if (asset.AutoGenerateBoundingBox)
                {
                    generateBoundingBox = true;
                    globalBoundingBox   = BoundingBox.Empty;
                }
                else
                {
                    generateBoundingBox = false;
                    globalBoundingBox   = asset.BoundingBox;
                }

                // Copy build settings so we can modify them
                buildSettings = asset.BuildSettings;

                // Check for tile size
                if (buildSettings.TileSize <= 0)
                {
                    return(Task.FromResult(ResultStatus.Failed));
                }

                // Clone scene, obtain hash and load collider shape assets
                EnsureClonedSceneAndHash();
                if (clonedSceneAsset == null)
                {
                    return(Task.FromResult(ResultStatus.Failed));
                }

                // This collects all the input geometry, calculates the modified areas and calculates the scene bounds
                CollectInputGeometry();
                List <BoundingBox> removedAreas = oldBuild?.GetRemovedAreas(sceneEntities);

                BoundingBox boundingBox = globalBoundingBox;

                // Can't generate when no bounding box or and invalid bounding box is specified
                // this means that either the user specified bounding box is wrong or the scene does not contain any colliders
                if (boundingBox.Extent.X > 0 && boundingBox.Extent.Y > 0 && boundingBox.Extent.Z > 0)
                {
                    // Turn generated data into arrays
                    Vector3[] meshVertices = sceneNavigationMeshInputBuilder.Points.ToArray();
                    int[]     meshIndices  = sceneNavigationMeshInputBuilder.Indices.ToArray();

                    // NOTE: Reversed winding order as input to recast
                    int numSrcTriangles = meshIndices.Length / 3;
                    for (int i = 0; i < numSrcTriangles; i++)
                    {
                        int j = meshIndices[i * 3 + 1];
                        meshIndices[i * 3 + 1] = meshIndices[i * 3 + 2];
                        meshIndices[i * 3 + 2] = j;
                    }

                    // Check if settings changed to trigger a full rebuild
                    int currentSettingsHash = asset.GetHashCode();
                    currentBuild.SettingsHash = currentSettingsHash;
                    if (oldBuild != null && oldBuild.SettingsHash != currentBuild.SettingsHash)
                    {
                        fullRebuild = true;
                    }

                    if (oldBuild != null && !fullRebuild)
                    {
                        // Perform incremental build on old navigation mesh
                        generatedNavigationMesh = oldBuild.NavigationMesh;
                    }

                    // Initialize navigation mesh for building
                    generatedNavigationMesh.Initialize(buildSettings, asset.NavigationMeshAgentSettings.ToArray());

                    // Set the new navigation mesh in the current build
                    currentBuild.NavigationMesh = generatedNavigationMesh;

                    // Generate all the layers corresponding to the various agent settings
                    for (int layer = 0; layer < asset.NavigationMeshAgentSettings.Count; layer++)
                    {
                        Stopwatch layerBuildTimer = new Stopwatch();
                        layerBuildTimer.Start();
                        var agentSetting = asset.NavigationMeshAgentSettings[layer];

                        // Flag tiles to build for this specific layer
                        HashSet <Point> tilesToBuild = new HashSet <Point>();
                        if (fullRebuild)
                        {
                            // For full rebuild just take the root bounding box for selecting tiles to build
                            List <Point> newTileList = NavigationMeshBuildUtils.GetOverlappingTiles(buildSettings, boundingBox);
                            foreach (Point p in newTileList)
                            {
                                tilesToBuild.Add(p);
                            }
                        }
                        else
                        {
                            // Apply an offset so their neighbouring tiles which are affected by the agent radius also get rebuild
                            Vector3 agentOffset = new Vector3(agentSetting.Radius, 0, agentSetting.Radius);
                            if (removedAreas != null)
                            {
                                updatedAreas.AddRange(removedAreas);
                            }
                            foreach (var update in updatedAreas)
                            {
                                BoundingBox agentSpecificBoundingBox = new BoundingBox
                                {
                                    Minimum = update.Minimum - agentOffset,
                                    Maximum = update.Maximum + agentOffset,
                                };
                                List <Point> newTileList = NavigationMeshBuildUtils.GetOverlappingTiles(buildSettings, agentSpecificBoundingBox);
                                foreach (Point p in newTileList)
                                {
                                    tilesToBuild.Add(p);
                                }
                            }
                        }

                        // Build tiles
                        foreach (var tileToBuild in tilesToBuild)
                        {
                            BoundingBox tileBoundingBox = NavigationMeshBuildUtils.ClampBoundingBoxToTile(buildSettings, boundingBox, tileToBuild);
                            // Check if tile bounding box is contained withing the navigation mesh bounding box
                            if (boundingBox.Contains(ref tileBoundingBox) == ContainmentType.Disjoint)
                            {
                                // Remove this tile
                                generatedNavigationMesh.Layers[layer].RemoveLayerTile(tileToBuild);
                                continue;
                            }

                            // Build the tile for the current layer being processed
                            generatedNavigationMesh.Layers[layer].BuildTile(meshVertices.ToArray(), meshIndices.ToArray(), tileBoundingBox, tileToBuild);
                        }
                    }
                }

                // Store used bounding box in navigation mesh
                generatedNavigationMesh.BoundingBox = boundingBox;

                contentManager.Save(assetUrl, generatedNavigationMesh);
                SaveIntermediateData(intermediateDataId, currentBuild);

                return(Task.FromResult(ResultStatus.Successful));
            }