Пример #1
0
        /// <summary>
        /// Traces a space craft orbit by re-centering the world around the parent.
        /// </summary>
        public static void TraceSpaceCraft(SpaceCraftBase satellite, OrbitTrace trace)
        {
            IMassiveBody parent = satellite.GravitationalParent;

            DVector2 initialPosition = satellite.Position - parent.Position;

            var shipOffset = new DVector2(Math.Cos(satellite.Pitch) * (satellite.TotalWidth - satellite.Width),
                                          Math.Sin(satellite.Pitch) * (satellite.TotalHeight - satellite.Height)) * 0.5;

            initialPosition -= shipOffset;

            var proxyParent    = new MassiveBodyProxy(DVector2.Zero, DVector2.Zero, parent);
            var proxySatellite = new SpaceCraftProxy(initialPosition, satellite.Velocity - parent.Velocity, satellite);

            proxySatellite.SetGravitationalParent(proxyParent);

            int stepCount;

            double targetDt;
            double proximityDt;
            double orbitalDt = 0;

            bool isOrbiting;

            double altitude          = proxyParent.GetRelativeHeight(proxySatellite.Position);
            double proximityAltitude = proxyParent.SurfaceRadius * 0.15;

            if (altitude < proximityAltitude)
            {
                stepCount = 1100;

                isOrbiting = false;

                proximityDt = GetProximityDt(altitude, proximityAltitude);

                targetDt = proximityDt;
            }
            else
            {
                stepCount = 600;

                isOrbiting = true;

                orbitalDt = GetOrbitalDt(initialPosition.Length(), parent.Mass, proxySatellite.Velocity.Length());

                targetDt = orbitalDt;
            }

            // Assumes that the parent is (0,0) which will be true in this case
            double previousAngle            = proxySatellite.Position.Angle();
            double totalAngularDisplacement = 0;

            trace.Reset(satellite.Position - shipOffset);

            // Update steps based on orbit vs atmosphere
            for (int step = 0; step < stepCount; step++)
            {
                proxySatellite.ResetAccelerations();

                proxySatellite.ResolveGravitation(proxyParent);
                proxySatellite.ResolveAtmopsherics(proxyParent);

                proxySatellite.Update(targetDt);

                double currentAngle = proxySatellite.Position.Angle();

                totalAngularDisplacement += DeltaAngle(currentAngle, previousAngle);

                // Made a full orbit
                if (totalAngularDisplacement > AngularCutoff)
                {
                    break;
                }

                previousAngle = currentAngle;

                altitude = proxyParent.GetRelativeHeight(proxySatellite.Position);

                double velocity = proxySatellite.GetRelativeVelocity().Length();

                double offsetFactor = 0.0;

                //if (altitude < proxyParent.AtmosphereHeight*2)
                if (altitude < proxyParent.AtmosphereHeight * 4)
                {
                    if (velocity < 3000)
                    {
                        offsetFactor = 1.0;
                    }
                    else if (velocity < 4000)
                    {
                        offsetFactor = 1.0 - velocity / 3000.0;
                    }
                }

                // Check if reference frame shifting needs to occur in atmosphere
                if (offsetFactor > 0.0001)
                {
                    DVector2 difference = proxyParent.Position - proxySatellite.Position;
                    difference.Normalize();

                    var surfaceNormal = new DVector2(-difference.Y, difference.X);

                    double altitudeFromCenter = altitude + proxyParent.SurfaceRadius;

                    // Distance of circumference at this altitude ( c= r * 2pi )
                    double pathCirumference = Constants.TwoPi * altitudeFromCenter;

                    double rotationalSpeed = pathCirumference / parent.RotationPeriod;

                    DVector2 atmopshereVelocity = surfaceNormal * rotationalSpeed;

                    proxySatellite.ApplyFrameOffset(atmopshereVelocity * offsetFactor * targetDt);
                }

                // Return early if the trace goes into a planet
                if (altitude <= 0)
                {
                    trace.AddPoint(proxySatellite.Position + parent.Position, altitude);
                    break;
                }

                // Determine the correct change overs from orbital to surface proximity
                if (isOrbiting)
                {
                    if (altitude < proximityAltitude)
                    {
                        proximityDt = GetProximityDt(altitude, proximityAltitude);

                        targetDt = MathHelper.Lerp(targetDt, proximityDt, 0.75);

                        isOrbiting = false;

                        stepCount = 1000;
                    }
                    else
                    {
                        targetDt = MathHelper.Lerp(targetDt, orbitalDt, 0.1);
                    }
                }
                else
                {
                    if (altitude > proximityAltitude)
                    {
                        orbitalDt = GetOrbitalDt(proxySatellite.Position.Length(), parent.Mass, proxySatellite.Velocity.Length());

                        targetDt = MathHelper.Lerp(targetDt, orbitalDt, 0.1);

                        isOrbiting = true;

                        stepCount = 600;
                    }
                    else
                    {
                        proximityDt = GetProximityDt(altitude, proximityAltitude);

                        targetDt = MathHelper.Lerp(targetDt, proximityDt, 0.75);
                    }
                }

                trace.AddPoint(proxySatellite.Position + parent.Position, altitude);
            }
        }
Пример #2
0
        private void PredictTargetThrottle(SpaceCraftBase spaceCraft)
        {
            double optimalThrust       = _currentThrust;
            double optimalLandingSpeed = double.PositiveInfinity;

            for (int i = -1; i <= 1; i++)
            {
                double thrust = _currentThrust;

                thrust += i;

                if (thrust < 40 || thrust > 100)
                {
                    continue;
                }

                IMassiveBody parent = spaceCraft.GravitationalParent;

                DVector2 initialPosition = spaceCraft.Position - parent.Position;

                var proxyParent    = new MassiveBodyProxy(DVector2.Zero, DVector2.Zero, parent);
                var proxySatellite = new SpaceCraftProxy(initialPosition, spaceCraft.Velocity - parent.Velocity, spaceCraft);

                foreach (int id in _engineIds)
                {
                    proxySatellite.Engines[id].Startup();
                    proxySatellite.Engines[id].AdjustThrottle(thrust);
                }

                proxySatellite.SetGravitationalParent(proxyParent);

                // Simulate until the rocket runs out of fuel or touches down
                for (int step = 0; step < 1000; step++)
                {
                    proxySatellite.ResetAccelerations();
                    proxySatellite.ResolveGravitation(proxyParent);
                    proxySatellite.ResolveAtmopsherics(proxyParent);

                    if (proxySatellite.PropellantMass <= 0)
                    {
                        break;
                    }

                    if (proxySatellite.OnGround)
                    {
                        double landingSpeed = proxySatellite.RelativeVelocity.Length();

                        if (landingSpeed < optimalLandingSpeed)
                        {
                            optimalLandingSpeed = landingSpeed;
                            optimalThrust       = thrust;
                        }

                        break;
                    }

                    proxySatellite.Update(0.05);
                }
            }

            // Set the target engines to the optimal computed thrust
            if (_engineIds != null)
            {
                // Startup the required landing engines
                foreach (int id in _engineIds)
                {
                    IEngine engine = spaceCraft.Engines[id];

                    engine.AdjustThrottle(optimalThrust);
                }

                _currentThrust = optimalThrust;
            }
        }
Пример #3
0
        /// <summary>
        /// Traces a space craft orbit by re-centering the world around the parent.
        /// </summary>
        public static void TraceSpaceCraft(SpaceCraftBase satellite, OrbitTrace trace)
        {
            IMassiveBody parent = satellite.GravitationalParent;

            DVector2 initialPosition = satellite.Position - parent.Position;

            var shipOffset = new DVector2(Math.Cos(satellite.Pitch) * (satellite.TotalWidth - satellite.Width),
                                          Math.Sin(satellite.Pitch) * (satellite.TotalHeight - satellite.Height)) * 0.5;

            initialPosition -= shipOffset;

            var proxyParent    = new MassiveBodyProxy(DVector2.Zero, DVector2.Zero, parent);
            var proxySatellite = new SpaceCraftProxy(initialPosition, satellite.Velocity - parent.Velocity, satellite);

            proxySatellite.SetGravitationalParent(proxyParent);

            int stepCount;

            double targetDt;
            double proximityDt;
            double orbitalDt = 0;

            bool   isOrbiting;
            double orbitalTerminationRadius = 0;

            double altitude          = proxyParent.GetRelativeHeight(proxySatellite.Position);
            double proximityAltitude = proxyParent.SurfaceRadius * 0.15;

            if (altitude < proximityAltitude)
            {
                stepCount = 1100;

                isOrbiting = false;

                proximityDt = GetProximityDt(altitude, proximityAltitude);

                targetDt = proximityDt;
            }
            else
            {
                stepCount = 600;

                isOrbiting = true;

                orbitalDt = GetOrbitalDt(initialPosition, proxySatellite.Velocity, out orbitalTerminationRadius);

                targetDt = orbitalDt;
            }

            trace.Reset(satellite.Position - shipOffset);

            // Simulate 300 orbital steps, more for proximity
            for (int step = 0; step < stepCount; step++)
            {
                proxySatellite.ResetAccelerations();

                proxySatellite.ResolveGravitation(proxyParent);
                proxySatellite.ResolveAtmopsherics(proxyParent);

                proxySatellite.Update(targetDt);

                altitude = proxyParent.GetRelativeHeight(proxySatellite.Position);

                double velocity = proxySatellite.GetRelativeVelocity().Length();

                double offsetFactor = 0.0;

                if (altitude < proxyParent.AtmosphereHeight * 2)
                {
                    if (velocity < 3000)
                    {
                        offsetFactor = 1.0;
                    }
                    else if (velocity < 4000)
                    {
                        offsetFactor = 1.0 - velocity / 3000.0;
                    }
                }

                // Check if reference frame shifting needs to occur in atmosphere
                if (offsetFactor > 0.0001)
                {
                    DVector2 difference = proxyParent.Position - proxySatellite.Position;
                    difference.Normalize();

                    var surfaceNormal = new DVector2(-difference.Y, difference.X);

                    double altitudeFromCenter = altitude + proxyParent.SurfaceRadius;

                    // Distance of circumference at this altitude ( c= 2r * pi )
                    double pathCirumference = 2 * Math.PI * altitudeFromCenter;

                    double rotationalSpeed = pathCirumference / parent.RotationPeriod;

                    DVector2 atmopshereVelocity = surfaceNormal * rotationalSpeed;

                    proxySatellite.ApplyFrameOffset(atmopshereVelocity * offsetFactor * targetDt);

                    // Return early if the trace goes into a planet
                    if (altitude <= 0)
                    {
                        trace.AddPoint(proxySatellite.Position + parent.Position, altitude);
                        break;
                    }
                }

                // Determine the correct change overs from orbital to surface proximity
                if (isOrbiting)
                {
                    if (altitude < proximityAltitude)
                    {
                        proximityDt = GetProximityDt(altitude, proximityAltitude);

                        targetDt = MathHelper.Lerp(targetDt, proximityDt, 0.75);

                        isOrbiting = false;

                        stepCount = 1000;
                    }
                    else
                    {
                        targetDt = MathHelper.Lerp(targetDt, orbitalDt, 0.1);
                    }
                }
                else
                {
                    if (altitude > proximityAltitude)
                    {
                        orbitalDt = GetOrbitalDt(proxySatellite.Position, proxySatellite.Velocity, out orbitalTerminationRadius);

                        targetDt = MathHelper.Lerp(targetDt, orbitalDt, 0.1);

                        isOrbiting = true;

                        stepCount = 600;
                    }
                    else
                    {
                        proximityDt = GetProximityDt(altitude, proximityAltitude);

                        targetDt = MathHelper.Lerp(targetDt, proximityDt, 0.75);
                    }
                }

                // Check expensive termination conditions after half of the iterations
                if (isOrbiting && step > 100)
                {
                    DVector2 offsetVector = proxySatellite.Position - initialPosition;

                    double distanceFromStart = offsetVector.Length();

                    // Terminate and add the end point
                    if (distanceFromStart < orbitalTerminationRadius)
                    {
                        trace.AddPoint(proxySatellite.Position + parent.Position, altitude);
                        break;
                    }
                }

                trace.AddPoint(proxySatellite.Position + parent.Position, altitude);
            }
        }