Exemple #1
0
        void SetCellStateNow(Point p, bool state)
        {
            Point tp = ConnectedEdgesPosition(p);

            if (tp != Point.OutOfBounds)
            {
                if (state != GetCellState(tp))
                {
                    if (state)
                    {
                        cellsAlive++;
                    }
                    else
                    {
                        cellsAlive--;
                    }
                    cells[tp.x, tp.y] = state;
                    CellStateChanged?.Invoke(tp);
                }
            }
        }
Exemple #2
0
        public void OnCellStateChanged(CellStateChanged message)
        {
            // Get random generator based on world seed and cell location.
            var hasher = new Hasher();

            hasher.Write(message.Id).Write(WorldSeed);
            var random = new MersenneTwister(hasher.Value);

            if (message.IsSubCell)
            {
                if (message.IsActive)
                {
                    PopulateSubCell(message, random);
                }
            }
            else
            {
                if (message.IsActive)
                {
                    PopulateCell(message, random);
                }
                else
                {
                    // Remove cell info only if it does not deviate from the
                    // procedural values.
                    if (!_cellInfo[message.Id].Dirty)
                    {
                        _cellInfo.Remove(message.Id);
                    }
                    else
                    {
                        _cellInfo[message.Id].Stations.Clear();
                    }
                }
            }
        }
Exemple #3
0
        public void OnCellStateChanged(CellStateChanged message)
        {
            if (!message.IsSubCell)
            {
                return;
            }

            if (!message.IsActive)
            {
                _cellSpawns.RemoveAll(x => x.Item1 == message.Id);
            }
            else
            {
                _cellSpawns.Add(Tuple.Create(message.Id, 5));

                /*
                 * // Get the cell position.
                 * var position = CellSystem.GetSubCellCoordinatesFromId(message.Id);
                 *
                 * // Get the cell info to know what faction we're spawning for. Use the large cell id for that,
                 * // because we only store info for that.
                 * var cellInfo = ((UniverseSystem) Manager.GetSystem(UniverseSystem.TypeId))
                 *  .GetCellInfo(CellSystem.GetCellIdFromCoordinates(position));
                 *
                 * // The area covered by the cell.
                 * FarRectangle cellArea;
                 * cellArea.X = position.X;
                 * cellArea.Y = position.Y;
                 * cellArea.Width = CellSystem.SubCellSize;
                 * cellArea.Height = CellSystem.SubCellSize;
                 *
                 * // Get center point for spawn group.
                 * FarPosition spawnPoint;
                 * spawnPoint.X = _random.NextInt32((int) cellArea.Left, (int) cellArea.Right);
                 * spawnPoint.Y = _random.NextInt32((int) cellArea.Top, (int) cellArea.Bottom);
                 *
                 * // TODO number of groups based on cell/biome type
                 *
                 * // Configuration for spawned ships.
                 * string[] ships;
                 * ArtificialIntelligence.AIConfiguration[] configurations = null;
                 * var formation = SquadSystem.Formations.None;
                 *
                 * // TODO different groups, based on cell info? definable via editor maybe?
                 * if (_random.NextDouble() < 0.5f)
                 * {
                 *  ships = new[]
                 *  {
                 *      "L1_AI_Ship",
                 *      "L1_AI_Ship",
                 *      "L1_AI_Ship",
                 *      "L1_AI_Ship",
                 *      "L1_AI_Ship",
                 *      "L1_AI_Ship"
                 *  };
                 *  configurations = new[]
                 *  {
                 *      new ArtificialIntelligence.AIConfiguration
                 *      {
                 *          AggroRange = UnitConversion.ToSimulationUnits(600)
                 *      }
                 *  };
                 *  formation = SquadSystem.Formations.Block;
                 * }
                 * else
                 * {
                 *  ships = new[]
                 *  {
                 *      "L1_AI_Ship",
                 *      "L1_AI_Ship",
                 *      "L1_AI_Ship",
                 *      "L1_AI_Ship",
                 *      "L1_AI_Ship"
                 *  };
                 *  configurations = new[]
                 *  {
                 *      new ArtificialIntelligence.AIConfiguration
                 *      {
                 *          AggroRange = UnitConversion.ToSimulationUnits(800)
                 *      }
                 *  };
                 *  formation = SquadSystem.Formations.Vee;
                 * }
                 *
                 * // Generate spawns.
                 * for (var i = 0; i < 5; ++i)
                 * {
                 *  var entity = Manager.AddEntity();
                 *  var body = Manager.AddBody(
                 *      entity, type: Body.BodyType.Static, worldPosition: spawnPoint);
                 *  Manager.AttachCircle(
                 *      body,
                 *      UnitConversion.ToSimulationUnits(5000),
                 *      collisionCategory: Factions.Nature.ToCollisionGroup(),
                 *      collisionMask: Factions.Players.ToCollisionGroup(),
                 *      isSensor: true);
                 *
                 * }
                 */
            }
        }
Exemple #4
0
        private void PopulateSubCell(CellStateChanged message, IUniformRandom random)
        {
            // We randomly spawn some asteroid fields in sub-cells. These are laid out as follows:
            // - we decide how many fields we want to spawn.
            // - we build a grid inside the cell that has enough entries for our asteroid fields,
            //   i.e. we take the next higher squared number (e.g. if we have 5 fields, we generate
            //   a 3x3 grid).
            // - For each field we randomly pick one such grid cell to determine it's basic position,
            //   and shift it to a random position inside that grid cell.
            // - To position the actual asteroids, we want it to be somewhat circular, but it should
            //   not look too regular. We lay out our asteroids in a spiral, on which we place our
            //   asteroids in a fixed interval. Finally we add some random offset to make the spiral
            //   non-obvious.

            // Get content manager to fetch textures from which to generate physics models.
            var content = ((ContentSystem)Manager.GetSystem(ContentSystem.TypeId)).Content;

            // Number of asteroid fields in this cell?
            var fieldCount = random.NextInt32(8, 12);

            // Determine number of rows and cols for base positions.
            var cols = (int)Math.Ceiling(Math.Sqrt(fieldCount));

            // Build sampling list.
            var cells = new List <Tuple <int, int> >(cols * cols);

            for (var x = 0; x < cols; ++x)
            {
                for (var y = 0; y < cols; ++y)
                {
                    cells.Add(Tuple.Create(x, y));
                }
            }

            // Size of a cell in our sub grid.
            var gridSize = CellSystem.SubCellSize / (float)cols;

            // Cell top left corner position.
            var cellPosition = new FarPosition(message.X, message.Y) * CellSystem.SubCellSize;

            // Generate asteroid fields.
            for (var i = 0; i < fieldCount; ++i)
            {
                // Get base position.
                var positionIndex = random.NextInt32(cells.Count);
                var fieldIndex    = cells[positionIndex];
                cells.RemoveAt(positionIndex);

                var asteroidCount = random.NextInt32(30, 60);
                var center        = cellPosition + new FarPosition(
                    fieldIndex.Item1 * gridSize + (float)random.NextDouble(0, gridSize),
                    fieldIndex.Item2 * gridSize + (float)random.NextDouble(0, gridSize));

                // We grow our asteroid fields as spirals, with a little jitter.
                const float jitter     = 2.5f;
                const float radiusStep = 0.4f;  //< how fast we move outwards.
                const float angleStep  = 2.25f; //< the asteroid interval on the spiral.
                var         theta      = angleStep / radiusStep;

                // Create first one at the center.
                CreateAsteroid(center, random, content);

                // Generate rest of the spiral.
                for (var j = 1; j < asteroidCount; ++j)
                {
                    // Compute position in our spiral.
                    var radius   = radiusStep * theta;
                    var position = center;
                    position.X += (float)Math.Cos(theta) * radius;
                    position.Y += (float)Math.Sin(theta) * radius;
                    position.X += (float)random.NextDouble(-jitter / 2, jitter / 2);
                    position.Y += (float)random.NextDouble(-jitter / 2, jitter / 2);
                    theta      += angleStep / radius;

                    CreateAsteroid(position, random, content);
                }
            }

            //// Sprinkle some asteroids in the background, for depth and movement perception.
            //for (var i = 0; i < 1000; ++i)
            //{
            //    var center = cellPosition + new FarPosition(
            //        (float) random.NextDouble(0, CellSystem.SubCellSize),
            //        (float) random.NextDouble(0, CellSystem.SubCellSize));

            //    // Randomly scale and rotate it.
            //    var layer = (float) random.NextDouble(0.5f, 0.75f);
            //    var scale = (float) random.NextDouble(0.6f, 0.9f);
            //    var angle = (float) random.NextDouble() * MathHelper.TwoPi;

            //    // Determine shape for physics system.
            //    var textureName = "Textures/Asteroids/rock_" + random.NextInt32(1, 14);
            //    var texture = content.Load<Texture2D>(textureName);

            //    // Create component that will be rendered.
            //    var entity = Manager.AddEntity();
            //    Manager.AddComponent<Transform>(entity).Initialize(center, angle);

            //    // Expand bounds based on layer for camera and interpolation system, so that they
            //    // can see the asteroids in time (lower parallax = farther in background = moving
            //    // slower = longer in screen = wider actual viewport necessary to check).
            //    var width = UnitConversion.ToSimulationUnits(texture.Width);
            //    var height = UnitConversion.ToSimulationUnits(texture.Height);
            //    var diagonal = 8f * (float) Math.Sqrt(width * width + height * height) / layer / scale;
            //    var bounds = new FarRectangle(-diagonal / 2f, -diagonal / 2f, diagonal, diagonal);

            //    // Rendering stuff.
            //    Manager.AddComponent<Parallax>(entity).Initialize(layer);
            //    Manager.AddComponent<Indexable>(entity).Initialize(bounds, CameraSystem.IndexId);
            //    Manager.AddComponent<Indexable>(entity).Initialize(bounds, InterpolationSystem.IndexId);
            //    Manager.AddComponent<SimpleTextureDrawable>(entity).Initialize(textureName, new Color(100, 100, 100, 255), scale);

            //    // Auto removal.
            //    Manager.AddComponent<CellDeath>(entity).Initialize(true);
            //    Manager.AddComponent<Indexable>(entity).Initialize(CellSystem.CellDeathAutoRemoveIndexId);
            //}
        }
Exemple #5
0
        private void PopulateCell(CellStateChanged message, IUniformRandom random)
        {
            // Check if we have a changed cell info.
            if (!_cellInfo.ContainsKey(message.Id))
            {
                // No, generate the default one. Get an independent
                // randomizer to avoid different results in other
                // sampling operations from when we have an existing
                // cell info.
                var hasher = new Hasher();
                hasher.Write(message.Id).Write(WorldSeed);
                var independentRandom = new MersenneTwister(hasher.Value);

                // Figure out which faction should own this cell.
                Factions faction;
                switch (independentRandom.NextInt32(3))
                {
                case 0:
                    faction = Factions.NPCFactionA;
                    break;

                case 1:
                    faction = Factions.NPCFactionB;
                    break;

                default:
                    faction = Factions.NPCFactionC;
                    break;
                }

                // Figure out our tech level.
                // TODO make dependent on distance to center / start system.
                var techLevel = independentRandom.NextInt32(3);

                // Create the cell and push it.
                _cellInfo.Add(message.Id, new CellInfo(faction, techLevel));
            }

            // Get center of our cell.
            const int cellSize = CellSystem.CellSize;
            var       center   = new FarPosition(
                cellSize * message.X + (cellSize >> 1),
                cellSize * message.Y + (cellSize >> 1));

            // Check if it's the start system or not.
            if (message.X == 0 && message.Y == 0)
            {
                // It is, use a predefined number of planets and moons,
                // and make sure it's a solar system.
                FactoryLibrary.SampleSunSystem(Manager, "solar_system", center, random);
            }
            else
            {
                // It isn't, randomize.
                FactoryLibrary.SampleSunSystem(Manager, "sunsystem_1", center, random);
            }

            // Find nearby active cells and the stations in them, mark
            // them as possible targets for all station sin this cell,
            // and let them know about our existence, as well.
            var cellSystem = (CellSystem)Manager.GetSystem(CellSystem.TypeId);
            var stations   = _cellInfo[message.Id].Stations;

            for (var ny = message.Y - 1; ny <= message.Y + 1; ny++)
            {
                for (var nx = message.X - 1; nx <= message.X + 1; nx++)
                {
                    // Don't fly to cells that are diagonal to
                    // ourselves, which we do by checking if the
                    // sum of the coordinates is uneven.
                    // This becomes more obvious when considering this:
                    // +-+-+-+-+
                    // |0|1|0|1|
                    // +-+-+-+-+
                    // |1|0|1|0|
                    // +-+-+-+-+
                    // |0|1|0|1|
                    // +-+-+-+-+
                    // |1|0|1|0|
                    // +-+-+-+-+
                    // Where 0 means the sum of the own coordinate is
                    // even, 1 means it is odd. Then we can see that
                    // the sum of diagonal pairs of cells is always
                    // even, and the one of straight neighbors is
                    // always odd.
                    if (((message.X + message.Y + ny + nx) & 1) == 0)
                    {
                        // Get the id, only mark the station if we have
                        // info on it and it's an enemy cell.
                        var id = BitwiseMagic.Pack(nx, ny);
                        if (cellSystem.IsCellActive(id) &&
                            _cellInfo.ContainsKey(id) &&
                            (_cellInfo[id].Faction.IsAlliedTo(_cellInfo[message.Id].Faction)))
                        {
                            // Tell the other stations.
                            foreach (var stationId in _cellInfo[id].Stations)
                            {
                                var spawn = ((ShipSpawner)Manager.GetComponent(stationId, ShipSpawner.TypeId));
                                foreach (var otherStationId in stations)
                                {
                                    spawn.Targets.Add(otherStationId);
                                }
                            }
                            // Tell our own stations.
                            foreach (var stationId in stations)
                            {
                                var spawner = ((ShipSpawner)Manager.GetComponent(stationId, ShipSpawner.TypeId));
                                foreach (var otherStationId in _cellInfo[id].Stations)
                                {
                                    spawner.Targets.Add(otherStationId);
                                }
                            }
                        }
                    }
                }
            }
        }