예제 #1
0
        public void Draw(Graphics graphics, Camera camera, IMassiveBody parentBody)
        {
            var poweredTrails = new List <RectangleF>();
            var coastTrails   = new List <RectangleF>();

            for (int i = 0; i < _trailAngles.Count; i++)
            {
                double angle    = _trailAngles[i] + parentBody.Pitch;
                double distance = _trailDistances[i];

                DVector2 worldPoint = DVector2.FromAngle(angle) * distance + parentBody.Position;

                if (camera.Contains(worldPoint))
                {
                    PointF localPoint = RenderUtils.WorldToScreen(worldPoint, camera.Bounds);

                    if (_trailPowered[i])
                    {
                        poweredTrails.Add(new RectangleF(localPoint.X, localPoint.Y, 2, 2));
                    }
                    else
                    {
                        coastTrails.Add(new RectangleF(localPoint.X, localPoint.Y, 2, 2));
                    }
                }
            }

            RenderUtils.DrawRectangles(graphics, poweredTrails, Color.Red);
            RenderUtils.DrawRectangles(graphics, coastTrails, Color.White);
        }
예제 #2
0
        protected virtual void RenderAbove(Graphics graphics, Camera camera)
        {
            if (EntryFlame != null)
            {
                EntryFlame.Draw(graphics, camera);
            }

            // Only show the vectors when it's requested and the craft is not parented
            if (_showDisplayVectors && Parent == null)
            {
                // The length of the vector is based on the width of the camera bounds
                float lengthFactor = (float)(camera.Bounds.Width * 0.1);

                PointF start = RenderUtils.WorldToScreen(Position, camera.Bounds);

                DVector2 relativeVelocity = GetRelativeVelocity();

                // Only draw the velocity vector when it can be normalized
                if (relativeVelocity.Length() > 0)
                {
                    relativeVelocity.Normalize();

                    PointF velocityEnd = RenderUtils.WorldToScreen(Position + relativeVelocity * lengthFactor, camera.Bounds);

                    graphics.DrawLine(Pens.White, start, velocityEnd);
                }

                DVector2 pitchVector = DVector2.FromAngle(Pitch);
                pitchVector.Normalize();

                PointF pitchEnd = RenderUtils.WorldToScreen(Position + pitchVector * lengthFactor, camera.Bounds);

                graphics.DrawLine(Pens.Red, start, pitchEnd);
            }
        }
예제 #3
0
        /// <summary>
        /// Stages the spacecraft according to its mounted angle by applying a normal force.
        /// </summary>
        public void Stage()
        {
            if (Children.Count > 0)
            {
                ISpaceCraft[] children = Children.ToArray();

                foreach (ISpaceCraft child in children)
                {
                    child.Stage();
                }
            }
            else if (Parent != null)
            {
                Parent.RemoveChild(this);
                Parent = null;

                // Simulate simple staging mechanism
                double sAngle = StageOffset.Angle();

                DVector2 stagingNormal = DVector2.FromAngle(Pitch + sAngle + Math.PI * 0.5);

                _stagingForce    = stagingNormal * Mass * 0.005;
                _requiresStaging = true;
            }
        }
예제 #4
0
        public void Update(TimeStep timeStep, DVector2 enginePosition, DVector2 shipVelocity,
                           double rotation, double throttle, double ispMultiplier, double angle = 0)
        {
            if (angle != 0)
            {
                _angle = angle;
            }

            double retrograde = rotation + Math.PI + _angle;

            int particles = (int)((throttle * _particleRate) / timeStep.UpdateLoops);

            // Interpolate between spreads based on ISP
            double spreadMultiplier = (1.0 - ispMultiplier) * _minSpread + ispMultiplier * _maxSpread;

            double throttleMultiplier = Math.Max(throttle, 0.3) * 0.01;

            // Add new particles if nessecary
            for (int i = 0; i < particles; i++)
            {
                if (_availableParticles.Count > 0)
                {
                    double velocityFactor = _random.Next(200, 300) * throttleMultiplier;
                    double spread         = _random.NextDouble() - 0.5;

                    DVector2 velocity = DVector2.FromAngle(retrograde + spread * spreadMultiplier);

                    int id = _availableParticles.Dequeue();

                    Particle particle = _particles[id];

                    particle.IsActive = true;
                    particle.Age      = 0;
                    particle.MaxAge   = _random.NextDouble() * 0.05 + _maxAge;

                    particle.Position = enginePosition.Clone();
                    particle.Velocity = shipVelocity.Clone() + velocity * velocityFactor;
                }
            }

            // Update the particles
            for (int i = 0; i < _particles.Length; i++)
            {
                Particle particle = _particles[i];

                if (particle.IsActive)
                {
                    particle.Position += particle.Velocity * timeStep.Dt;
                    particle.Age      += timeStep.Dt;

                    if (particle.Age > particle.MaxAge)
                    {
                        particle.IsActive = false;
                        _availableParticles.Enqueue(i);
                    }
                }
            }
        }
예제 #5
0
        public void RenderGdi(Graphics graphics, Camera camera)
        {
            // Update position and rotation given the parent's motion
            double currentRotation = (_parent.Pitch - _initialRotation) + _rotationOffset;

            DVector2 rotationNormal = DVector2.FromAngle(currentRotation);

            Position = _parent.Position + rotationNormal * _initialDistance;

            var bounds = new RectangleD(Position.X - Width * 0.5, Position.Y - Height * 0.5, Width, Height);

            // Not in range easy return
            if (!camera.Intersects(bounds))
            {
                return;
            }

            RectangleF screenBounds = RenderUtils.ComputeBoundingBox(Position, camera.Bounds, Width, Height);

            // Saftey
            if (screenBounds.Width > RenderUtils.ScreenWidth * 500)
            {
                return;
            }

            double drawingRotation = currentRotation + Constants.PiOverTwo;

            var offset = new PointF(screenBounds.X + screenBounds.Width * 0.5f,
                                    screenBounds.Y + screenBounds.Height * 0.5f);

            camera.ApplyScreenRotation(graphics);
            camera.ApplyRotationMatrix(graphics, offset, drawingRotation);

            graphics.DrawImage(_texture, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height);

            graphics.ResetTransform();

            double visibility = Visibility(camera.Bounds);

            if (visibility < 1)
            {
                PointF iconPoint = RenderUtils.WorldToScreen(Position, camera.Bounds);

                var iconBounds = new RectangleF(iconPoint.X - 5, iconPoint.Y - 5, 10, 10);

                var iconColor = Color.FromArgb((int)((1 - visibility) * 255), IconColor.R, IconColor.G, IconColor.B);

                camera.ApplyScreenRotation(graphics);

                graphics.FillEllipse(new SolidBrush(iconColor), iconBounds);

                graphics.ResetTransform();
            }
        }
예제 #6
0
        public void Update(TimeStep timeStep, DVector2 shipPosition, DVector2 shipVelocity, double pitch, double heatingRate)
        {
            double rotation = pitch - _offsetAngle;

            DVector2 offset = new DVector2(Math.Cos(rotation), Math.Sin(rotation)) * _offsetLength;

            DVector2 shockPosition = shipPosition - offset;

            double normalizedHeating = Math.Max((heatingRate - 500000) * 0.0005, 0);

            int particles = (int)(normalizedHeating * _particleRate) / timeStep.UpdateLoops;

            // Add new particles if nessecary
            for (int i = 0; i < particles; i++)
            {
                if (_availableParticles.Count > 0)
                {
                    double velocityFactor = _random.Next(50, 200);
                    double spread         = _random.NextDouble() * 2.5 - 1.25;

                    DVector2 velocity = DVector2.FromAngle(rotation + spread);

                    int id = _availableParticles.Dequeue();

                    Particle particle = _particles[id];

                    particle.IsActive = true;
                    particle.Age      = 0;
                    particle.MaxAge   = _random.NextDouble() * 0.01 + 0.02;

                    particle.Position = shockPosition.Clone();
                    particle.Velocity = shipVelocity.Clone() + velocity * velocityFactor;
                }
            }

            // Update the particles
            for (int i = 0; i < _particles.Length; i++)
            {
                Particle particle = _particles[i];

                if (particle.IsActive)
                {
                    particle.Position += particle.Velocity * timeStep.Dt;
                    particle.Age      += timeStep.Dt;

                    if (particle.Age > particle.MaxAge)
                    {
                        particle.IsActive = false;
                        _availableParticles.Enqueue(i);
                    }
                }
            }
        }
예제 #7
0
파일: Factory.cs 프로젝트: rbarraud/Blarg2
        void TickUpdate() {
                ComSat.Trace(this, "TickUpdate");
                if(sabotageTime > 0) {
                        sabotageTime -= ComSat.tickRate;
                }
                if (buildQueue.Any()) {
                        var buildMe = buildQueue.Peek();
                        var prefab = prefabs[buildMe.what];

                        if(delay > 0) {
                                var advance = ComSat.tickRate;
                                if(sabotageTime > 0) {
                                        advance /= sabotageTimeMultiplier;
                                }
                                if(!powerSink.Powered()) {
                                        advance /= 2;
                                }

                                var completion = advance / prefab.buildTime;
                                var totalRemaining = prefab.buildCost - usedResources;
                                partialMetalUnit += DReal.Min(completion * prefab.buildCost.Metal, totalRemaining.Metal);
                                partialSmokeUnit += DReal.Min(completion * prefab.buildCost.MagicSmoke, totalRemaining.MagicSmoke);
                                var rs = new ResourceSet { Metal = (int)partialMetalUnit, MagicSmoke = (int)partialSmokeUnit };
                                if (resourceMan.TakeResources(entity.team, rs)) {
                                        usedResources += rs;
                                        partialMetalUnit %= 1;
                                        partialSmokeUnit %= 1;
                                        delay -= advance;
                                } else {
                                        partialMetalUnit -= completion * prefab.buildCost.Metal;
                                        partialSmokeUnit -= completion * prefab.buildCost.MagicSmoke;
                                }
                        }
                        if(delay <= 0) {
                                if (!resourceMan.TakeResources(entity.team, prefab.buildCost - usedResources)) return;

                                // Timer expired and we're building something.
                                print("Build new " + prefab);
                                var prefabSize = (DReal)prefab.collisionRadiusNumerator / prefab.collisionRadiusDenominator;
                                var wiggle = ((ComSat.RandomValue() % 5) / 5) * ((ComSat.RandomValue() % 2 == 0) ? 1 : -1);
                                var position = prefab.buildAtPoint
                                        ? buildMe.position
                                        : (entity.position + DVector2.FromAngle(entity.rotation + wiggle) * (entity.collisionRadius + prefabSize + 2 + wiggle));
                                ComSat.SpawnEntity(entity, prefab.gameObject, position, 0);
                                if(buildMe.buildCollider != null) {
                                        buildMan.RemovePendingBuild(buildMe.buildCollider);
                                }
                                if (!buildMe.repeat) buildQueue.Dequeue();
                                ResetBuildTime();
                        }
                }
        }
예제 #8
0
        public override void UpdateAnimations(TimeStep timeStep)
        {
            DVector2 retrogradeVelocity = GetRelativeVelocity();

            retrogradeVelocity.Negate();

            DVector2 engineBase = Position - DVector2.FromAngle(Pitch) * Height * 0.5;

            double altitude = GetRelativeAltitude();

            double atmosphericDensity = GravitationalParent.GetAtmosphericDensity(altitude);

            _engineSmoke.Update(timeStep, engineBase, Velocity, retrogradeVelocity, atmosphericDensity, _sootRatio);

            base.UpdateAnimations(timeStep);
        }
예제 #9
0
        public void Update(TimeStep timeStep, DVector2 enginePosition, DVector2 shipVelocity, double rotation, double throttle)
        {
            double retrograde = rotation + Math.PI;

            int particles = (int)((throttle * _particleRate) / timeStep.UpdateLoops);

            // Add new particles if nessecary
            for (int i = 0; i < particles; i++)
            {
                if (_availableParticles.Count > 0)
                {
                    double velocityFactor = _random.Next(150, 250);
                    double spread         = _random.NextDouble() - 0.5;

                    DVector2 velocity = DVector2.FromAngle(retrograde + spread * _spreadFactor);

                    int id = _availableParticles.Dequeue();

                    Particle particle = _particles[id];

                    particle.IsActive = true;
                    particle.Age      = 0;
                    particle.MaxAge   = _random.NextDouble() * 0.1 + 0.05;

                    particle.Position = enginePosition.Clone();
                    particle.Velocity = shipVelocity.Clone() + velocity * velocityFactor;
                }
            }

            // Update the particles
            for (int i = 0; i < _particles.Length; i++)
            {
                Particle particle = _particles[i];

                if (particle.IsActive)
                {
                    particle.Position += particle.Velocity * timeStep.Dt;
                    particle.Age      += timeStep.Dt;

                    if (particle.Age > particle.MaxAge)
                    {
                        particle.IsActive = false;
                        _availableParticles.Enqueue(i);
                    }
                }
            }
        }
예제 #10
0
    void TickUpdate()
    {
        ComSat.Trace(this, "TickUpdate");
        if (ComSat.EntityExists(target))
        {
            var dir         = target.position - entity.position;     // also vector to dest.
            var targetAngle = DVector2.ToAngle(dir);
            var baseAngle   = Utility.CalculateNewAngle(entity.rotation, targetAngle, DReal.Radians(turnSpeed));
            entity.rotation = baseAngle;
        }
        entity.velocity = DVector2.FromAngle(entity.rotation) * speed;
        DVector2 newPosition = entity.position + entity.velocity * ComSat.tickRate;

        // FIXME: this should do something to account for hitting fast-moving projectiles.
        DVector2 hitPosition;
        Entity   hit = ComSat.LineCast(entity.position, newPosition, out hitPosition, entity.team);

        if (hit != null && (!hit.hitOnlyIfTargetted || hit == target))
        {
            hit.Damage((int)ComputeDamage());

            var position = new Vector3((float)hitPosition.y, 0, (float)hitPosition.x);
            var rotation = Quaternion.AngleAxis((float)entity.rotation, Vector3.up);
            if (impactPrefab != null && ComSat.RateLimit())
            {
                ObjectPool.Instantiate(impactPrefab, position, rotation);
            }

            //if(trail) {
            //        trail.transform.parent = null;
            //        trail.autodestruct = true;
            //        trail = null;
            //}

            if (!penetrates || speed < minPenetrationSpeed)
            {
                ComSat.DestroyEntity(entity, DestroyReason.HitTarget);
                return;
            }
            else
            {
                speed -= penetrationSpeedReduction;
            }
        }
    }
예제 #11
0
파일: Vehicle.cs 프로젝트: rbarraud/Blarg2
    // This could be smarter. If dest is too close & perpendicular, then the tank
    // can end up circling around.
    public void MoveTowards(DVector2 dest)
    {
        ComSat.Trace(this, "MoveTowards");
        var dir         = dest - entity.position; // also vector to dest.
        var targetAngle = DVector2.ToAngle(dir);
        var baseAngle   = Utility.CalculateNewAngle(entity.rotation, targetAngle, DReal.Radians(turnSpeed));

        entity.rotation = baseAngle;

        // Move along current heading. Ramp speed up as the angle gets closer.
        // Augh.
        // [-pi,pi] => [0,2pi]
        if (targetAngle < 0)
        {
            targetAngle += DReal.TwoPI;
        }
        // Get targetAngle within +/- pi of baseAngle.
        if (targetAngle < baseAngle - DReal.PI)
        {
            targetAngle += DReal.TwoPI;
        }
        else if (targetAngle > baseAngle + DReal.PI)
        {
            targetAngle -= DReal.TwoPI;
        }
        var diff = DReal.Abs(baseAngle - targetAngle);

        if (canMoveWithoutTurning || diff < maxMoveAngle)
        {
            var distance = dir.magnitude;
            //print("Distance: " + distance + "  speed is: " + tickSpeed);
            var speed = minSpeed + (maxSpeed - minSpeed) * (1 - (diff / DReal.PI));
            if (distance < speed)
            {
                speed = DReal.Max(minSpeed, distance);
            }
            entity.velocity = canMoveWithoutTurning ? dir.normalized * speed : DVector2.FromAngle(baseAngle) * speed;
        }
        else
        {
            Stop();
        }
    }
예제 #12
0
        /// <summary>
        /// Stages the spacecraft according to its mounted angle by applying a normal force.
        /// </summary>
        public void Stage()
        {
            if (Children.Count > 0)
            {
                ISpaceCraft[] children = Children.ToArray();

                foreach (ISpaceCraft child in children)
                {
                    child.Stage();
                }
            }
            else if (Parent != null)
            {
                Parent.RemoveChild(this);
                Parent = null;

                // Simulate simple staging mechanism
                double sAngle = StageOffset.Angle();

                DVector2 stagingVector = DVector2.FromAngle(Rotation + sAngle + Math.PI * 0.5);

                AccelerationN += stagingVector * 1000;
            }
        }
예제 #13
0
파일: Vehicle.cs 프로젝트: rbarraud/Blarg2
 public void Stop()
 {
     ComSat.Trace(this, "Stop");
     entity.velocity = DVector2.FromAngle(entity.rotation) * minSpeed;
 }
예제 #14
0
        /// <summary>
        /// Updates the spacecraft and it's children.
        /// </summary>
        public override void Update(double dt)
        {
            ComputeCachedProperties();

            double altitude = GetRelativeAltitude();

            if (GravitationalParent == null)
            {
                IspMultiplier = 1;
            }
            else
            {
                IspMultiplier = GravitationalParent.GetIspMultiplier(altitude);
            }

            if (Parent == null)
            {
                UpdateEngines(dt);

                if (Thrust > 0 && _isReleased)
                {
                    var thrustVector = new DVector2(Math.Cos(Pitch) * Math.Cos(Yaw), Math.Sin(Pitch) * Math.Cos(Yaw));
                    var yawVector    = new DVector2(Math.Cos(Pitch) * Math.Sin(Yaw), Math.Sin(Pitch) * Math.Sin(Yaw));

                    AccelerationN += (thrustVector * Thrust) / Mass;
                    AccelerationY += (yawVector * Thrust) / Mass;
                }

                if (_requiresStaging)
                {
                    // Simulate simple staging mechanism
                    double sAngle = StageOffset.Angle();

                    DVector2 stagingNormal = DVector2.FromAngle(Pitch + sAngle + Constants.PiOverTwo);

                    AccelerationN += stagingNormal * StagingForce;

                    _requiresStaging = false;
                }

                if (_isReleased)
                {
                    // Integrate acceleration
                    Velocity += AccelerationG * dt;
                    Velocity += AccelerationD * dt;
                    Velocity += AccelerationL * dt;
                    Velocity += AccelerationN * dt;

                    LateralVelocity += AccelerationY * dt;
                    LateralPosition += LateralVelocity * dt;
                }

                // Re-normalize FTL scenarios
                if (Velocity.LengthSquared() > Constants.SpeedLightSquared)
                {
                    Velocity.Normalize();

                    Velocity *= Constants.SpeedOfLight;
                }

                // If the craft is on the ground with high time warpd don't update the position as normal.
                // Instead just keep putting the ship at the correct spot on it's gravitational body based on rotation.
                if (OnGround && dt > 5)
                {
                    DVector2 parentOffset = GravitationalParent.Position - Position;
                    parentOffset.Normalize();

                    Position = GravitationalParent.Position + parentOffset * GravitationalParent.SurfaceRadius;
                }
                else
                {
                    // Integrate velocity
                    Position += Velocity * dt;
                }

                MachNumber = GetRelativeVelocity().Length() * 0.0029411764;

                foreach (ISpaceCraft child in Children)
                {
                    child.UpdateChildren(Position, Velocity);
                }

                _trailTimer += dt;

                // Somewhat arbitrary conditions for launch trails
                if (dt < 0.1666666666 && !InOrbit && !OnGround && _cachedAltitude > 50 && _cachedAltitude < GravitationalParent.AtmosphereHeight * 2 && _trailTimer > 1)
                {
                    string parentName = GravitationalParent.ToString();

                    if (!_launchTrails.ContainsKey(parentName))
                    {
                        _launchTrails.Add(parentName, new LaunchTrail());
                    }

                    _launchTrails[parentName].AddPoint(Position, GravitationalParent, Throttle > 0);
                    _trailTimer = 0;
                }
            }
        }
예제 #15
0
        /// <summary>
        /// Updates the spacecraft and it's children.
        /// </summary>
        public override void Update(double dt)
        {
            ComputeCachedProperties();

            double altitude = GetRelativeAltitude();

            IspMultiplier = GravitationalParent.GetIspMultiplier(altitude);

            if (Parent == null)
            {
                UpdateEngines(dt);

                if (Thrust > 0)
                {
                    var thrustVector = new DVector2(Math.Cos(Pitch), Math.Sin(Pitch));

                    AccelerationN += (thrustVector * Thrust) / Mass;
                }

                if (_requiresStaging)
                {
                    // Simulate simple staging mechanism
                    double sAngle = StageOffset.Angle();

                    DVector2 stagingNormal = DVector2.FromAngle(Pitch + sAngle + Math.PI * 0.5);

                    AccelerationN += stagingNormal * StagingForce;

                    _requiresStaging = false;
                }

                // Integrate acceleration
                Velocity += (AccelerationG * dt);
                Velocity += (AccelerationD * dt);
                Velocity += (AccelerationN * dt);
                Velocity += (AccelerationL * dt);

                // Re-normalize FTL scenarios
                if (Velocity.LengthSquared() > Constants.SpeedLightSquared)
                {
                    Velocity.Normalize();

                    Velocity *= Constants.SpeedOfLight;
                }

                // Integrate velocity
                Position += (Velocity * dt);

                MachNumber = GetRelativeVelocity().Length() * 0.0029411764;

                foreach (ISpaceCraft child in Children)
                {
                    child.UpdateChildren(Position, Velocity);
                }

                _trailTimer += dt;

                // Somewhat arbitrary conditions for launch trails
                if (dt < 0.1666666666 && !InOrbit && _cachedAltitude > 50 && _cachedAltitude < GravitationalParent.AtmosphereHeight * 2 && _trailTimer > 1)
                {
                    string parentName = GravitationalParent.ToString();

                    if (!_launchTrails.ContainsKey(parentName))
                    {
                        _launchTrails.Add(parentName, new LaunchTrail());
                    }

                    _launchTrails[parentName].AddPoint(Position, GravitationalParent, Throttle > 0);
                    _trailTimer = 0;
                }
            }
        }
예제 #16
0
        public static int Prev(int currentIndex, IList <IGravitationalBody> bodies, Camera camera)
        {
            DVector2 cameraNormal = DVector2.FromAngle(Math.PI - camera.Rotation);

            return(Iterate(currentIndex, bodies, cameraNormal));
        }