@ -8,12 +8,6 @@ namespace Aerostats
{
{
public class ModuleAerostat : PartModule
public class ModuleAerostat : PartModule
{
{
[KSPField(isPersistant = false, guiActive = false)]
public string DeployAnimation = "semiDeploy" ;
[KSPField(isPersistant = false, guiActive = false)]
public string InflateAnimation = "fullyDeploy" ;
// In this class, amount of gas Q is specified in m^3 at stp (standard pressure of 100kPa and temperature of 0°C = 273K). Ideal gas equation P.V = n.R.T gives us the equivalent number of moles: n = P.V/R/T = 100000.Q/8.314/273 = 44.Q mol
// In this class, amount of gas Q is specified in m^3 at stp (standard pressure of 100kPa and temperature of 0°C = 273K). Ideal gas equation P.V = n.R.T gives us the equivalent number of moles: n = P.V/R/T = 100000.Q/8.314/273 = 44.Q mol
private static readonly float R = 8.314f ;
private static readonly float R = 8.314f ;
private static readonly float ZeroCelsius = 2 7 3.15f ;
private static readonly float ZeroCelsius = 2 7 3.15f ;
@ -39,16 +33,6 @@ namespace Aerostats
[KSPField(isPersistant = false, guiActive = false)]
[KSPField(isPersistant = false, guiActive = false)]
public float MaxBalloonVolume = 1 0 0 0 0 ;
public float MaxBalloonVolume = 1 0 0 0 0 ;
/// <summary>
/// Maximum initial reserve of compressed gas, in m^3 at stp
/// For helium, the volume needed to store this reserve is about 0.0014m^3 of compressed storage (liquid) for 1m^3 of gas at stp
/// </summary>
[KSPField(isPersistant = false, guiActive = false)]
public float CompressedGasStorage = 1 5 0 0 0 ;
[KSPField(isPersistant = true, guiActive = true)]
public float RemainingCompressedGas = 1 5 0 0 0 ;
/// <summary>
/// <summary>
/// Weight, in kilograms, of 1m^3 of gas at 100kPa and 0°C
/// Weight, in kilograms, of 1m^3 of gas at 100kPa and 0°C
/// Helium is 179g/m^3
/// Helium is 179g/m^3
@ -112,35 +96,6 @@ namespace Aerostats
private GameObject Balloon ;
private GameObject Balloon ;
private LineRenderer Spring ;
private LineRenderer Spring ;
private void PlayAnimation ( string animationName , float animationSpeed )
{
foreach ( Animation animation in part . FindModelAnimators ( animationName ) )
{
AnimationState state = animation [ animationName ] ;
state . normalizedTime = 0 ;
state . normalizedSpeed = animationSpeed ;
state . enabled = true ;
animation . Play ( animationName ) ;
}
}
private bool IsAnimationPlaying ( string animationName )
{
return part . FindModelAnimators ( animationName ) . Any ( a = > a [ animationName ] . enabled ) ;
}
private void SetInflation ( float ratio )
{
foreach ( Animation animation in part . FindModelAnimators ( InflateAnimation ) )
{
AnimationState state = animation [ InflateAnimation ] ;
state . normalizedTime = ratio ;
state . normalizedSpeed = 0 ;
state . enabled = true ;
animation . Play ( InflateAnimation ) ;
}
}
public override void OnStart ( PartModule . StartState state )
public override void OnStart ( PartModule . StartState state )
{
{
if ( ! HighLogic . LoadedSceneIsEditor & & ! HighLogic . LoadedSceneIsFlight ) { return ; }
if ( ! HighLogic . LoadedSceneIsEditor & & ! HighLogic . LoadedSceneIsFlight ) { return ; }
@ -153,7 +108,6 @@ namespace Aerostats
{
{
UnityEngine . Debug . Log ( "Aerostats: staged" ) ;
UnityEngine . Debug . Log ( "Aerostats: staged" ) ;
ScreenMessages . PostScreenMessage ( "staged" ) ;
ScreenMessages . PostScreenMessage ( "staged" ) ;
//PlayAnimation(DeployAnimation, 1.0f);
Balloon = GameObject . CreatePrimitive ( PrimitiveType . Sphere ) ;
Balloon = GameObject . CreatePrimitive ( PrimitiveType . Sphere ) ;
Balloon . transform . position = part . Rigidbody . position + part . Rigidbody . transform . up ;
Balloon . transform . position = part . Rigidbody . position + part . Rigidbody . transform . up ;
@ -162,8 +116,7 @@ namespace Aerostats
Balloon . rigidbody . angularDrag = 1 0.0f ;
Balloon . rigidbody . angularDrag = 1 0.0f ;
LiftingGasQuantity = Math . Min ( MinimumFillQuantity , RemainingCompressedGas ) ;
LiftingGasQuantity = part . RequestResource ( "Helium" , MinimumFillQuantity ) ;
RemainingCompressedGas - = LiftingGasQuantity ;
Spring = Balloon . AddComponent < LineRenderer > ( ) ;
Spring = Balloon . AddComponent < LineRenderer > ( ) ;
Spring . useWorldSpace = true ;
Spring . useWorldSpace = true ;
@ -193,96 +146,83 @@ namespace Aerostats
if ( Staged )
if ( Staged )
{
{
//if (!IsAnimationPlaying(DeployAnimation))
float externalTemperature = ( float ) FlightGlobals . getExternalTemperature ( ) ;
float balloonInternalTemperature = externalTemperature ;
float externalPressure = Math . Max ( ( float ) FlightGlobals . getStaticPressure ( ) * 1 0 0 0.0f , 0.00001f ) ;
Util . PostSingleScreenMessage ( "external atmo" , "Temperature = " + externalTemperature + "K, Pressure=" + externalPressure + "Pa" ) ;
float currentMaxQuantity = MaxBalloonVolume / R / balloonInternalTemperature * externalPressure / StpVolumeToMoles ;
LiftingGasTargetQuantity = Math . Max ( MinimumFillQuantity , LiftingGasTargetQuantity ) ;
if ( LiftingGasTargetQuantity > LiftingGasQuantity )
{
// infalting balloon
float stepFinalQuantity = Math . Min ( LiftingGasQuantity + MaxGasFillRate * Time . fixedDeltaTime , Math . Min ( LiftingGasTargetQuantity , currentMaxQuantity ) ) ;
float step = Math . Max ( stepFinalQuantity - LiftingGasQuantity , 0.0f ) ;
LiftingGasQuantity + = part . RequestResource ( "Helium" , step ) ;
}
else
{
{
float externalTemperature = ( float ) FlightGlobals . getExternalTemperature ( ) ;
// deflating balloon
float balloonInternalTemperature = externalTemperature ;
LiftingGasQuantity = Math . Max ( LiftingGasQuantity - MaxGasVentRate * Time . fixedDeltaTime , LiftingGasTargetQuantity ) ;
float externalPressure = Math . Max ( ( float ) FlightGlobals . getStaticPressure ( ) * 1 0 0 0.0f , 0.00001f ) ;
Util . PostSingleScreenMessage ( "external atmo" , "Temperature = " + externalTemperature + "K, Pressure=" + externalPressure + "Pa" ) ;
float currentMaxQuantity = MaxBalloonVolume / R / balloonInternalTemperature * externalPressure / StpVolumeToMoles ;
LiftingGasTargetQuantity = Math . Max ( MinimumFillQuantity , LiftingGasTargetQuantity ) ;
if ( LiftingGasTargetQuantity > LiftingGasQuantity )
{
// infalting balloon
float stepFinalQuantity = Math . Min ( LiftingGasQuantity + MaxGasFillRate * Time . fixedDeltaTime , Math . Min ( LiftingGasTargetQuantity , currentMaxQuantity ) ) ;
float step = Math . Max ( stepFinalQuantity - LiftingGasQuantity , 0.0f ) ;
LiftingGasQuantity + = step ;
RemainingCompressedGas - = step ;
// gas exhausted
if ( RemainingCompressedGas < 0 )
{
Util . PostSingleScreenMessage ( "out of gas" , "Lifting gas reserve exhausted" ) ;
LiftingGasQuantity + = RemainingCompressedGas ;
RemainingCompressedGas = 0 ;
}
}
else
{
// deflating balloon
LiftingGasQuantity = Math . Max ( LiftingGasQuantity - MaxGasVentRate * Time . fixedDeltaTime , LiftingGasTargetQuantity ) ;
}
// balloon security valve
if ( LiftingGasQuantity > currentMaxQuantity )
{
Util . PostSingleScreenMessage ( "security valve" , "Some gas has been vented by the balloon security valve" ) ;
LiftingGasQuantity = currentMaxQuantity ;
}
float currentGasMoles = StpVolumeToMoles * LiftingGasQuantity ;
float currentGasVolume = currentGasMoles * R * balloonInternalTemperature / externalPressure ;
Inflation = currentGasVolume / MaxBalloonVolume ;
Util . PostSingleScreenMessage ( "inflation" , "Inflation = " + ( Inflation * 1 0 0.0f ) . ToString ( "0.00" ) + "%" ) ;
//SetInflation(Inflation);
float airDensity = ( float ) FlightGlobals . getAtmDensity ( externalPressure / 1 0 0 0.0f , externalTemperature , vessel . mainBody ) ;
float currentGasDensity = GasDensity * balloonInternalTemperature / ZeroCelsius / externalPressure * StandardPressure ;
float balloonLift = currentGasVolume * airDensity ;
float balloonGasMass = currentGasDensity * currentGasVolume ;
Util . PostSingleScreenMessage ( "lift" , "Air density = " + airDensity + "kg/m^3, Lift = " + ( balloonLift - balloonGasMass ) + "kg" ) ;
var gravityAccel = FlightGlobals . getGeeForceAtPosition ( vessel . GetWorldPos3D ( ) ) ;
//Util.PostSingleScreenMessage("gravity", "Gravity accel = (" + gravityAccel.x + ", " + gravityAccel.y + ", " + gravityAccel.z + ")");
// V = 4/3*pi*r^3
float radius = Mathf . Pow ( currentGasVolume * 0.75f / Mathf . PI , 0.333f ) ;
float scale = radius * 2.0f + 0.1f ;
Balloon . transform . localScale = new Vector3 ( scale , scale , scale ) ;
Balloon . rigidbody . mass = ( BalloonEmptyMass + balloonGasMass ) * 0.001f ;
Balloon . rigidbody . AddForce ( - gravityAccel * balloonLift / 1 0 0 0.0f , ForceMode . Force ) ;
// balloon drag
var airVelocity = Balloon . rigidbody . velocity + Krakensbane . GetFrameVelocity ( ) /*- vessel.mainBody.getRFrmVel(vessel.GetWorldPos3D())*/ ;
float sqVel = ( float ) airVelocity . magnitude ;
sqVel * = sqVel ;
float dragForce = 0.5f * airDensity * sqVel * BalloonDragCoeff * ( Mathf . PI * radius * radius ) ;
Util . PostSingleScreenMessage ( "balloon drag" , "Drag = " + dragForce + "N" ) ;
Balloon . rigidbody . AddForce ( - airVelocity . normalized * dragForce / 1 0 0 0.0f , ForceMode . Force ) ;
// spring between balloon and base
float restLength = SpringRestLength + radius ;
var springVec = Balloon . rigidbody . position - part . rigidbody . position ;
float springLength = springVec . magnitude ;
float springForceMag = 0 ;
var balloonAttachPoint = Balloon . rigidbody . position - Balloon . transform . up . normalized * radius ;
if ( springLength > restLength )
{
float tensingLength = springLength - restLength ;
springForceMag = tensingLength * SpringHardness ;
var springForce = springVec * ( springForceMag / springLength * 0.001f ) ;
part . rigidbody . AddForce ( springForce , ForceMode . Force ) ;
Balloon . rigidbody . AddForceAtPosition ( - springForce , balloonAttachPoint , ForceMode . Force ) ;
}
Util . PostSingleScreenMessage ( "spring force" , "Spring force = " + springForceMag + "N" ) ;
Spring . SetPosition ( 0 , part . transform . position ) ;
Spring . SetPosition ( 1 , balloonAttachPoint ) ;
}
}
// balloon security valve
if ( LiftingGasQuantity > currentMaxQuantity )
{
Util . PostSingleScreenMessage ( "security valve" , "Some gas has been vented by the balloon security valve" ) ;
LiftingGasQuantity = currentMaxQuantity ;
}
float currentGasMoles = StpVolumeToMoles * LiftingGasQuantity ;
float currentGasVolume = currentGasMoles * R * balloonInternalTemperature / externalPressure ;
Inflation = currentGasVolume / MaxBalloonVolume ;
Util . PostSingleScreenMessage ( "inflation" , "Inflation = " + ( Inflation * 1 0 0.0f ) . ToString ( "0.00" ) + "%" ) ;
float airDensity = ( float ) FlightGlobals . getAtmDensity ( externalPressure / 1 0 0 0.0f , externalTemperature , vessel . mainBody ) ;
float currentGasDensity = GasDensity * balloonInternalTemperature / ZeroCelsius / externalPressure * StandardPressure ;
float balloonLift = currentGasVolume * airDensity ;
float balloonGasMass = currentGasDensity * currentGasVolume ;
Util . PostSingleScreenMessage ( "lift" , "Air density = " + airDensity + "kg/m^3, Lift = " + ( balloonLift - balloonGasMass ) + "kg" ) ;
var gravityAccel = FlightGlobals . getGeeForceAtPosition ( vessel . GetWorldPos3D ( ) ) ;
//Util.PostSingleScreenMessage("gravity", "Gravity accel = (" + gravityAccel.x + ", " + gravityAccel.y + ", " + gravityAccel.z + ")");
// V = 4/3*pi*r^3
float radius = Mathf . Pow ( currentGasVolume * 0.75f / Mathf . PI , 0.333f ) ;
float scale = radius * 2.0f + 0.1f ;
Balloon . transform . localScale = new Vector3 ( scale , scale , scale ) ;
Balloon . rigidbody . mass = ( BalloonEmptyMass + balloonGasMass ) * 0.001f ;
Balloon . rigidbody . AddForce ( - gravityAccel * balloonLift / 1 0 0 0.0f , ForceMode . Force ) ;
// balloon drag
var airVelocity = Balloon . rigidbody . velocity + Krakensbane . GetFrameVelocity ( ) /*- vessel.mainBody.getRFrmVel(vessel.GetWorldPos3D())*/ ;
float sqVel = ( float ) airVelocity . magnitude ;
sqVel * = sqVel ;
float dragForce = 0.5f * airDensity * sqVel * BalloonDragCoeff * ( Mathf . PI * radius * radius ) ;
Util . PostSingleScreenMessage ( "balloon drag" , "Drag = " + dragForce + "N" ) ;
Balloon . rigidbody . AddForce ( - airVelocity . normalized * dragForce / 1 0 0 0.0f , ForceMode . Force ) ;
// spring between balloon and base
float restLength = SpringRestLength + radius ;
var springVec = Balloon . rigidbody . position - part . rigidbody . position ;
float springLength = springVec . magnitude ;
float springForceMag = 0 ;
var balloonAttachPoint = Balloon . rigidbody . position - Balloon . transform . up . normalized * radius ;
if ( springLength > restLength )
{
float tensingLength = springLength - restLength ;
springForceMag = tensingLength * SpringHardness ;
var springForce = springVec * ( springForceMag / springLength * 0.001f ) ;
part . rigidbody . AddForce ( springForce , ForceMode . Force ) ;
Balloon . rigidbody . AddForceAtPosition ( - springForce , balloonAttachPoint , ForceMode . Force ) ;
}
Util . PostSingleScreenMessage ( "spring force" , "Spring force = " + springForceMag + "N" ) ;
Spring . SetPosition ( 0 , part . transform . position ) ;
Spring . SetPosition ( 1 , balloonAttachPoint ) ;
}
}
}
}
}
}