Browse Source

added helium resource, with the corresponding tank part (wip)

master
Youen Toupin 10 years ago
parent
commit
a49fb7b123
  1. 6
      Parts/Balloon/balloon.cfg
  2. 31
      Parts/HeliumTankRadial/heliumTankRadial.cfg
  3. BIN
      Parts/HeliumTankRadial/ksp_r_xenonTank_diff.dds
  4. BIN
      Parts/HeliumTankRadial/model.mu
  5. 210
      Plugin/ModuleAerostat.cs
  6. 16
      TweakScale.cfg
  7. 10
      resources.cfg

6
Parts/Balloon/balloon.cfg

@ -11,11 +11,11 @@ PART
sound_parachute_open = activate
TechRequired = advLanding
entryCost = 3500
cost = 400
cost = 5000
category = Utility
subcategory = 0
title = Balloon
description = A test balloon.
description = A big balloon that can be inflated with helium (sold separately).
attachRules = 1,0,0,1,0
mass = 0.2
dragModelType = default
@ -30,7 +30,5 @@ PART
MODULE
{
name = ModuleAerostat
DeployAnimation = semiDeployLarge
InflateAnimation = fullyDeployLarge
}
}

31
Parts/HeliumTankRadial/heliumTankRadial.cfg

@ -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

Binary file not shown.

BIN
Parts/HeliumTankRadial/model.mu

Binary file not shown.

210
Plugin/ModuleAerostat.cs

@ -8,12 +8,6 @@ namespace Aerostats
{
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
private static readonly float R = 8.314f;
private static readonly float ZeroCelsius = 273.15f;
@ -39,16 +33,6 @@ namespace Aerostats
[KSPField(isPersistant = false, guiActive = false)]
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>
/// Weight, in kilograms, of 1m^3 of gas at 100kPa and 0°C
/// Helium is 179g/m^3
@ -112,35 +96,6 @@ namespace Aerostats
private GameObject Balloon;
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)
{
if (!HighLogic.LoadedSceneIsEditor && !HighLogic.LoadedSceneIsFlight) { return; }
@ -153,7 +108,6 @@ namespace Aerostats
{
UnityEngine.Debug.Log("Aerostats: staged");
ScreenMessages.PostScreenMessage("staged");
//PlayAnimation(DeployAnimation, 1.0f);
Balloon = GameObject.CreatePrimitive(PrimitiveType.Sphere);
Balloon.transform.position = part.Rigidbody.position + part.Rigidbody.transform.up;
@ -162,8 +116,7 @@ namespace Aerostats
Balloon.rigidbody.angularDrag = 10.0f;
LiftingGasQuantity = Math.Min(MinimumFillQuantity, RemainingCompressedGas);
RemainingCompressedGas -= LiftingGasQuantity;
LiftingGasQuantity = part.RequestResource("Helium", MinimumFillQuantity);
Spring = Balloon.AddComponent<LineRenderer>();
Spring.useWorldSpace = true;
@ -193,96 +146,83 @@ namespace Aerostats
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)
{
// 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
{
// deflating balloon
LiftingGasQuantity = Math.Max(LiftingGasQuantity - MaxGasVentRate * Time.fixedDeltaTime, LiftingGasTargetQuantity);
}
// balloon security valve
if (LiftingGasQuantity > currentMaxQuantity)
{
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)
{
// 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 + ")");
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);
// 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

@ -0,0 +1,16 @@
@PART[heliumTankRadial]
{
%MODULE[TweakScale]
{
type = free
}
}
@PART[balloon]
{
%MODULE[TweakScale]
{
type = stack
defaultScale = 1.25
}
}

10
resources.cfg

@ -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…
Cancel
Save