added helium resource, with the corresponding tank part (wip)
This commit is contained in:
parent
67bdfa615c
commit
a49fb7b123
@ -11,11 +11,11 @@ PART
|
|||||||
sound_parachute_open = activate
|
sound_parachute_open = activate
|
||||||
TechRequired = advLanding
|
TechRequired = advLanding
|
||||||
entryCost = 3500
|
entryCost = 3500
|
||||||
cost = 400
|
cost = 5000
|
||||||
category = Utility
|
category = Utility
|
||||||
subcategory = 0
|
subcategory = 0
|
||||||
title = Balloon
|
title = Balloon
|
||||||
description = A test balloon.
|
description = A big balloon that can be inflated with helium (sold separately).
|
||||||
attachRules = 1,0,0,1,0
|
attachRules = 1,0,0,1,0
|
||||||
mass = 0.2
|
mass = 0.2
|
||||||
dragModelType = default
|
dragModelType = default
|
||||||
@ -30,7 +30,5 @@ PART
|
|||||||
MODULE
|
MODULE
|
||||||
{
|
{
|
||||||
name = ModuleAerostat
|
name = ModuleAerostat
|
||||||
DeployAnimation = semiDeployLarge
|
|
||||||
InflateAnimation = fullyDeployLarge
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
31
Parts/HeliumTankRadial/heliumTankRadial.cfg
Normal file
31
Parts/HeliumTankRadial/heliumTankRadial.cfg
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
PART
|
||||||
|
{
|
||||||
|
name = heliumTankRadial
|
||||||
|
module = Part
|
||||||
|
author = Youen
|
||||||
|
mesh = model.mu
|
||||||
|
rescaleFactor = 1
|
||||||
|
node_attach = 0.0, 0.0, -0.1875, 0.0, 0.0, -1.0
|
||||||
|
TechRequired = advLanding
|
||||||
|
entryCost = 2000
|
||||||
|
cost = 2200
|
||||||
|
category = FuelTank
|
||||||
|
subcategory = 0
|
||||||
|
title = Helium tank
|
||||||
|
description = Disposable helium tank for all your lifting needs (and birthday party balloons). Do not refill after use.
|
||||||
|
attachRules = 0,1,0,0,1
|
||||||
|
mass = 0.003
|
||||||
|
dragModelType = default
|
||||||
|
maximum_drag = 0.2
|
||||||
|
minimum_drag = 0.2
|
||||||
|
angularDrag = 2
|
||||||
|
crashTolerance = 12
|
||||||
|
maxTemp = 2000 // = 2900
|
||||||
|
bulkheadProfiles = srf
|
||||||
|
RESOURCE
|
||||||
|
{
|
||||||
|
name = Helium
|
||||||
|
amount = 30
|
||||||
|
maxAmount = 30
|
||||||
|
}
|
||||||
|
}
|
BIN
Parts/HeliumTankRadial/ksp_r_xenonTank_diff.dds
Normal file
BIN
Parts/HeliumTankRadial/ksp_r_xenonTank_diff.dds
Normal file
Binary file not shown.
BIN
Parts/HeliumTankRadial/model.mu
Normal file
BIN
Parts/HeliumTankRadial/model.mu
Normal file
Binary file not shown.
@ -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 = 273.15f;
|
private static readonly float ZeroCelsius = 273.15f;
|
||||||
@ -39,16 +33,6 @@ namespace Aerostats
|
|||||||
[KSPField(isPersistant = false, guiActive = false)]
|
[KSPField(isPersistant = false, guiActive = false)]
|
||||||
public float MaxBalloonVolume = 10000;
|
public float MaxBalloonVolume = 10000;
|
||||||
|
|
||||||
/// <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 = 15000;
|
|
||||||
|
|
||||||
[KSPField(isPersistant = true, guiActive = true)]
|
|
||||||
public float RemainingCompressedGas = 15000;
|
|
||||||
|
|
||||||
/// <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 = 10.0f;
|
Balloon.rigidbody.angularDrag = 10.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() * 1000.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)
|
||||||
{
|
{
|
||||||
float externalTemperature = (float)FlightGlobals.getExternalTemperature();
|
// infalting balloon
|
||||||
float balloonInternalTemperature = externalTemperature;
|
float stepFinalQuantity = Math.Min(LiftingGasQuantity + MaxGasFillRate * Time.fixedDeltaTime, Math.Min(LiftingGasTargetQuantity, currentMaxQuantity));
|
||||||
float externalPressure = Math.Max((float)FlightGlobals.getStaticPressure() * 1000.0f, 0.00001f);
|
float step = Math.Max(stepFinalQuantity - LiftingGasQuantity, 0.0f);
|
||||||
Util.PostSingleScreenMessage("external atmo", "Temperature = " + externalTemperature + "K, Pressure=" + externalPressure + "Pa");
|
LiftingGasQuantity += part.RequestResource("Helium", step);
|
||||||
|
|
||||||
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 * 100.0f).ToString("0.00") + "%");
|
|
||||||
//SetInflation(Inflation);
|
|
||||||
|
|
||||||
float airDensity = (float)FlightGlobals.getAtmDensity(externalPressure / 1000.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 / 1000.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 / 1000.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);
|
|
||||||
}
|
}
|
||||||
|
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 * 100.0f).ToString("0.00") + "%");
|
||||||
|
|
||||||
|
float airDensity = (float)FlightGlobals.getAtmDensity(externalPressure / 1000.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 / 1000.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 / 1000.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
TweakScale.cfg
Normal file
16
TweakScale.cfg
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
@PART[heliumTankRadial]
|
||||||
|
{
|
||||||
|
%MODULE[TweakScale]
|
||||||
|
{
|
||||||
|
type = free
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PART[balloon]
|
||||||
|
{
|
||||||
|
%MODULE[TweakScale]
|
||||||
|
{
|
||||||
|
type = stack
|
||||||
|
defaultScale = 1.25
|
||||||
|
}
|
||||||
|
}
|
10
resources.cfg
Normal file
10
resources.cfg
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
RESOURCE_DEFINITION
|
||||||
|
{
|
||||||
|
name = Helium
|
||||||
|
density = 0.000179 // storage unit is m^3 of Helium at standard pressure (100kPa, 0°C), which has a density of 0.179kg/m^3 (helium tanks store liquid helium which occupies less space, but still weights the same)
|
||||||
|
unitCost = 1.2
|
||||||
|
hsp = 3000
|
||||||
|
flowMode = STAGE_PRIORITY_FLOW
|
||||||
|
transfer = PUMP
|
||||||
|
isTweakable = true
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user