@ -13,7 +13,7 @@ namespace Aerostats
private static readonly float ZeroCelsius = 2 7 3.15f ;
private static readonly float StandardPressure = 1 0 0 0 0 0.0f ;
private static readonly float StpVolumeToMoles = 1 0 0 0 0 0.0f / R / 2 7 3.15f ;
/// <summary>
/// Maximum rate at which gas can be injected in the balloon to fill it, in m^3/s at stp
/// </summary>
@ -79,38 +79,44 @@ namespace Aerostats
[KSPField(isPersistant = false, guiActive = false)]
public float SpringHardness = 5 0 0 0.0f ;
private bool Staged ;
[KSPField(isPersistant = false, guiActive = true)]
public string Status ;
private bool Deployed ;
private bool Destroyed ;
/// <summary>
/// Gas quantity currently inside the balloon
/// </summary>
[KSPField(isPersistant = true, guiActive = true)]
[KSPField(guiName = "Gas quantity", isPersistant = true, guiActive = true)]
public float LiftingGasQuantity ;
[KSPField(guiName = "Volume", isPersistant = false, guiActive = true)]
public string VolumeStatus ;
/// <summary>
/// Inflation ratio of the balloon (0=empty, 1=maximum)
/// </summary>
private float Inflation = 0 ;
private float Radius = 0.01f ;
private GameObject Balloon ;
private LineRenderer Spring ;
private Vector3 EstimatedNextFramePosition ;
public override void OnStart ( PartModule . StartState state )
{
if ( ! HighLogic . LoadedSceneIsEditor & & ! HighLogic . LoadedSceneIsFlight ) { return ; }
[KSPEvent(guiActive = true, active = true, externalToEVAOnly = false, guiActiveUnfocused = true, guiName = "Deploy balloon", unfocusedRange = 5)]
public void Deploy ( )
{
if ( Destroyed | | Deployed )
return ;
ScreenMessages . PostScreenMessage ( "Aerostat loaded" ) ;
part . stagingIcon = "PARACHUTES" ;
}
Deployed = true ;
private void OnStaged ( )
{
UnityEngine . Debug . Log ( "Aerostats: staged" ) ;
ScreenMessages . PostScreenMessage ( "staged" ) ;
Util . PostScreenMessage ( "staged" ) ;
Balloon = GameObject . CreatePrimitive ( PrimitiveType . Sphere ) ;
Balloon . transform . position = part . Rigidbody . position + part . Rigidbody . transform . up ;
@ -131,35 +137,55 @@ namespace Aerostats
part . OnJustAboutToBeDestroyed + = OnPartDestroyed ;
EstimatedNextFramePosition = part . Rigidbody . position ;
EstimatedNextFramePosition = part . Rigidbody . position ;
}
private void OnPartDestroyed ( )
{
[KSPEvent(guiActive = true, active = true, externalToEVAOnly = false, guiActiveUnfocused = true, guiName = "Cut rope", unfocusedRange = 5)]
public void Cut ( )
{
if ( Destroyed | | ! Deployed )
return ;
Destroy ( Balloon ) ; // another option could be to let it float freely, but in this case the buoyancy code should be implemented in a separate MonoBehavior
Balloon = null ;
Spring = null ;
part . OnJustAboutToBeDestroyed - = OnPartDestroyed ;
Destroyed = true ;
Destroyed = true ;
}
public override void OnStart ( PartModule . StartState state )
{
if ( ! HighLogic . LoadedSceneIsEditor & & ! HighLogic . LoadedSceneIsFlight ) { return ; }
Util . PostScreenMessage ( "Aerostat loaded" ) ;
part . stagingIcon = "PARACHUTES" ;
}
private void OnPartDestroyed ( )
{
Cut ( ) ;
}
private void FixedUpdate ( )
{
if ( Destroyed )
{
Status = "separated" ;
VolumeStatus = "-" ;
return ;
}
if ( ! Staged & & GameSettings . LAUNCH_STAGES . GetKeyDown ( ) & & vessel . isActiveVessel & & ( part . inverseStage = = Staging . CurrentStage - 1 | | Staging . CurrentStage = = 0 ) )
if ( GameSettings . LAUNCH_STAGES . GetKeyDown ( ) & & vessel . isActiveVessel & & ( part . inverseStage = = Staging . CurrentStage - 1 | | Staging . CurrentStage = = 0 ) )
{
Staged = true ;
OnStaged ( ) ;
Deploy ( ) ;
}
if ( Stag ed)
if ( Deploy ed)
{
// detect Krakensbane teleportation, and fix up the balloon position (otherwise it results in instant ship disintegration due to extreme forces on the spring)
if ( ( part . Rigidbody . position - EstimatedNextFramePosition ) . magnitude > 1 0 0 0.0f )
if ( ( part . Rigidbody . position - EstimatedNextFramePosition ) . magnitude > 1 0 0 0.0f )
{
ScreenMessages . PostScreenMessage ( "Krakensbane teleportation detected! (dist=" + ( part . Rigidbody . position - EstimatedNextFramePosition ) . magnitude + ")" ) ;
Util . PostScreenMessage ( "Krakensbane teleportation detected! (dist=" + ( part . Rigidbody . position - EstimatedNextFramePosition ) . magnitude + ")" ) ;
var offset = part . rigidbody . position - EstimatedNextFramePosition ;
Balloon . rigidbody . position + = offset ;
Balloon . transform . position = Balloon . rigidbody . position ;
@ -179,11 +205,21 @@ namespace Aerostats
// 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 ) ;
float stepResource = part . RequestResource ( "Helium" , step ) ;
LiftingGasQuantity + = stepResource ;
if ( step > 0.0f )
{
Status = stepResource > 0.0f ? "inflating" : "out-of-gas" ;
}
else
{
Status = "nominal" ;
}
}
else
{
// deflating balloon
Status = LiftingGasTargetQuantity = = LiftingGasQuantity ? "nominal" : "deflating" ;
LiftingGasQuantity = Math . Max ( LiftingGasQuantity - MaxGasVentRate * Time . fixedDeltaTime , LiftingGasTargetQuantity ) ;
}
@ -191,6 +227,7 @@ namespace Aerostats
// balloon security valve
if ( LiftingGasQuantity > currentMaxQuantity )
{
Status = "full (venting)" ;
Util . PostSingleScreenMessage ( "security valve" , "Some gas has been vented by the balloon security valve" ) ;
LiftingGasQuantity = currentMaxQuantity ;
}
@ -198,6 +235,7 @@ namespace Aerostats
float currentGasMoles = StpVolumeToMoles * LiftingGasQuantity ;
float currentGasVolume = currentGasMoles * R * balloonInternalTemperature / externalPressure ;
Inflation = currentGasVolume / MaxBalloonVolume ;
VolumeStatus = Mathf . Round ( currentGasVolume ) + " / " + Mathf . Round ( MaxBalloonVolume ) ;
Util . PostSingleScreenMessage ( "inflation" , "Inflation = " + ( Inflation * 1 0 0.0f ) . ToString ( "0.00" ) + "%" ) ;
@ -210,8 +248,8 @@ namespace Aerostats
//Util.PostSingleScreenMessage("gravity", "Gravity accel = (" + gravityAccel.x + ", " + gravityAccel.y + ", " + gravityAccel.z + ")");
// V = 4/3*pi*r^3
float r adius = Mathf . Pow ( currentGasVolume * 0.75f / Mathf . PI , 0.333f ) ;
float scale = r adius * 2.0f + 0.1f ;
R adius = Mathf . Pow ( currentGasVolume * 0.75f / Mathf . PI , 0.333f ) ;
float scale = R adius * 2.0f + 0.1f ;
Balloon . transform . localScale = new Vector3 ( scale , scale , scale ) ;
Balloon . rigidbody . mass = ( BalloonEmptyMass + balloonGasMass ) * 0.001f ;
@ -221,16 +259,16 @@ namespace Aerostats
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 * r adius) ;
float dragForce = 0.5f * airDensity * sqVel * BalloonDragCoeff * ( Mathf . PI * Radius * R adius) ;
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 + r adius;
float restLength = SpringRestLength + R adius;
var springVec = Balloon . rigidbody . position - part . rigidbody . position ;
float springLength = springVec . magnitude ;
float springForceMag = 0 ;
var balloonAttachPoint = Balloon . rigidbody . position - Balloon . transform . up . normalized * r adius;
var balloonAttachPoint = Balloon . rigidbody . position - Balloon . transform . up . normalized * R adius;
if ( springLength > restLength )
{
float tensingLength = springLength - restLength ;
@ -240,6 +278,22 @@ namespace Aerostats
Balloon . rigidbody . AddForceAtPosition ( - springForce , balloonAttachPoint , ForceMode . Force ) ;
}
Util . PostSingleScreenMessage ( "spring force" , "Spring force = " + springForceMag + "N" ) ;
}
else
{
Status = "packed" ;
VolumeStatus = "-" ;
}
}
private void LateUpdate ( )
{
if ( Destroyed )
return ;
if ( Deployed )
{
var balloonAttachPoint = Balloon . rigidbody . position - Balloon . transform . up . normalized * Radius ;
Spring . SetPosition ( 0 , part . transform . position ) ;
Spring . SetPosition ( 1 , balloonAttachPoint ) ;