public void OnComponentInstallation(Entity parentEntity, ComponentInstance componentInstance) { NewtonThrustAbilityDB db; if (!parentEntity.HasDataBlob <NewtonThrustAbilityDB>()) { db = new NewtonThrustAbilityDB(FuelType); parentEntity.SetDataBlob(db); } else { db = parentEntity.GetDataBlob <NewtonThrustAbilityDB>(); if (db.FuelType != FuelType) { throw new Exception("prime entity can only have thrusters which use the same fuel type"); } //todo: fix so we can use different fuel types on the prime entity. } //db.ThrustInNewtons += ThrustInNewtons; db.ExhaustVelocity = ExhaustVelocity; db.FuelBurnRate += FuelBurnRate; db.ThrustInNewtons += ExhaustVelocity * FuelBurnRate; /* * var wetmass = parentEntity.GetDataBlob<MassVolumeDB>().Mass; * ProcessedMaterialSD foo = StaticRefLib.StaticData.CargoGoods.GetMaterials()[FuelType]; * var cargo = parentEntity.GetDataBlob<CargoStorageDB>(); * var fuelAmount = StorageSpaceProcessor.GetAmount(cargo, foo); * var dryMass = wetmass - fuelAmount; * db.DeltaV = OrbitMath.TsiolkovskyRocketEquation(wetmass, dryMass, ExhaustVelocity); */ }
public NewtonThrustAbilityDB(NewtonThrustAbilityDB db) { ThrustInNewtons = db.ThrustInNewtons; ExhaustVelocity = db.ExhaustVelocity; FuelType = db.FuelType; FuelBurnRate = db.FuelBurnRate; DeltaV = db.DeltaV; }
public static (Vector3 pos, Vector3 vel) GetAbsulutePositon_m(Entity entity, NewtonMoveDB newtonMoveDB, DateTime atDateTime) { PositionDB positionDB = entity.GetDataBlob <PositionDB>(); NewtonThrustAbilityDB newtonThrust = entity.GetDataBlob <NewtonThrustAbilityDB>(); DateTime dateTimeNow = entity.StarSysDateTime; TimeSpan timeDelta = atDateTime - dateTimeNow; double mass_Kg = entity.GetDataBlob <MassVolumeDB>().Mass; double parentMass_kg = newtonMoveDB.ParentMass; Vector3 newAbsolute = positionDB.AbsolutePosition_m; Vector3 velocity = newtonMoveDB.CurrentVector_ms; double secondsToItterate = timeDelta.TotalSeconds; while (secondsToItterate > 0) { //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 = positionDB.GetDistanceTo_m(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_m); Vector3 acceleratonFromGrav = gravForceVector / mass_Kg; double maxAccelFromThrust1 = newtonThrust.ExhaustVelocity * Math.Log(mass_Kg / (mass_Kg - newtonThrust.FuelBurnRate)); //per second double maxAccelFromThrust = newtonThrust.ThrustInNewtons / mass_Kg; //per second Vector3 accelerationFromThrust = newtonMoveDB.DeltaVForManuver_AU / maxAccelFromThrust; //per second Vector3 accelerationTotal = acceleratonFromGrav + accelerationFromThrust; Vector3 newVelocity = (accelerationTotal * timeStep) + velocity; velocity = newVelocity; Vector3 deltaPos = (velocity + newVelocity) / 2 * timeStep; newAbsolute += deltaPos; secondsToItterate -= timeStep; } return(newAbsolute, velocity); }
/// <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>(); NewtonThrustAbilityDB newtonThrust = entity.GetDataBlob <NewtonThrustAbilityDB>(); 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 timeStep = Math.Max(secondsToItterate / speed_kms, 1); //timeStep = Math.Min(timeStep, secondsToItterate); double timeStepInSeconds = 1;//because the above seems unstable and looses energy. double distanceToParent_m = positionDB.GetDistanceTo_m(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_m); Vector3 totalDVFromGrav = (gravForceVector / mass_Kg) * timeStepInSeconds; double maxAccelFromThrust1 = newtonThrust.ExhaustVelocity * Math.Log(mass_Kg / (mass_Kg - newtonThrust.FuelBurnRate)); //per second double maxAccelFromThrust = newtonThrust.ThrustInNewtons / mass_Kg; //per second Vector3 manuverDV = newtonMoveDB.DeltaVForManuver_m; //how much dv needed to complete the manuver. double dryMass = mass_Kg - newtonThrust.FuelBurnRate * timeStepInSeconds; //how much our ship weighs after a timestep of fuel is used. //how much dv can we get in this timestep. double deltaVThisStep = OrbitMath.TsiolkovskyRocketEquation(mass_Kg, dryMass, newtonThrust.ExhaustVelocity); deltaVThisStep = Math.Min(manuverDV.Length(), deltaVThisStep); //don't use more Dv than what is called for. deltaVThisStep = Math.Min(newtonThrust.DeltaV, deltaVThisStep); //check we've got the deltaV to spend. Vector3 totalDVFromThrust = Vector3.Normalise(manuverDV) * deltaVThisStep; //remove the deltaV we're expending from the max (TODO: Remove fuel from cargo, change mass of ship) newtonThrust.DeltaV -= deltaVThisStep; //remove the vectorDV from the amount needed to fully complete the manuver. newtonMoveDB.DeltaVForManuver_m -= totalDVFromThrust; Vector3 totalDV = totalDVFromGrav + totalDVFromThrust; Vector3 newVelocity = totalDV + newtonMoveDB.CurrentVector_ms; newtonMoveDB.CurrentVector_ms = newVelocity; Vector3 deltaPos = (newtonMoveDB.CurrentVector_ms + newVelocity) / 2 * timeStepInSeconds; positionDB.RelativePosition_m += deltaPos; double sOIRadius = OrbitProcessor.GetSOI_m(newtonMoveDB.SOIParent); if (positionDB.RelativePosition_m.Length() >= sOIRadius) { 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_m(orbitDB, entity.StarSysDateTime); parentRalitiveVector = newtonMoveDB.CurrentVector_ms + parentVelocity; } 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_ms; parentRalitiveVector = newtonMoveDB.CurrentVector_ms + parentVelocity; } parentMass_kg = newParent.GetDataBlob <MassVolumeDB>().Mass; Vector3 posRalitiveToNewParent = positionDB.AbsolutePosition_m - newParent.GetDataBlob <PositionDB>().AbsolutePosition_m; var dateTime = dateTimeNow + TimeSpan.FromSeconds(deltaSeconds - secondsToItterate); double sgp = GMath.StandardGravitationalParameter(parentMass_kg + mass_Kg); var kE = OrbitMath.KeplerFromPositionAndVelocity(sgp, posRalitiveToNewParent, parentRalitiveVector, dateTime); positionDB.SetParent(newParent); newtonMoveDB.ParentMass = parentMass_kg; newtonMoveDB.SOIParent = newParent; newtonMoveDB.CurrentVector_ms = parentRalitiveVector; } if (newtonMoveDB.DeltaVForManuver_m.Length() <= 0) //if we've completed the manuver. { var dateTime = dateTimeNow + TimeSpan.FromSeconds(deltaSeconds - secondsToItterate); double sgp = GMath.StandardGravitationalParameter(parentMass_kg + mass_Kg); KeplerElements kE = OrbitMath.KeplerFromPositionAndVelocity(sgp, positionDB.RelativePosition_m, newtonMoveDB.CurrentVector_ms, dateTime); var parentEntity = Entity.GetSOIParentEntity(entity, positionDB); if (kE.Eccentricity < 1) //if we're going to end up in a regular orbit around our new parent { var newOrbit = OrbitDB.FromKeplerElements( parentEntity, mass_Kg, kE, dateTime); entity.RemoveDataBlob <NewtonMoveDB>(); entity.SetDataBlob(newOrbit); positionDB.SetParent(parentEntity); var newPos = OrbitProcessor.GetPosition_m(newOrbit, dateTime); positionDB.RelativePosition_m = newPos; } break; } secondsToItterate -= timeStepInSeconds; } newtonMoveDB.LastProcessDateTime = dateTimeFuture; }
internal override void ActionCommand(DateTime atDateTime) { if (atDateTime < ActionOnDate) { return; } if (!IsRunning) { IsRunning = true; _newtonAbilityDB = _entityCommanding.GetDataBlob <NewtonThrustAbilityDB>(); _startDV = _newtonAbilityDB.DeltaV; _fuelBurnRate = _newtonAbilityDB.FuelBurnRate; _totalFuel = _newtonAbilityDB.TotalFuel_kg; var soiParentEntity = Entity.GetSOIParentEntity(_entityCommanding); _soiParentMass = soiParentEntity.GetDataBlob <MassVolumeDB>().MassDry; var currentVel = Entity.GetRalitiveFutureVelocity(_entityCommanding, atDateTime); if (_entityCommanding.HasDataBlob <OrbitDB>()) { _entityCommanding.RemoveDataBlob <OrbitDB>(); } if (_entityCommanding.HasDataBlob <OrbitUpdateOftenDB>()) { _entityCommanding.RemoveDataBlob <OrbitUpdateOftenDB>(); } if (_entityCommanding.HasDataBlob <NewtonMoveDB>()) { _newtonMovedb = _entityCommanding.GetDataBlob <NewtonMoveDB>(); } else { _newtonMovedb = new NewtonMoveDB(soiParentEntity, currentVel); } _entityCommanding.SetDataBlob(_newtonMovedb); } var halfDV = _startDV * 0.5; //lets burn half the dv getting into a good intercept. var dvUsed = _startDV - _newtonAbilityDB.DeltaV; var dvToUse = halfDV - dvUsed; if (dvToUse > 0) { (Vector3 Position, Vector3 Velocity)curOurRalState = Entity.GetRalitiveState(_entityCommanding); (Vector3 Position, Vector3 Velocity)curTgtRalState = Entity.GetRalitiveState(_targetEntity); var dvRemaining = _newtonAbilityDB.DeltaV; var tgtVelocity = Entity.GetAbsoluteFutureVelocity(_targetEntity, atDateTime); //calculate the differencecs in velocity vectors. Vector3 leadToTgt = (curTgtRalState.Velocity - curOurRalState.Velocity); //convert the lead to an orbit ralitive (prograde Y) vector. //var manuverVector = OrbitMath.GlobalToOrbitVector(leadToTgt, curOurRalState.Position, curOurRalState.Velocity); var burnRate = _newtonAbilityDB.FuelBurnRate; //var foo = OrbitMath.TsiolkovskyFuelUse(_totalFuel, ) var fuelUse = OrbitMath.TsiolkovskyFuelCost( _newtonAbilityDB.TotalFuel_kg, _newtonAbilityDB.ExhaustVelocity, dvToUse//pretty sure this should be dvToUse, but that's giving me a silent crash. ); var burnTime = fuelUse / burnRate; var manuverVector = ManuverVector(dvToUse, burnTime, curOurRalState, curTgtRalState, atDateTime); _newtonMovedb.DeltaVForManuver_FoRO_m = manuverVector; _entityCommanding.Manager.ManagerSubpulses.AddEntityInterupt(atDateTime + TimeSpan.FromSeconds(5), nameof(OrderableProcessor), _entityCommanding); } else { _newtonMovedb.DeltaVForManuver_FoRO_m = new Vector3(); } }