コード例 #1
0
        public void PlaceObjects(Level level, int amount)
        {
            objectGrid = new List <LevelObject> [
                level.Size.X / GridSize,
                (level.Size.Y - level.BottomPos) / GridSize];

            List <SpawnPosition> availableSpawnPositions = new List <SpawnPosition>();
            var levelCells = level.GetAllCells();

            availableSpawnPositions.AddRange(GetAvailableSpawnPositions(levelCells, LevelObjectPrefab.SpawnPosType.Wall));
            availableSpawnPositions.AddRange(GetAvailableSpawnPositions(level.SeaFloor.Cells, LevelObjectPrefab.SpawnPosType.SeaFloor));

            foreach (Structure structure in Structure.WallList)
            {
                if (!structure.HasBody || structure.HiddenInGame)
                {
                    continue;
                }
                if (level.Ruins.Any(r => r.Submarine == structure.Submarine))
                {
                    if (structure.IsHorizontal)
                    {
                        bool topHull    = Hull.FindHull(structure.WorldPosition + Vector2.UnitY * 64) != null;
                        bool bottomHull = Hull.FindHull(structure.WorldPosition - Vector2.UnitY * 64) != null;
                        if (topHull && bottomHull)
                        {
                            continue;
                        }

                        availableSpawnPositions.Add(new SpawnPosition(
                                                        new GraphEdge(new Vector2(structure.WorldRect.X, structure.WorldPosition.Y), new Vector2(structure.WorldRect.Right, structure.WorldPosition.Y)),
                                                        bottomHull ? Vector2.UnitY : -Vector2.UnitY,
                                                        LevelObjectPrefab.SpawnPosType.RuinWall,
                                                        bottomHull ? Alignment.Bottom : Alignment.Top));
                    }
                    else
                    {
                        bool rightHull = Hull.FindHull(structure.WorldPosition + Vector2.UnitX * 64) != null;
                        bool leftHull  = Hull.FindHull(structure.WorldPosition - Vector2.UnitX * 64) != null;
                        if (rightHull && leftHull)
                        {
                            continue;
                        }

                        availableSpawnPositions.Add(new SpawnPosition(
                                                        new GraphEdge(new Vector2(structure.WorldPosition.X, structure.WorldRect.Y), new Vector2(structure.WorldPosition.X, structure.WorldRect.Y - structure.WorldRect.Height)),
                                                        leftHull ? Vector2.UnitX : -Vector2.UnitX,
                                                        LevelObjectPrefab.SpawnPosType.RuinWall,
                                                        leftHull ? Alignment.Left : Alignment.Right));
                    }
                }
            }

            foreach (var posOfInterest in level.PositionsOfInterest)
            {
                if (posOfInterest.PositionType != Level.PositionType.MainPath && posOfInterest.PositionType != Level.PositionType.SidePath)
                {
                    continue;
                }

                availableSpawnPositions.Add(new SpawnPosition(
                                                new GraphEdge(posOfInterest.Position.ToVector2(), posOfInterest.Position.ToVector2() + Vector2.UnitX),
                                                Vector2.UnitY,
                                                LevelObjectPrefab.SpawnPosType.MainPath,
                                                Alignment.Top));
            }

            availableSpawnPositions.Add(new SpawnPosition(
                                            new GraphEdge(level.StartPosition - Vector2.UnitX, level.StartPosition + Vector2.UnitX),
                                            -Vector2.UnitY, LevelObjectPrefab.SpawnPosType.LevelStart, Alignment.Top));
            availableSpawnPositions.Add(new SpawnPosition(
                                            new GraphEdge(level.EndPosition - Vector2.UnitX, level.EndPosition + Vector2.UnitX),
                                            -Vector2.UnitY, LevelObjectPrefab.SpawnPosType.LevelEnd, Alignment.Top));

            var availablePrefabs = new List <LevelObjectPrefab>(LevelObjectPrefab.List);

            objects           = new List <LevelObject>();
            updateableObjects = new List <LevelObject>();

            Dictionary <LevelObjectPrefab, List <SpawnPosition> > suitableSpawnPositions = new Dictionary <LevelObjectPrefab, List <SpawnPosition> >();
            Dictionary <LevelObjectPrefab, List <float> >         spawnPositionWeights   = new Dictionary <LevelObjectPrefab, List <float> >();

            for (int i = 0; i < amount; i++)
            {
                //get a random prefab and find a place to spawn it
                LevelObjectPrefab prefab = GetRandomPrefab(level.GenerationParams, availablePrefabs);
                if (prefab == null)
                {
                    continue;
                }
                if (!suitableSpawnPositions.ContainsKey(prefab))
                {
                    float minDistance = level.Size.X * 0.2f;

                    suitableSpawnPositions.Add(prefab,
                                               availableSpawnPositions.Where(sp =>
                                                                             sp.SpawnPosTypes.Any(type => prefab.SpawnPos.HasFlag(type)) &&
                                                                             sp.Length >= prefab.MinSurfaceWidth &&
                                                                             (prefab.AllowAtStart || !level.IsCloseToStart(sp.GraphEdge.Center, minDistance)) &&
                                                                             (prefab.AllowAtEnd || !level.IsCloseToEnd(sp.GraphEdge.Center, minDistance)) &&
                                                                             (sp.Alignment == Alignment.Any || prefab.Alignment.HasFlag(sp.Alignment))).ToList());

                    spawnPositionWeights.Add(prefab,
                                             suitableSpawnPositions[prefab].Select(sp => sp.GetSpawnProbability(prefab)).ToList());
                }

                SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.Server);
                if (spawnPosition == null && prefab.SpawnPos != LevelObjectPrefab.SpawnPosType.None)
                {
                    continue;
                }
                PlaceObject(prefab, spawnPosition, level);
                if (prefab.MaxCount < amount)
                {
                    if (objects.Count(o => o.Prefab == prefab) >= prefab.MaxCount)
                    {
                        availablePrefabs.Remove(prefab);
                    }
                }
            }

            foreach (Level.Cave cave in level.Caves)
            {
                availablePrefabs = new List <LevelObjectPrefab>(LevelObjectPrefab.List.FindAll(p => p.SpawnPos.HasFlag(LevelObjectPrefab.SpawnPosType.CaveWall)));
                availableSpawnPositions.Clear();
                suitableSpawnPositions.Clear();
                spawnPositionWeights.Clear();

                var caveCells = cave.Tunnels.SelectMany(t => t.Cells);
                List <VoronoiCell> caveWallCells = new List <VoronoiCell>();
                foreach (var edge in caveCells.SelectMany(c => c.Edges))
                {
                    if (!edge.NextToCave)
                    {
                        continue;
                    }
                    if (edge.Cell1?.CellType == CellType.Solid)
                    {
                        caveWallCells.Add(edge.Cell1);
                    }
                    if (edge.Cell2?.CellType == CellType.Solid)
                    {
                        caveWallCells.Add(edge.Cell2);
                    }
                }
                availableSpawnPositions.AddRange(GetAvailableSpawnPositions(caveWallCells.Distinct(), LevelObjectPrefab.SpawnPosType.CaveWall));

                for (int i = 0; i < cave.CaveGenerationParams.LevelObjectAmount; i++)
                {
                    //get a random prefab and find a place to spawn it
                    LevelObjectPrefab prefab = GetRandomPrefab(cave.CaveGenerationParams, availablePrefabs, requireCaveSpecificOverride: true);
                    if (prefab == null)
                    {
                        continue;
                    }
                    if (!suitableSpawnPositions.ContainsKey(prefab))
                    {
                        suitableSpawnPositions.Add(prefab,
                                                   availableSpawnPositions.Where(sp =>
                                                                                 sp.Length >= prefab.MinSurfaceWidth &&
                                                                                 (sp.Alignment == Alignment.Any || prefab.Alignment.HasFlag(sp.Alignment))).ToList());
                        spawnPositionWeights.Add(prefab,
                                                 suitableSpawnPositions[prefab].Select(sp => sp.GetSpawnProbability(prefab)).ToList());
                    }
                    SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.Server);
                    if (spawnPosition == null && prefab.SpawnPos != LevelObjectPrefab.SpawnPosType.None)
                    {
                        continue;
                    }
                    PlaceObject(prefab, spawnPosition, level, cave);
                    if (prefab.MaxCount < amount)
                    {
                        if (objects.Count(o => o.Prefab == prefab && o.ParentCave == cave) >= prefab.MaxCount)
                        {
                            availablePrefabs.Remove(prefab);
                        }
                    }
                }
            }
        }