예제 #1
0
            /// <summary>Samples a new orbiter of this type.</summary>
            /// <param name="manager">The manager.</param>
            /// <param name="center">The center.</param>
            /// <param name="dominantAngle">The dominant angle.</param>
            /// <param name="random">The random.</param>
            /// <returns></returns>
            internal void Sample(IManager manager, int center, float dominantAngle, IUniformRandom random)
            {
                if (random != null && ChanceToExist <= random.NextDouble())
                {
                    return;
                }

                var radius       = UnitConversion.ToSimulationUnits(SampleOrbitRadius(random));
                var eccentricity = SampleEccentricity(random);
                var angleOffset  = SampleAngleOffset(random);
                var travelSpeed  = UnitConversion.ToSimulationUnits(SampleTravelSpeed(random));
                var periodOffset = random == null ? 0f : (float)random.NextDouble();

                // Compute minor and major radius.
                float a, b;

                ComputeRadii(radius, eccentricity, out a, out b);

                // Get period. Figure out circumference using Ramanujan's approximation.
                var circumference = MathHelper.Pi * (3 * (a + b) - (float)Math.Sqrt((3 * a + b) * (a + 3 * b)));
                var period        = circumference / travelSpeed * Settings.TicksPerSecond;

                var entity = FactoryLibrary.SamplePlanet(manager, Name, random);

                // Make it move around its center.
                manager.AddComponent <EllipsePath>(entity)
                .Initialize(center, a, b, dominantAngle + angleOffset, period, MathHelper.TwoPi * periodOffset);

                // Recurse.
                if (Moons != null)
                {
                    Moons.Sample(manager, entity, random);
                }
            }
예제 #2
0
        // TODO in case we need this somewhere else it might be a good idea to move this to the EntityFactory
        private void CreateAsteroid(FarPosition position, IUniformRandom random, ContentManager content)
        {
            // Randomly scale and rotate it.
            var scale = (float)random.NextDouble(0.5f, 1f);
            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);
            var hull        = new List <Vector2>(TextureConverter.DetectVertices(texture, 8f, textureName: textureName)[0]);

            for (var k = 0; k < hull.Count; ++k)
            {
                hull[k] -= new Vector2(texture.Width / 2f, texture.Height / 2f);
                hull[k]  = XnaUnitConversion.ToSimulationUnits(hull[k]) * scale;
            }
            var polygons = EarClipDecomposer.ConvexPartition(hull);

            // Create physical representation.
            var entity = Manager.AddEntity();
            var body   = Manager.AddBody(entity, position, angle, Body.BodyType.Dynamic);

            foreach (var polygon in polygons)
            {
                Manager.AttachPolygon(body, polygon, density: 1000f, restitution: 0.2f);
            }
            // Slow down to allow reaching sleep state again.
            body.LinearDamping  = 0.05f * Space.Util.Settings.TicksPerSecond;
            body.AngularDamping = 0.025f * Space.Util.Settings.TicksPerSecond;

            // Bounds of the asteroid for rendering culling. We use the diagonal for a loose fit that
            // contains every possible rotated state of the texture.
            var width    = UnitConversion.ToSimulationUnits(texture.Width);
            var height   = UnitConversion.ToSimulationUnits(texture.Height);
            var diagonal = (float)Math.Sqrt(width * width + height * height);
            var bounds   = new FarRectangle(-diagonal / 2, -diagonal / 2, diagonal, diagonal);

            // Rendering stuff.
            Manager.AddComponent <Indexable>(entity).Initialize(bounds, CameraSystem.IndexId);
            Manager.AddComponent <Indexable>(entity).Initialize(bounds, InterpolationSystem.IndexId);
            Manager.AddComponent <SimpleTextureDrawable>(entity).Initialize(textureName, scale);

            // Auto removal.
            Manager.AddComponent <CellDeath>(entity).Initialize(true);
            Manager.AddComponent <Indexable>(entity).Initialize(CellSystem.CellDeathAutoRemoveIndexId);

            // Make it destructible.
            var health = Manager.AddComponent <Health>(entity);

            health.Value        = health.MaxValue = 200 * scale;
            health.Regeneration = 0f;

            // As they don't move on their own, start asteroids as sleeping to save performance.
            body.IsAwake = false;
        }
예제 #3
0
        public static RectangleF NextRectangle(this IUniformRandom random, float area, float minSize, float maxSize)
        {
            var rect = new RectangleF
            {
                Width  = (float)random.NextDouble(minSize, maxSize),
                Height = (float)random.NextDouble(minSize, maxSize)
            };

            rect.X = (float)random.NextDouble(-area / 2, area / 2 - rect.Width);
            rect.Y = (float)random.NextDouble(-area / 2, area / 2 - rect.Height);
            return(rect);
        }
예제 #4
0
 /// <summary>Samples the offset of this sun.</summary>
 /// <param name="random">The randomizer to use.</param>
 /// <returns>The sampled offset.</returns>
 private Vector2 SampleOffset(IUniformRandom random)
 {
     if (_offsetRadius != null && random != null)
     {
         Vector2 offset;
         offset.X = (float)(random.NextDouble() - 0.5);
         offset.Y = (float)(random.NextDouble() - 0.5);
         offset.Normalize();
         offset *= MathHelper.Lerp(_offsetRadius.Low, _offsetRadius.High, (float)random.NextDouble());
         return(offset);
     }
     return(Vector2.Zero);
 }
예제 #5
0
 /// <summary>Samples the angle of this planet's orbit.</summary>
 /// <param name="random">The randomizer to use.</param>
 /// <returns>The sampled angle.</returns>
 private float SampleAngle(IUniformRandom random)
 {
     return
         (MathHelper.ToRadians(
              (random == null)
                 ? _angle.Low
                 : MathHelper.Lerp(_angle.Low, _angle.High, (float)random.NextDouble())));
 }
예제 #6
0
 /// <summary>Samples the mass of this sun.</summary>
 /// <param name="random">The randomizer to use.</param>
 /// <returns>The sampled mass.</returns>
 private float SampleMass(IUniformRandom random)
 {
     if (_mass != null)
     {
         return((random == null)
                    ? _mass.Low
                    : MathHelper.Lerp(_mass.Low, _mass.High, (float)random.NextDouble()));
     }
     return(0f);
 }
예제 #7
0
파일: Ziggurat.cs 프로젝트: matrix4x4/Space
        /// <summary>Get the next sample value from the gaussian distribution.</summary>
        public double NextSample()
        {
            for (;;)
            {
                // Select box at random.
                var u    = (byte)_rng.NextUInt32();
                var i    = u & 0x7F;
                var sign = ((u & 0x80) == 0) ? -1.0 : 1.0;

                // Generate uniform random value with range [0,0xFFFFFFFF].
                var u2 = _rng.NextUInt32();

                // Special case for the base segment.
                if (0 == i)
                {
                    if (u2 < _xComp[0])
                    {
                        // Generated x is within R0.
                        return(u2 * UIntToU * _aDivY0 * sign);
                    }
                    // Generated x is in the tail of the distribution.
                    return(SampleTail() * sign);
                }

                // All other segments.
                if (u2 < _xComp[i])
                {
                    // Generated x is within the rectangle.
                    return(u2 * UIntToU * _x[i] * sign);
                }

                // Generated x is outside of the rectangle.
                // Generate a random y coordinate and test if our (x,y) is within the distribution curve.
                // This execution path is relatively slow/expensive (makes a call to Math.Exp()) but relatively rarely executed,
                // although more often than the 'tail' path (above).
                double x = u2 * UIntToU * _x[i];
                if (_y[i - 1] + ((_y[i] - _y[i - 1]) * _rng.NextDouble()) < GaussianPdfDenorm(x))
                {
                    return(x * sign);
                }
            }
        }
예제 #8
0
        /// <summary>Samples the attributes to apply to the item.</summary>
        /// <param name="manager">The manager.</param>
        /// <param name="random">The randomizer to use.</param>
        /// <return>The entity with the attributes applied.</return>
        public int Sample(IManager manager, IUniformRandom random)
        {
            var entity = manager.AddEntity();

            // Sample all values in advance, to allow reshuffling component creation
            // order in case we need to, without influencing the 'random' results.
            var radius        = UnitConversion.ToSimulationUnits(SampleRadius(random));
            var rotationSpeed = SampleRotationSpeed(random);
            var mass          = SampleMass(random);

            var surfaceRotation = random != null
                                      ? (Math.Sign(random.NextDouble() - 0.5) * rotationSpeed)
                                      : rotationSpeed;

            // Give it a position.
            manager.AddComponent <Transform>(entity);

            // Add it to some indexes.
            var bounds = new FarRectangle(-radius, -radius, radius * 2, radius * 2);

            // Can be detected.
            manager.AddComponent <Indexable>(entity).Initialize(bounds, Detectable.IndexId);
            // Can make some noise.
            manager.AddComponent <Indexable>(entity).Initialize(SoundSystem.IndexId);
            // Must be detectable by the camera.
            manager.AddComponent <Indexable>(entity).Initialize(bounds, CameraSystem.IndexId);

            // Remove when out of bounds or large containing cell dies.
            manager.AddComponent <Indexable>(entity).Initialize(CellSystem.CellDeathAutoRemoveIndexId);
            manager.AddComponent <CellDeath>(entity).Initialize(false);

            // Make it rotate.
            manager.AddComponent <Velocity>(entity).Initialize(
                Vector2.Zero,
                MathHelper.ToRadians(rotationSpeed) / Settings.TicksPerSecond);

            // Make it attract stuff if it has mass.
            if (mass > 0)
            {
                manager.AddComponent <Gravitation>(entity).Initialize(Gravitation.GravitationTypes.Attractor, mass);
            }

            // Make it detectable.
            manager.AddComponent <Detectable>(entity).Initialize("Textures/Radar/Icons/radar_planet");

            // Make it visible.
            manager.AddComponent <PlanetRenderer>(entity).Initialize(this, UnitConversion.ToScreenUnits(radius), surfaceRotation);

            // Let it rap.
            manager.AddComponent <Sound>(entity).Initialize("Planet");

            return(entity);
        }
예제 #9
0
        /// <summary>Samples an attribute modifier from this constraint.</summary>
        /// <param name="random">The randomizer to use.</param>
        /// <returns>The sampled attribute modifier.</returns>
        public AttributeModifier <TAttribute> SampleAttributeModifier(IUniformRandom random)
        {
            // Only randomize if necessary.
            var value = (random == null)
                            ? _value.Low
                            : MathHelper.Lerp(_value.Low, _value.High, (float)random.NextDouble());

            if (_round)
            {
                value = (float)System.Math.Round(value);
            }
            return(new AttributeModifier <TAttribute>(_type, value, _computationType));
        }
예제 #10
0
 /// <summary>Samples the acceleration force.</summary>
 /// <param name="baseRotation">The base rotation.</param>
 /// <param name="random">The randomizer to use.</param>
 /// <returns>The sampled acceleration force.</returns>
 public Vector2 SampleAccelerationForce(float baseRotation, IUniformRandom random)
 {
     if (_accelerationDirection != null && _accelerationForce != null)
     {
         var acceleration = Vector2.UnitX;
         var rotation     =
             Matrix.CreateRotationZ(
                 baseRotation +
                 MathHelper.ToRadians(
                     MathHelper.Lerp(
                         _accelerationDirection.Low,
                         _accelerationDirection.High,
                         (random == null) ? 0 : (float)random.NextDouble())));
         Vector2.Transform(ref acceleration, ref rotation, out acceleration);
         acceleration.Normalize();
         return(acceleration *
                ((random == null)
                     ? _accelerationForce.Low
                     : MathHelper.Lerp(
                     _accelerationForce.Low, _accelerationForce.High, (float)random.NextDouble())));
     }
     return(Vector2.Zero);
 }
예제 #11
0
 /// <summary>Samples the initial directed velocity.</summary>
 /// <param name="baseRotation">The base rotation.</param>
 /// <param name="random">The randomizer to use.</param>
 /// <returns>The sampled velocity.</returns>
 public Vector2 SampleInitialDirectedVelocity(float baseRotation, IUniformRandom random)
 {
     if (_initialDirection != null && _initialVelocity != null)
     {
         var velocity = Vector2.UnitX;
         var rotation =
             Matrix.CreateRotationZ(
                 baseRotation +
                 MathHelper.ToRadians(
                     MathHelper.Lerp(
                         _initialDirection.Low,
                         _initialDirection.High,
                         (random == null) ? 0 : (float)random.NextDouble())));
         Vector2.Transform(ref velocity, ref rotation, out velocity);
         velocity.Normalize();
         return(velocity *
                ((random == null)
                     ? _initialVelocity.Low
                     : MathHelper.Lerp(_initialVelocity.Low, _initialVelocity.High, (float)random.NextDouble())));
     }
     return(Vector2.Zero);
 }
예제 #12
0
        /// <summary>
        ///     Samples the specified number of attributes from the list of available attributes in the specified attribute
        ///     pools.
        /// </summary>
        /// <param name="count">The number of attributes to sample.</param>
        /// <param name="random">The randomizer to use.</param>
        protected IEnumerable <AttributeModifier <AttributeType> > SampleAttributes(int count, IUniformRandom random)
        {
            if (count <= 0)
            {
                yield break;
            }

            // Get the cumulative weights, and figure out how many attributes
            // there are, so we don't have to resize our list of all attributes
            // while adding them.
            var summedWeights  = 0;
            var attributeCount = 0;

            for (var i = 0; i < _additionalAttributes.Length; i++)
            {
                var pool = FactoryLibrary.GetAttributePool(_additionalAttributes[i]);
                attributeCount += pool.Attributes.Length;
                summedWeights  += pool.Attributes.Sum(attribute => attribute.Weight);
            }

            // Get the actual list of available attributes.
            var attributes = new List <AttributePool.AttributeInfo>(attributeCount);

            for (var i = 0; i < _additionalAttributes.Length; i++)
            {
                attributes.AddRange(FactoryLibrary.GetAttributePool(_additionalAttributes[i]).Attributes);
            }

            // Sample some attributes! Make sure we always have some (may
            // remove some, if they may not be re-used).
            for (var i = 0; i < count && attributes.Count > 0; i++)
            {
                // Regarding the following...
                // Assume we have 5 attributes, when concatenating their
                // weights on an interval that might look like so:
                // |--|----|--|-|---------|
                // where one '-' represents one weight (i.e. '--' == 2).
                // Now, when sampling we multiply a uniform random value
                // with the sum of those weights, meaning that number
                // falls somewhere in that interval. What we need to do
                // then, is to figure out into which sub-interval it is,
                // meaning which attribute is to be picked. We do this by
                // starting with the left interval, moving to the right
                // and subtracting the weight of the current interval until
                // the remaining rolled value becomes negative, in which
                // case we it fell into the last one. (equal zero does
                // not count, because the roll is at max weight - 1,
                // because 0 counts for the first interval).

                // Note that the list does *not* have to be sorted for
                // this, because each point on the interval is equally
                // likely to be hit!

                // Get a random number determining the attribute we want.
                var roll = (int)(random.NextDouble() * summedWeights);

                // Figure out the interval, starting with the first.
                var j = 0;
                while (roll >= 0)
                {
                    roll -= attributes[j].Weight;
                    ++j;
                }

                // Get the attribute that was sampled.
                var attribute = attributes[j];

                // Sample it!
                yield return(attribute.Attribute.SampleAttributeModifier(random));

                // If the attribute may not be reused, remove it from our list.
                if (!attribute.AllowRedraw)
                {
                    attributes.RemoveAt(j);
                    summedWeights -= attribute.Weight;
                }
            }
        }
예제 #13
0
 /// <summary>Samples the rotation speed of this planet.</summary>
 /// <param name="random">The randomizer to use.</param>
 /// <returns>The sampled rotation speed.</returns>
 private float SampleRotationSpeed(IUniformRandom random)
 {
     if (_rotationSpeed != null)
     {
         return(MathHelper.ToRadians(
                    (random == null)
                 ? _rotationSpeed.Low
                 : MathHelper.Lerp(_rotationSpeed.Low, _rotationSpeed.High, (float)random.NextDouble())));
     }
     return(0f);
 }
예제 #14
0
 /// <summary>Samples the eccentricity of this planet's orbit.</summary>
 /// <param name="random">The randomizer to use.</param>
 /// <returns>The sampled major radius.</returns>
 private float SampleEccentricity(IUniformRandom random)
 {
     if (_eccentricity != null)
     {
         return((random == null)
                    ? _eccentricity.Low
                    : MathHelper.Lerp(_eccentricity.Low, _eccentricity.High, (float)random.NextDouble()));
     }
     return(0f);
 }
예제 #15
0
 /// <summary>Samples the travel speed of this planet.</summary>
 /// <param name="random">The randomizer to use.</param>
 /// <returns>The sampled travel speed.</returns>
 private float SampleTravelSpeed(IUniformRandom random)
 {
     if (_travelSpeed != null)
     {
         return((random == null)
                    ? _travelSpeed.Low
                    : MathHelper.Lerp(_travelSpeed.Low, _travelSpeed.High, (float)random.NextDouble()));
     }
     return(0f);
 }
예제 #16
0
 /// <summary>Samples the angle of this planet's orbit.</summary>
 /// <param name="random">The randomizer to use.</param>
 /// <returns>The sampled angle.</returns>
 private float SampleOrbitRadius(IUniformRandom random)
 {
     return((random == null)
                ? _orbitRadius.Low
                : MathHelper.Lerp(_orbitRadius.Low, _orbitRadius.High, (float)random.NextDouble()));
 }
예제 #17
0
 public static FarPosition NextVector(this IUniformRandom random, float area)
 {
     return(new FarPosition((float)(random.NextDouble() * area - area / 2.0),
                            (float)(random.NextDouble() * area - area / 2.0)));
 }
예제 #18
0
 public static Vector2 NextVector(this IUniformRandom random, float area)
 {
     return(new Vector2((float)(random.NextDouble() * area - area / 2.0),
                        (float)(random.NextDouble() * area - area / 2.0)));
 }
예제 #19
0
        /// <summary>Samples the attributes to apply to the item.</summary>
        /// <param name="manager">The manager.</param>
        /// <param name="cellCenter">The center of the cell the sun will be inserted in.</param>
        /// <param name="random">The randomizer to use.</param>
        /// <return>The entity with the attributes applied.</return>
        public int Sample(IManager manager, FarPosition cellCenter, IUniformRandom random)
        {
            var entity = manager.AddEntity();

            // Sample all values in advance, to allow reshuffling component creation
            // order in case we need to, without influencing the 'random' results.
            var radius = UnitConversion.ToSimulationUnits(SampleRadius(random));
            var offset = SampleOffset(random);
            var mass   = SampleMass(random);

            var surfaceRotation = -Vector2.UnitX;

            if (random != null)
            {
                surfaceRotation.X = (float)(random.NextDouble() - 0.5) * 2;
                surfaceRotation.Y = (float)(random.NextDouble() - 0.5) * 2;
                surfaceRotation.Normalize();
            }

            var primaryTurbulenceRotation = Vector2.UnitX;

            if (random != null)
            {
                primaryTurbulenceRotation.X = (float)(random.NextDouble() - 0.5) * 2;
                primaryTurbulenceRotation.Y = (float)(random.NextDouble() - 0.5) * 2;
                primaryTurbulenceRotation.Normalize();
            }

            var secondaryTurbulenceRotation = Vector2.UnitY;

            if (random != null)
            {
                secondaryTurbulenceRotation.X = (float)(random.NextDouble() - 0.5) * 2;
                secondaryTurbulenceRotation.Y = (float)(random.NextDouble() - 0.5) * 2;
                secondaryTurbulenceRotation.Normalize();
            }

            var body = manager.AddBody(entity, offset + cellCenter);

            manager.AttachCircle(body, radius);

            var bounds = new FarRectangle(-radius, -radius, radius * 2, radius * 2);

            // Can be detected.
            manager.AddComponent <Indexable>(entity).Initialize(bounds, Detectable.IndexId);
            // Can make noise.
            manager.AddComponent <Indexable>(entity).Initialize(SoundSystem.IndexId);
            // Must be detectable by the camera.
            manager.AddComponent <Indexable>(entity).Initialize(bounds, CameraSystem.IndexId);

            // Remove when out of bounds or large containing cell dies.
            manager.AddComponent <Indexable>(entity).Initialize(CellSystem.CellDeathAutoRemoveIndexId);
            manager.AddComponent <CellDeath>(entity).Initialize(false);

            // Make it attract stuff if it has mass.
            if (mass > 0)
            {
                manager.AddComponent <Gravitation>(entity).Initialize(Gravitation.GravitationTypes.Attractor);
            }

            // Damage stuff that touches a sun.
            manager.AddComponent <CollisionDamage>(entity).Initialize(false);
            var attributes = manager.AddComponent <Attributes <AttributeType> >(entity);

            attributes.SetBaseValue(AttributeType.AttackBurnMinDamage, 1000);
            attributes.SetBaseValue(AttributeType.AttackBurnMaxDamage, 2000);
            attributes.SetBaseValue(AttributeType.AttackBurnChance, 1);
            attributes.SetBaseValue(AttributeType.AttackBurnMinDuration, 5);
            attributes.SetBaseValue(AttributeType.AttackBurnMaxDuration, 5);
            attributes.SetBaseValue(AttributeType.Mass, mass);

            // Make it detectable.
            manager.AddComponent <Detectable>(entity).Initialize("Textures/Radar/Icons/radar_sun");

            // Make it glow.
            manager.AddComponent <SunRenderer>(entity)
            .Initialize(UnitConversion.ToScreenUnits(radius) * 0.95f, surfaceRotation, primaryTurbulenceRotation, secondaryTurbulenceRotation, _tint);

            // Make it go whoooosh.
            manager.AddComponent <Sound>(entity).Initialize("Sun");

            return(entity);
        }
예제 #20
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);
            //}
        }