internal override void ActionCommand(Game game) { if (!IsRunning) { Entity parentEntity = EntityCommanding.GetDataBlob <OrbitDB>().Parent; Vector2 newVector = OrbitProcessor.InstantaneousOrbitalVelocityVector(EntityCommanding.GetDataBlob <OrbitDB>(), _db.ActionOnDateTime); newVector += _db.DeltaVToExpend_AU; var spdmps = Distance.AuToMt(newVector.Length()); Vector3 newVector3d = new Vector3(newVector.X, newVector.Y, 0); OrbitDB newOrbit = OrbitDB.FromVector(parentEntity, EntityCommanding, newVector3d, _db.ActionOnDateTime); /* * if (newOrbit.Periapsis > targetSOI) * { * //TODO: find who's SOI we're currently in and create an orbit for that; * } * if (newOrbit.Apoapsis > targetSOI) * { * //TODO: change orbit to new parent at SOI change * } */ EntityCommanding.SetDataBlob(newOrbit); newOrbit.SetParent(parentEntity); } }
/// <summary> /// Returns an orbit representing the defined parameters. /// </summary> /// <param name="semiMajorAxis_AU">SemiMajorAxis of orbit in AU.</param> /// <param name="eccentricity">Eccentricity of orbit.</param> /// <param name="inclination">Inclination of orbit in degrees.</param> /// <param name="longitudeOfAscendingNode">Longitude of ascending node in degrees.</param> /// <param name="argumentOfPeriapsis">Argument of periapsis in degrees.</param> /// <param name="meanAnomaly">Mean Anomaly in degrees.</param> /// <param name="epoch">reference time for these orbital elements.</param> public static OrbitDB FromAsteroidFormat([NotNull] Entity parent, double parentMass, double myMass, double semiMajorAxis_AU, double eccentricity, double inclination, double longitudeOfAscendingNode, double argumentOfPeriapsis, double meanAnomaly, DateTime epoch) { if (parent == null) { throw new ArgumentNullException(nameof(parent)); } double sma_m = Distance.AuToMt(semiMajorAxis_AU); OrbitDB orbit = new OrbitDB(parent) { SemiMajorAxis = sma_m, Eccentricity = eccentricity, Inclination_Degrees = inclination, LongitudeOfAscendingNode_Degrees = longitudeOfAscendingNode, ArgumentOfPeriapsis_Degrees = argumentOfPeriapsis, MeanAnomalyAtEpoch_Degrees = meanAnomaly, Epoch = epoch, _parentMass = parentMass, _myMass = myMass }; orbit.CalculateExtendedParameters(); return(orbit); }
public static void StartNonNewtTranslation(Entity entity) { var moveDB = entity.GetDataBlob <TranslateMoveDB>(); var propulsionDB = entity.GetDataBlob <PropulsionAbilityDB>(); var positionDB = entity.GetDataBlob <PositionDB>(); var maxSpeedMS = propulsionDB.MaximumSpeed_MS; positionDB.SetParent(null); Vector3 targetPosMt = Distance.AuToMt(moveDB.TranslateExitPoint_AU); Vector3 currentPositionMt = Distance.AuToMt(positionDB.AbsolutePosition_AU); Vector3 postionDelta = currentPositionMt - targetPosMt; double totalDistance = postionDelta.Length(); double maxKMeters = ShipMovementProcessor.CalcMaxFuelDistance_KM(entity); double fuelMaxDistanceMt = maxKMeters * 1000; if (fuelMaxDistanceMt >= totalDistance) { var currentVelocityMS = Vector3.Normalise(targetPosMt - currentPositionMt) * maxSpeedMS; propulsionDB.CurrentVectorMS = currentVelocityMS; moveDB.CurrentNonNewtonionVectorMS = currentVelocityMS; moveDB.LastProcessDateTime = entity.Manager.ManagerSubpulses.StarSysDateTime; CargoStorageDB storedResources = entity.GetDataBlob <CargoStorageDB>(); foreach (var item in propulsionDB.FuelUsePerKM) { var fuel = staticData.GetICargoable(item.Key); StorageSpaceProcessor.RemoveCargo(storedResources, fuel, (long)(item.Value * totalDistance / 1000)); } } }
/// <summary> /// Moves an entity while it's in a non newtonion translation state. /// TODO: doing this in meters will likely cause problems for ships that have a large position value. /// (position in meters could consevably go out of max value) /// </summary> /// <param name="entity">Entity.</param> /// <param name="deltaSeconds">Unused</param> public void ProcessEntity(Entity entity, int deltaSeconds) { var manager = entity.Manager; var moveDB = entity.GetDataBlob <TranslateMoveDB>(); var propulsionDB = entity.GetDataBlob <PropulsionAbilityDB>(); var currentVelocityMS = moveDB.CurrentNonNewtonionVectorMS; DateTime dateTimeFrom = moveDB.LastProcessDateTime; DateTime dateTimeNow = manager.ManagerSubpulses.StarSysDateTime; DateTime dateTimeFuture = dateTimeNow + TimeSpan.FromSeconds(deltaSeconds); double deltaT = (dateTimeFuture - dateTimeFrom).TotalSeconds; var positionDB = entity.GetDataBlob <PositionDB>(); var currentPositionAU = positionDB.AbsolutePosition_AU; Vector3 currentPositionMt = Distance.AuToMt(positionDB.AbsolutePosition_AU); Vector3 targetPosMt; targetPosMt = Distance.AuToMt(moveDB.TranslateExitPoint_AU); var deltaVecToTargetMt = currentPositionMt - targetPosMt; var newPositionMt = currentPositionMt + currentVelocityMS * deltaT; //var distanceToTargetAU = deltaVecToTargetAU.Length(); //in au var distanceToTargetMt = deltaVecToTargetMt.Length(); //var deltaVecToTimeAU = currentPositionAU - TimePosAU; var positionDelta = currentPositionMt - newPositionMt; double distanceToMove = positionDelta.Length(); if (distanceToTargetMt <= distanceToMove) // moving would overtake target, just go directly to target { newPositionMt = targetPosMt; positionDB.SetParent(moveDB.TargetEntity); //positionDB.AbsolutePosition_AU = Distance.MToAU(newPositionMt);//this needs to be set before creating the orbitDB positionDB.RelativePosition_AU = moveDB.TranslateRalitiveExit_AU; SetOrbitHere(entity, propulsionDB, positionDB, moveDB, dateTimeFuture); } else { positionDB.AbsolutePosition_AU = Distance.MToAU(newPositionMt); } moveDB.LastProcessDateTime = dateTimeFuture; }
/// <summary> /// Returns an orbit representing the defined parameters. /// </summary> /// <param name="semiMajorAxis_AU">SemiMajorAxis of orbit in AU.</param> /// <param name="eccentricity">Eccentricity of orbit.</param> /// <param name="inclination">Inclination of orbit in degrees.</param> /// <param name="longitudeOfAscendingNode">Longitude of ascending node in degrees.</param> /// <param name="longitudeOfPeriapsis">Longitude of periapsis in degrees.</param> /// <param name="meanLongitude">Longitude of object at epoch in degrees.</param> /// <param name="epoch">reference time for these orbital elements.</param> public static OrbitDB FromMajorPlanetFormat([NotNull] Entity parent, double parentMass, double myMass, double semiMajorAxis_AU, double eccentricity, double inclination, double longitudeOfAscendingNode, double longitudeOfPeriapsis, double meanLongitude, DateTime epoch) { if (parent == null) { throw new ArgumentNullException(nameof(parent)); } // http://en.wikipedia.org/wiki/Longitude_of_the_periapsis double argumentOfPeriapsis = longitudeOfPeriapsis - longitudeOfAscendingNode; // http://en.wikipedia.org/wiki/Mean_longitude double meanAnomaly = meanLongitude - (longitudeOfAscendingNode + argumentOfPeriapsis); double sma_m = Distance.AuToMt(semiMajorAxis_AU); return(new OrbitDB(parent, parentMass, myMass, sma_m, eccentricity, inclination, longitudeOfAscendingNode, argumentOfPeriapsis, meanAnomaly, epoch)); }
void SetOrbitHere(Entity entity, PropulsionAbilityDB propulsionDB, PositionDB positionDB, TranslateMoveDB moveDB, DateTime atDateTime) { propulsionDB.CurrentVectorMS = new Vector3(0, 0, 0); double targetSOI = OrbitProcessor.GetSOI(moveDB.TargetEntity); Entity targetEntity; if (moveDB.TargetEntity.GetDataBlob <PositionDB>().GetDistanceTo(positionDB) > targetSOI) { targetEntity = moveDB.TargetEntity.GetDataBlob <OrbitDB>().Parent; //TODO: it's concevable we could be in another SOI not the parent (ie we could be in a target's moon's SOI) } else { targetEntity = moveDB.TargetEntity; } OrbitDB targetOrbit = targetEntity.GetDataBlob <OrbitDB>(); var orbitalVector = OrbitProcessor.GetOrbitalVector(targetOrbit, atDateTime); var insertionVector2d = OrbitProcessor.GetOrbitalInsertionVector(moveDB.SavedNewtonionVector_AU, targetOrbit, atDateTime); Vector3 parentOrbitalVector = new Vector3(orbitalVector.X, orbitalVector.Y, 0); Vector3 insertionVector = new Vector3(insertionVector2d.X, insertionVector2d.Y, 0); insertionVector += moveDB.ExpendDeltaV_AU; //TODO: only use it if we have it. propulsionDB.RemainingDV_MS -= (float)Distance.AuToMt(moveDB.ExpendDeltaV_AU).Length(); OrbitDB newOrbit = OrbitDB.FromVector(targetEntity, entity, insertionVector, atDateTime); if (newOrbit.Periapsis > targetSOI) { //TODO: find who's SOI we're currently in and create an orbit for that; } if (newOrbit.Apoapsis > targetSOI) { //TODO: change orbit to new parent at SOI change } positionDB.SetParent(targetEntity); moveDB.IsAtTarget = true; entity.RemoveDataBlob <TranslateMoveDB>(); entity.SetDataBlob(newOrbit); newOrbit.SetParent(targetEntity); }
/// <summary> /// This was designed so that fast moving objects will get interpolated a lot more than slow moving objects /// so fast moving objects shouldn't loose positional acuracy when close to a planet, /// and slow moving objects won't have processor time wasted on them by calulcating too often. /// However this seems to be unstable and looses energy, unsure why. currently set it to just itterate/interpolate every second. /// so currently will be using more time to get through this than neccisary. /// </summary> /// <param name="entity">Entity.</param> /// <param name="deltaSeconds">Delta seconds.</param> public static void NewtonMove(Entity entity, int deltaSeconds) { NewtonMoveDB newtonMoveDB = entity.GetDataBlob <NewtonMoveDB>(); PositionDB positionDB = entity.GetDataBlob <PositionDB>(); double Mass_Kg = entity.GetDataBlob <MassVolumeDB>().Mass; double ParentMass_kg = newtonMoveDB.ParentMass; var manager = entity.Manager; DateTime dateTimeFrom = newtonMoveDB.LastProcessDateTime; DateTime dateTimeNow = manager.ManagerSubpulses.StarSysDateTime; DateTime dateTimeFuture = dateTimeNow + TimeSpan.FromSeconds(deltaSeconds); double deltaT = (dateTimeFuture - dateTimeFrom).TotalSeconds; double secondsToItterate = deltaT; while (secondsToItterate > 0) { double speed_kms = newtonMoveDB.CurrentVector_kms.Length(); //double timeStep = Math.Max(secondsToItterate / speed_kms, 1); //timeStep = Math.Min(timeStep, secondsToItterate); double timeStep = 1;//because the above seems unstable and looses energy. double distanceToParent_m = Distance.AuToMt(positionDB.GetDistanceTo(newtonMoveDB.SOIParent.GetDataBlob <PositionDB>())); distanceToParent_m = Math.Max(distanceToParent_m, 0.1); //don't let the distance be 0 (once collision is in this will likely never happen anyway) double gravForce = GameConstants.Science.GravitationalConstant * (Mass_Kg * ParentMass_kg / Math.Pow(distanceToParent_m, 2)); Vector3 gravForceVector = gravForce * -Vector3.Normalise(positionDB.RelativePosition_AU); double distance = Distance.AuToKm(positionDB.RelativePosition_AU).Length(); Vector3 totalForce = gravForceVector + newtonMoveDB.ThrustVector; Vector3 acceleration_mps = totalForce / Mass_Kg; Vector3 newVelocity = (acceleration_mps * timeStep * 0.001) + newtonMoveDB.CurrentVector_kms; newtonMoveDB.CurrentVector_kms = newVelocity; Vector3 deltaPos = (newtonMoveDB.CurrentVector_kms + newVelocity) / 2 * timeStep; //Vector4 deltaPos = newtonMoveDB.CurrentVector_kms * timeStep; positionDB.RelativePosition_AU += Distance.KmToAU(deltaPos); double sOIRadius_AU = OrbitProcessor.GetSOI(newtonMoveDB.SOIParent); if (positionDB.RelativePosition_AU.Length() >= sOIRadius_AU) { Entity newParent; Vector3 parentRalitiveVector; //if our parent is a regular kepler object (normaly this is the case) if (newtonMoveDB.SOIParent.HasDataBlob <OrbitDB>()) { var orbitDB = newtonMoveDB.SOIParent.GetDataBlob <OrbitDB>(); newParent = orbitDB.Parent; var parentVelocity = OrbitProcessor.InstantaneousOrbitalVelocityVector(orbitDB, entity.Manager.ManagerSubpulses.StarSysDateTime); parentRalitiveVector = Distance.KmToAU(newtonMoveDB.CurrentVector_kms) + parentVelocity; var pvlen = Distance.AuToKm(parentVelocity.Length()); var vlen = newtonMoveDB.CurrentVector_kms.Length(); var rvlen = Distance.AuToKm(parentRalitiveVector.Length()); } else //if (newtonMoveDB.SOIParent.HasDataBlob<NewtonMoveDB>()) { //this will pretty much never happen. newParent = newtonMoveDB.SOIParent.GetDataBlob <NewtonMoveDB>().SOIParent; var parentVelocity = newtonMoveDB.SOIParent.GetDataBlob <NewtonMoveDB>().CurrentVector_kms; parentRalitiveVector = Distance.KmToAU(newtonMoveDB.CurrentVector_kms + parentVelocity); } double newParentMass = newParent.GetDataBlob <MassVolumeDB>().Mass; double sgp = GameConstants.Science.GravitationalConstant * (newParentMass + Mass_Kg) / 3.347928976e33; Vector3 posRalitiveToNewParent = positionDB.AbsolutePosition_AU - newParent.GetDataBlob <PositionDB>().AbsolutePosition_AU; var dateTime = dateTimeNow + TimeSpan.FromSeconds(deltaSeconds - secondsToItterate); var kE = OrbitMath.KeplerFromPositionAndVelocity(sgp, posRalitiveToNewParent, parentRalitiveVector, dateTime); if (kE.Eccentricity < 1) //if we're going to end up in a regular orbit around our new parent { /* * var newOrbit = OrbitDB.FromKeplerElements( * newParent, * newParentMass, * Mass_Kg, * kE, * dateTime); */ var newOrbit = OrbitDB.FromVector(newParent, entity, parentRalitiveVector, dateTime); entity.RemoveDataBlob <NewtonMoveDB>(); entity.SetDataBlob(newOrbit); positionDB.SetParent(newParent); var currentPos = Distance.AuToKm(positionDB.RelativePosition_AU); var newPos = OrbitProcessor.GetPosition_AU(newOrbit, dateTime); var newPosKM = Distance.AuToKm(newPos); positionDB.RelativePosition_AU = newPos; break; } else //else we're in a hyperbolic trajectory around our new parent, so just coninue the newtonion move. { positionDB.SetParent(newParent); newtonMoveDB.ParentMass = newParentMass; newtonMoveDB.SOIParent = newParent; } } secondsToItterate -= timeStep; } newtonMoveDB.LastProcessDateTime = dateTimeFuture; }