Exemple #1
0
 /// <summary>Converts a rectangle in simulation space to screen space.</summary>
 /// <param name="rectangle">The rectangle.</param>
 /// <returns></returns>
 public static FarRectangle ToScreenUnits(FarRectangle rectangle)
 {
     rectangle.Inflate(
         rectangle.Width / 2f * (Util.UnitConversion.ScreenOverSimulationRatio - 1f),
         rectangle.Height / 2f * (Util.UnitConversion.ScreenOverSimulationRatio - 1f));
     return(rectangle);
 }
Exemple #2
0
 /// <summary>Converts a rectangle in screen space to simulation space.</summary>
 /// <param name="rectangle">The rectangle.</param>
 /// <returns></returns>
 public static FarRectangle ToSimulationUnits(FarRectangle rectangle)
 {
     rectangle.Inflate(
         -rectangle.Width / 2f * (1f - Util.UnitConversion.SimulationOverScreenRatio),
         -rectangle.Height / 2f * (1f - Util.UnitConversion.SimulationOverScreenRatio));
     return(rectangle);
 }
Exemple #3
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;
        }
Exemple #4
0
        public static FarRectangle NextRectangle(this IUniformRandom random, float area, float minSize, float maxSize)
        {
            var rect = new FarRectangle
            {
                Width  = (float)random.NextDouble(minSize, maxSize),
                Height = (float)random.NextDouble(minSize, maxSize)
            };

            rect.X = (float)random.NextDouble(-area / 2, area / 2 - (int)rect.Width);
            rect.Y = (float)random.NextDouble(-area / 2, area / 2 - (int)rect.Height);
            return(rect);
        }
Exemple #5
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);
        }
Exemple #6
0
        /// <summary>Returns the current bounds of the viewport, i.e. the rectangle of the world to actually render.</summary>
        /// <returns>The visible bounds, in world coordinates.</returns>
        public FarRectangle ComputeVisibleBounds()
        {
            var center = CameraPosition;
            var zoom   = Zoom;
            var width  = UnitConversion.ToSimulationUnits(_graphics.Viewport.Width / zoom);
            var height = UnitConversion.ToSimulationUnits(_graphics.Viewport.Height / zoom);
            // Get scaled viewport bounds, translated to camera position.
            var result = new FarRectangle
            {
                X      = (center.X - (width * 0.5f)),
                Y      = (center.Y - (height * 0.5f)),
                Width  = width,
                Height = height
            };

            return(result);
        }
Exemple #7
0
        /// <summary>Reset this behavior so it can be reused later on.</summary>
        public override void Reset()
        {
            base.Reset();

            Area = FarRectangle.Empty;
        }
Exemple #8
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);
        }
Exemple #9
0
        /// <summary>Sets up the basic ship data that is deterministic.</summary>
        /// <param name="manager"> </param>
        /// <param name="faction"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        private int CreateShip(IManager manager, Factions faction, FarPosition position)
        {
            var entity = manager.AddEntity();

            var body = manager.AddBody(entity, type: Body.BodyType.Dynamic, worldPosition: position, allowSleep: false);

            // We need at least one fixture to carry on our index and collision groups.
            manager.AttachCircle(
                body,
                UnitConversion.ToSimulationUnits(_collisionRadius),
                collisionCategory: faction.ToCollisionGroup(),
                collisionMask: ~(faction.ToCollisionGroup() | Factions.Shields.ToCollisionGroup()));

            // These are 'worst-case' bounds, i.e. no ship should get larger than this. We use it as
            // a buffer for the camera and interpolation system, to allow them picking up on objects
            // that are positioned outside the viewport, but reach into it due to their size.
            var bounds = new FarRectangle(-2, -2, 4, 4);

            // Can be detected.
            manager.AddComponent <Indexable>(entity).Initialize(Detectable.IndexId);
            // Can be attracted.
            manager.AddComponent <Indexable>(entity).Initialize(GravitationSystem.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);
            // Rendering should be interpolated.
            manager.AddComponent <Indexable>(entity).Initialize(bounds, InterpolationSystem.IndexId);

            // Although 'unrealistic' in space, make ships stop automatically if not accelerating.
            body.LinearDamping = LinearDamping;

            manager.AddComponent <Gravitation>(entity).Initialize();
            manager.AddComponent <ShipControl>(entity);
            manager.AddComponent <WeaponControl>(entity);
            manager.AddComponent <Energy>(entity);
            manager.AddComponent <Health>(entity).Initialize(120);
            manager.AddComponent <ShipDrawable>(entity)
            .Initialize(_texture, Color.Lerp(Color.White, faction.ToColor(), 0.5f));
            manager.AddComponent <ParticleEffects>(entity);

            // Faction component, which allows checking which group the ship
            // belongs to.
            manager.AddComponent <Faction>(entity).Initialize(faction);

            // Make it detectable by AI and show up on the radar.
            manager.AddComponent <Detectable>(entity).Initialize("Textures/ship", true);

            // Controllers for maneuvering and shooting.
            manager.AddComponent <ShipInfo>(entity);

            // Create equipment slot.
            manager.AddComponent <SpaceItemSlot>(entity).Initialize(Fuselage.TypeId);

            // Give it an inventory as well.
            manager.AddComponent <Inventory>(entity).Initialize(10);

            // Add some character!
            manager.AddComponent <Attributes <AttributeType> >(entity);

            // Do we drop stuff?
            if (_itemPool != null)
            {
                manager.AddComponent <Drops>(entity).Initialize(_itemPool);
            }

            // The the sound component for the thruster sound.
            manager.AddComponent <Sound>(entity).Initialize("Thruster");

            return(entity);
        }
 /// <summary>Makes the AI roams the specified area.</summary>
 /// <param name="area">The area.</param>
 public void Roam(ref FarRectangle area)
 {
     ((RoamBehavior)_behaviors[BehaviorType.Roam]).Area = area;
     PushBehavior(BehaviorType.Roam);
 }