finished refactoring to have a distinct part for the balloon and the case ; when cutting the rope the balloon becomes an independent vessel ; the balloon can be destroyed by a collision or over heating
This commit is contained in:
parent
057d997626
commit
bdda3ed81f
@ -4,24 +4,17 @@ PART
|
|||||||
module = Part
|
module = Part
|
||||||
author = Youen
|
author = Youen
|
||||||
mesh = model.mu
|
mesh = model.mu
|
||||||
scale = 0.1
|
TechRequired = Unresearcheable
|
||||||
rescaleFactor = 1
|
entryCost = 0
|
||||||
node_stack_bottom = 0.0, -0.020649, 0.0, 0.0, -1.0, 0.0, 1
|
cost = 0
|
||||||
node_attach = 0.0, -0.020649, 0.0, 0.0, -1.0, 0.0
|
category = none
|
||||||
sound_parachute_open = activate
|
|
||||||
TechRequired = advLanding
|
|
||||||
entryCost = 3500
|
|
||||||
cost = 5000
|
|
||||||
category = Utility
|
|
||||||
subcategory = 0
|
subcategory = 0
|
||||||
title = Balloon
|
title = Balloon
|
||||||
description = A big balloon that can be inflated with helium (sold separately).
|
mass = 0.050
|
||||||
attachRules = 1,0,0,1,0
|
|
||||||
mass = 0.2
|
|
||||||
dragModelType = default
|
dragModelType = default
|
||||||
angularDrag = 3
|
angularDrag = 10
|
||||||
crashTolerance = 12
|
crashTolerance = 12
|
||||||
maxTemp = 2000 // = 3100
|
maxTemp = 1000
|
||||||
breakingForce = 100
|
breakingForce = 100
|
||||||
breakingTorque = 50
|
breakingTorque = 50
|
||||||
bodyLiftMultiplier = 0
|
bodyLiftMultiplier = 0
|
||||||
@ -29,6 +22,6 @@ PART
|
|||||||
bulkheadProfiles = size1, srf
|
bulkheadProfiles = size1, srf
|
||||||
MODULE
|
MODULE
|
||||||
{
|
{
|
||||||
name = ModuleBalloonCase
|
name = ModuleBalloon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
34
Parts/HeliumBalloonCase/heliumBalloonCase.cfg
Normal file
34
Parts/HeliumBalloonCase/heliumBalloonCase.cfg
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
PART
|
||||||
|
{
|
||||||
|
name = heliumBalloonCase
|
||||||
|
module = Part
|
||||||
|
author = Youen
|
||||||
|
mesh = model.mu
|
||||||
|
scale = 0.1
|
||||||
|
rescaleFactor = 1
|
||||||
|
node_stack_bottom = 0.0, -0.020649, 0.0, 0.0, -1.0, 0.0, 1
|
||||||
|
node_attach = 0.0, -0.020649, 0.0, 0.0, -1.0, 0.0
|
||||||
|
sound_parachute_open = activate
|
||||||
|
TechRequired = advLanding
|
||||||
|
entryCost = 3500
|
||||||
|
cost = 5000
|
||||||
|
category = Utility
|
||||||
|
subcategory = 0
|
||||||
|
title = Balloon
|
||||||
|
description = A big balloon that can be inflated with helium (sold separately).
|
||||||
|
attachRules = 1,0,0,1,0
|
||||||
|
mass = 0.2
|
||||||
|
dragModelType = default
|
||||||
|
angularDrag = 3
|
||||||
|
crashTolerance = 12
|
||||||
|
maxTemp = 2000 // = 3100
|
||||||
|
breakingForce = 100
|
||||||
|
breakingTorque = 50
|
||||||
|
bodyLiftMultiplier = 0
|
||||||
|
stageOffset = -1
|
||||||
|
bulkheadProfiles = size1, srf
|
||||||
|
MODULE
|
||||||
|
{
|
||||||
|
name = ModuleBalloonCase
|
||||||
|
}
|
||||||
|
}
|
BIN
Parts/HeliumBalloonCase/model.mu
Normal file
BIN
Parts/HeliumBalloonCase/model.mu
Normal file
Binary file not shown.
BIN
Parts/HeliumBalloonCase/model000.dds
Normal file
BIN
Parts/HeliumBalloonCase/model000.dds
Normal file
Binary file not shown.
BIN
Parts/HeliumBalloonCase/model001.dds
Normal file
BIN
Parts/HeliumBalloonCase/model001.dds
Normal file
Binary file not shown.
@ -8,14 +8,29 @@ namespace Aerostats
|
|||||||
{
|
{
|
||||||
public class ModuleBalloon : PartModule
|
public class ModuleBalloon : PartModule
|
||||||
{
|
{
|
||||||
public float MaxBalloonVolume { get; private set; }
|
/// <summary>
|
||||||
public float GasDensity { get; private set; }
|
/// Volume at which the balloon is full. Trying to add more gas, or simply having already stored gas expand due to lower exterior pressure or increased temperature, will cause gas to be vented through the security valve.
|
||||||
public float BalloonDragCoeff { get; private set; }
|
/// Air density at sea level is about 1.2kg/m^3, which means a 1000m^3 balloon will be able to lift about 1 ton at sea level (after substracting the balloon gas weight)
|
||||||
public float BalloonEmptyMass { get; private set; }
|
/// </summary>
|
||||||
|
[KSPField(isPersistant = false, guiActive = false)]
|
||||||
|
public float MaxVolume = 15000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Drag coefficient of the balloon
|
||||||
|
/// </summary>
|
||||||
|
[KSPField(isPersistant = false, guiActive = false)]
|
||||||
|
public float DragCoeff = 0.3f;
|
||||||
|
|
||||||
|
public float GasMolarMass { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mass of the empty balloon, in kg
|
||||||
|
/// </summary>
|
||||||
|
public float EmptyMass { get; private set; }
|
||||||
|
|
||||||
public float LiftingGasQuantity { get; private set; }
|
public float LiftingGasQuantity { get; private set; }
|
||||||
public float CurrentVolume { get; private set; }
|
public float CurrentVolume { get; private set; }
|
||||||
public float BalloonLift { get; private set; }
|
public float Lift { get; private set; }
|
||||||
public bool IsVenting { get; private set; }
|
public bool IsVenting { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -25,22 +40,47 @@ namespace Aerostats
|
|||||||
|
|
||||||
public float Radius { get; private set; }
|
public float Radius { get; private set; }
|
||||||
|
|
||||||
|
public ModuleBalloonCase AttachedCase { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Must be called right after creating a balloon
|
/// Must be called right after creating a balloon
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Initialize(float emptyMass, Vector3 initialVelocity, float maxVolume, float gasDensity, float dragCoeff)
|
public void Initialize(ModuleBalloonCase attachedCase, Vector3 initialVelocity, float gasDensity, float initialGasQuantity)
|
||||||
{
|
{
|
||||||
MaxBalloonVolume = maxVolume;
|
AttachedCase = attachedCase;
|
||||||
GasDensity = gasDensity;
|
GasMolarMass = gasDensity / GasUtilities.StpVolumeToMoles;
|
||||||
BalloonDragCoeff = dragCoeff;
|
EmptyMass = part.mass * 1000.0f;
|
||||||
BalloonEmptyMass = emptyMass;
|
|
||||||
|
// replace mesh and collider by a sphere (hack until proper assets are created)
|
||||||
|
var sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
||||||
|
gameObject.GetComponentInChildren<MeshFilter>().mesh = sphere.GetComponent<MeshFilter>().mesh;
|
||||||
|
Destroy(gameObject.collider);
|
||||||
|
var collider = gameObject.AddComponent<SphereCollider>();
|
||||||
|
collider.radius = 0.67f; // don't ask me, I don't know why
|
||||||
|
Destroy(sphere);
|
||||||
|
|
||||||
gameObject.AddComponent<Rigidbody>();
|
gameObject.AddComponent<Rigidbody>();
|
||||||
rigidbody.mass = BalloonEmptyMass;
|
rigidbody.mass = EmptyMass * 0.001f;
|
||||||
rigidbody.velocity = initialVelocity; // start with the same velocity or everything explodes when deploying from a moving vessel
|
rigidbody.velocity = initialVelocity; // start with the same velocity or everything explodes when deploying from a moving vessel
|
||||||
rigidbody.angularDrag = 10.0f;
|
rigidbody.angularDrag = 10.0f;
|
||||||
|
rigidbody.position = transform.position;
|
||||||
|
|
||||||
InjectGas(0.0001f);
|
InjectGas(initialGasQuantity);
|
||||||
|
|
||||||
|
part.OnJustAboutToBeDestroyed += OnPartDestroyed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDetached()
|
||||||
|
{
|
||||||
|
AttachedCase = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPartDestroyed()
|
||||||
|
{
|
||||||
|
if(AttachedCase != null)
|
||||||
|
AttachedCase.Cut();
|
||||||
|
|
||||||
|
part.OnJustAboutToBeDestroyed -= OnPartDestroyed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -56,7 +96,7 @@ namespace Aerostats
|
|||||||
if (LiftingGasQuantity > currentMaxQuantity)
|
if (LiftingGasQuantity > currentMaxQuantity)
|
||||||
{
|
{
|
||||||
IsVenting = true;
|
IsVenting = true;
|
||||||
Util.PostSingleScreenMessage("security valve", "Some gas has been vented by the balloon security valve");
|
Util.PostDebugSingleScreenMessage("security valve", "Some gas has been vented by the balloon security valve");
|
||||||
LiftingGasQuantity = currentMaxQuantity;
|
LiftingGasQuantity = currentMaxQuantity;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -73,21 +113,20 @@ namespace Aerostats
|
|||||||
|
|
||||||
float currentGasMoles = GasUtilities.StpVolumeToMoles * LiftingGasQuantity;
|
float currentGasMoles = GasUtilities.StpVolumeToMoles * LiftingGasQuantity;
|
||||||
CurrentVolume = currentGasMoles * GasUtilities.R * balloonInternalTemperature / externalPressure;
|
CurrentVolume = currentGasMoles * GasUtilities.R * balloonInternalTemperature / externalPressure;
|
||||||
Inflation = CurrentVolume / MaxBalloonVolume;
|
Inflation = CurrentVolume / MaxVolume;
|
||||||
|
|
||||||
Util.PostSingleScreenMessage("inflation", "Inflation = " + (Inflation * 100.0f).ToString("0.00") + "%");
|
Util.PostDebugSingleScreenMessage("inflation", "Inflation = " + (Inflation * 100.0f).ToString("0.00") + "%");
|
||||||
|
|
||||||
float airDensity = (float)FlightGlobals.getAtmDensity(externalPressure / 1000.0f, externalTemperature, body);
|
float airDensity = (float)FlightGlobals.getAtmDensity(externalPressure / 1000.0f, externalTemperature, body);
|
||||||
float currentGasDensity = GasDensity * balloonInternalTemperature / GasUtilities.ZeroCelsius / externalPressure * GasUtilities.StandardPressure;
|
Lift = CurrentVolume * airDensity;
|
||||||
BalloonLift = CurrentVolume * airDensity;
|
float balloonGasMass = GasMolarMass * currentGasMoles;
|
||||||
float balloonGasMass = currentGasDensity * CurrentVolume;
|
Util.PostDebugSingleScreenMessage("lift", "Air density = " + airDensity + "kg/m^3, Lift = " + (Lift - balloonGasMass) + "kg");
|
||||||
Util.PostSingleScreenMessage("lift", "Air density = " + airDensity + "kg/m^3, Lift = " + (BalloonLift - balloonGasMass) + "kg");
|
|
||||||
|
|
||||||
// V = 4/3*pi*r^3
|
// V = 4/3*pi*r^3
|
||||||
Radius = Mathf.Pow(CurrentVolume * 0.75f / Mathf.PI, 0.333f);
|
Radius = Mathf.Pow(CurrentVolume * 0.75f / Mathf.PI, 0.333f);
|
||||||
float scale = Radius * 2.0f + 0.1f;
|
float scale = Radius + 0.1f;
|
||||||
transform.localScale = new Vector3(scale, scale, scale);
|
transform.localScale = new Vector3(scale, scale, scale);
|
||||||
rigidbody.mass = (BalloonEmptyMass + balloonGasMass) * 0.001f;
|
rigidbody.mass = (EmptyMass + balloonGasMass) * 0.001f;
|
||||||
|
|
||||||
return LiftingGasQuantity;
|
return LiftingGasQuantity;
|
||||||
}
|
}
|
||||||
@ -103,9 +142,9 @@ namespace Aerostats
|
|||||||
float externalTemperature = (float)FlightGlobals.getExternalTemperature(worldPos, body);
|
float externalTemperature = (float)FlightGlobals.getExternalTemperature(worldPos, body);
|
||||||
float balloonInternalTemperature = externalTemperature;
|
float balloonInternalTemperature = externalTemperature;
|
||||||
float externalPressure = Math.Max((float)FlightGlobals.getStaticPressure(worldPos, body) * 1000.0f, 0.00001f);
|
float externalPressure = Math.Max((float)FlightGlobals.getStaticPressure(worldPos, body) * 1000.0f, 0.00001f);
|
||||||
Util.PostSingleScreenMessage("external atmo", "Temperature = " + externalTemperature + "K, Pressure=" + externalPressure + "Pa");
|
Util.PostDebugSingleScreenMessage("external atmo", "Temperature = " + externalTemperature + "K, Pressure=" + externalPressure + "Pa");
|
||||||
|
|
||||||
float currentMaxQuantity = MaxBalloonVolume / GasUtilities.R / balloonInternalTemperature * externalPressure / GasUtilities.StpVolumeToMoles;
|
float currentMaxQuantity = MaxVolume / GasUtilities.R / balloonInternalTemperature * externalPressure / GasUtilities.StpVolumeToMoles;
|
||||||
|
|
||||||
return currentMaxQuantity;
|
return currentMaxQuantity;
|
||||||
}
|
}
|
||||||
@ -115,6 +154,8 @@ namespace Aerostats
|
|||||||
Vector3d worldPos = vessel.GetWorldPos3D();
|
Vector3d worldPos = vessel.GetWorldPos3D();
|
||||||
CelestialBody body = vessel.mainBody;
|
CelestialBody body = vessel.mainBody;
|
||||||
|
|
||||||
|
rigidbody.WakeUp();
|
||||||
|
|
||||||
InjectGas(0); // update security valve venting
|
InjectGas(0); // update security valve venting
|
||||||
|
|
||||||
var gravityAccel = FlightGlobals.getGeeForceAtPosition(worldPos);
|
var gravityAccel = FlightGlobals.getGeeForceAtPosition(worldPos);
|
||||||
@ -125,14 +166,14 @@ namespace Aerostats
|
|||||||
float externalPressure = Math.Max((float)FlightGlobals.getStaticPressure(worldPos, body) * 1000.0f, 0.00001f);
|
float externalPressure = Math.Max((float)FlightGlobals.getStaticPressure(worldPos, body) * 1000.0f, 0.00001f);
|
||||||
float airDensity = (float)FlightGlobals.getAtmDensity(externalPressure / 1000.0f, externalTemperature, body);
|
float airDensity = (float)FlightGlobals.getAtmDensity(externalPressure / 1000.0f, externalTemperature, body);
|
||||||
|
|
||||||
rigidbody.AddForce(-gravityAccel * BalloonLift / 1000.0f, ForceMode.Force);
|
rigidbody.AddForce(-gravityAccel * Lift / 1000.0f, ForceMode.Force);
|
||||||
|
|
||||||
// balloon drag
|
// balloon drag
|
||||||
var airVelocity = rigidbody.velocity + Krakensbane.GetFrameVelocity() /*- vessel.mainBody.getRFrmVel(vessel.GetWorldPos3D())*/;
|
var airVelocity = rigidbody.velocity + Krakensbane.GetFrameVelocity() /*- vessel.mainBody.getRFrmVel(vessel.GetWorldPos3D())*/;
|
||||||
float sqVel = (float)airVelocity.magnitude;
|
float sqVel = (float)airVelocity.magnitude;
|
||||||
sqVel *= sqVel;
|
sqVel *= sqVel;
|
||||||
float dragForce = 0.5f * airDensity * sqVel * BalloonDragCoeff * (Mathf.PI * Radius * Radius);
|
float dragForce = 0.5f * airDensity * sqVel * DragCoeff * (Mathf.PI * Radius * Radius);
|
||||||
Util.PostSingleScreenMessage("balloon drag", "Drag = " + dragForce + "N");
|
Util.PostDebugSingleScreenMessage("balloon drag", "Drag = " + dragForce + "N");
|
||||||
rigidbody.AddForce(-airVelocity.normalized * dragForce / 1000.0f, ForceMode.Force);
|
rigidbody.AddForce(-airVelocity.normalized * dragForce / 1000.0f, ForceMode.Force);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,13 +20,6 @@ namespace Aerostats
|
|||||||
[KSPField(isPersistant = false, guiActive = false)]
|
[KSPField(isPersistant = false, guiActive = false)]
|
||||||
public float MaxGasVentRate = 500;
|
public float MaxGasVentRate = 500;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Volume at which the balloon is full. Trying to add more gas, or simply having already stored gas expand due to lower exterior pressure or increased temperature, will cause gas to be vented through the security valve.
|
|
||||||
/// Air density at sea level is about 1.2kg/m^3, which means a 1000m^3 balloon will be able to lift about 1 ton at sea level (after substracting the balloon gas weight)
|
|
||||||
/// </summary>
|
|
||||||
[KSPField(isPersistant = false, guiActive = false)]
|
|
||||||
public float MaxBalloonVolume = 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
|
||||||
@ -43,24 +36,12 @@ namespace Aerostats
|
|||||||
[UI_FloatRange(minValue = 0, maxValue = 20000.0f, stepIncrement = 100.0f)]
|
[UI_FloatRange(minValue = 0, maxValue = 20000.0f, stepIncrement = 100.0f)]
|
||||||
public float LiftingGasTargetQuantity = 100.0f;
|
public float LiftingGasTargetQuantity = 100.0f;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Mass of the empty balloon, in kg
|
|
||||||
/// </summary>
|
|
||||||
[KSPField(isPersistant = false, guiActive = false)]
|
|
||||||
public float BalloonEmptyMass = 50.0f;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Minimum amount of gas that will be used to inflate the balloon at the beginning. The balloon can not be deflated below this amount.
|
/// Minimum amount of gas that will be used to inflate the balloon at the beginning. The balloon can not be deflated below this amount.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[KSPField(isPersistant = false, guiActive = false)]
|
[KSPField(isPersistant = false, guiActive = false)]
|
||||||
public float MinimumFillQuantity = 10.0f;
|
public float MinimumFillQuantity = 10.0f;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Drag coefficient of the balloon
|
|
||||||
/// </summary>
|
|
||||||
[KSPField(isPersistant = false, guiActive = false)]
|
|
||||||
public float BalloonDragCoeff = 0.3f;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Length of spring that can not be extended (no force applied under this length)
|
/// Length of spring that can not be extended (no force applied under this length)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -80,6 +61,8 @@ namespace Aerostats
|
|||||||
|
|
||||||
private bool Destroyed;
|
private bool Destroyed;
|
||||||
|
|
||||||
|
private Vector3 EstimatedNextFramePosition;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gas quantity currently inside the balloon
|
/// Gas quantity currently inside the balloon
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -92,26 +75,60 @@ namespace Aerostats
|
|||||||
private ModuleBalloon Balloon;
|
private ModuleBalloon Balloon;
|
||||||
private LineRenderer Spring;
|
private LineRenderer Spring;
|
||||||
|
|
||||||
private Vector3 EstimatedNextFramePosition;
|
public static void RemoveAttachJointBetween(Part part1, Part part2)
|
||||||
|
{
|
||||||
|
if (part1.attachJoint && ((part1.attachJoint.Host == part1 && part1.attachJoint.Target == part2) || (part1.attachJoint.Host == part2 && part1.attachJoint.Target == part1)))
|
||||||
|
{
|
||||||
|
part1.attachJoint.DestroyJoint();
|
||||||
|
}
|
||||||
|
if (part2.attachJoint && ((part2.attachJoint.Host == part2 && part2.attachJoint.Target == part1) || (part2.attachJoint.Host == part1 && part2.attachJoint.Target == part2)))
|
||||||
|
{
|
||||||
|
part2.attachJoint.DestroyJoint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[KSPEvent(guiActive = true, active = true, externalToEVAOnly = false, guiActiveUnfocused = true, guiName = "Deploy balloon", unfocusedRange = 5)]
|
[KSPEvent(guiActive = true, active = true, externalToEVAOnly = false, guiActiveUnfocused = true, guiName = "Deploy balloon", unfocusedRange = 5)]
|
||||||
public void Deploy()
|
public void Deploy()
|
||||||
{
|
{
|
||||||
if (Destroyed || Deployed)
|
if (Destroyed || Deployed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Deployed = true;
|
Deployed = true;
|
||||||
|
|
||||||
UnityEngine.Debug.Log("Aerostats: staged");
|
UnityEngine.Debug.Log("Aerostats: staged");
|
||||||
Util.PostScreenMessage("staged");
|
Util.PostDebugScreenMessage("staged");
|
||||||
|
|
||||||
var balloonObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
/*var balloonObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
||||||
|
balloonObject.SetActive(false);
|
||||||
balloonObject.transform.position = part.Rigidbody.position + part.Rigidbody.transform.up;
|
balloonObject.transform.position = part.Rigidbody.position + part.Rigidbody.transform.up;
|
||||||
Balloon = balloonObject.AddComponent<ModuleBalloon>();
|
var balloonPart = balloonObject.AddComponent<Part>();
|
||||||
Balloon.part = part; // TODO: remove this hack and properly instantiate a new vessel?
|
balloonPart.children = new List<Part>();
|
||||||
Balloon.Initialize(BalloonEmptyMass, part.rigidbody.velocity, MaxBalloonVolume, GasDensity, BalloonDragCoeff);
|
balloonPart.partTransform = balloonObject.transform;
|
||||||
|
balloonPart.name = "heliumBalloon";
|
||||||
|
new GameObject("model").transform.parent = balloonPart.partTransform;
|
||||||
|
balloonPart.SetHierarchyRoot(balloonPart);
|
||||||
|
balloonPart.vessel = vessel;
|
||||||
|
balloonPart.setParent(part);*/
|
||||||
|
|
||||||
LiftingGasQuantity = Balloon.InjectGas(part.RequestResource("Helium", MinimumFillQuantity));
|
AvailablePart avPart = PartLoader.Instance.parts.Single(p => p.name == "heliumBalloon");
|
||||||
|
var balloonPart = (Part)UnityEngine.Object.Instantiate(avPart.partPrefab);
|
||||||
|
var balloonObject = balloonPart.gameObject;
|
||||||
|
balloonObject.transform.position = part.Rigidbody.position + part.Rigidbody.transform.up * 3.0f;
|
||||||
|
//balloonObject.transform.rotation = part.Rigidbody.rotation;
|
||||||
|
balloonPart.SetHierarchyRoot(balloonPart);
|
||||||
|
balloonPart.vessel = vessel;
|
||||||
|
balloonPart.setParent(part);
|
||||||
|
|
||||||
|
Balloon = balloonObject.GetComponent<ModuleBalloon>();
|
||||||
|
Balloon.part = balloonPart;
|
||||||
|
float initialGasQuantity = Mathf.Min(0.1f, part.RequestResource("Helium", MinimumFillQuantity));
|
||||||
|
|
||||||
|
balloonObject.SetActive(true);
|
||||||
|
GameEvents.onVesselWasModified.Fire(vessel);
|
||||||
|
|
||||||
|
Balloon.Initialize(this, part.rigidbody.velocity, GasDensity, initialGasQuantity);
|
||||||
|
|
||||||
|
LiftingGasQuantity = Balloon.LiftingGasQuantity;
|
||||||
|
|
||||||
Spring = part.gameObject.AddComponent<LineRenderer>();
|
Spring = part.gameObject.AddComponent<LineRenderer>();
|
||||||
Spring.useWorldSpace = true;
|
Spring.useWorldSpace = true;
|
||||||
@ -122,27 +139,33 @@ namespace Aerostats
|
|||||||
|
|
||||||
part.OnJustAboutToBeDestroyed += OnPartDestroyed;
|
part.OnJustAboutToBeDestroyed += OnPartDestroyed;
|
||||||
|
|
||||||
EstimatedNextFramePosition = part.Rigidbody.position;
|
EstimatedNextFramePosition = part.Rigidbody.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
[KSPEvent(guiActive = true, active = true, externalToEVAOnly = false, guiActiveUnfocused = true, guiName = "Cut rope", unfocusedRange = 5)]
|
[KSPEvent(guiActive = true, active = true, externalToEVAOnly = false, guiActiveUnfocused = true, guiName = "Cut rope", unfocusedRange = 5)]
|
||||||
public void Cut()
|
public void Cut()
|
||||||
{
|
{
|
||||||
if (Destroyed || !Deployed)
|
if (Destroyed || !Deployed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Balloon = null;
|
if (Balloon != null)
|
||||||
|
{
|
||||||
|
Balloon.OnDetached();
|
||||||
|
Balloon.part.decouple(); // after that, the balloon becomes an independent vessel
|
||||||
|
Balloon.part.vessel.vesselName = vessel.vesselName + " balloon";
|
||||||
|
Balloon = null;
|
||||||
|
}
|
||||||
Destroy(Spring);
|
Destroy(Spring);
|
||||||
Spring = null;
|
Spring = null;
|
||||||
part.OnJustAboutToBeDestroyed -= OnPartDestroyed;
|
part.OnJustAboutToBeDestroyed -= OnPartDestroyed;
|
||||||
Destroyed = true;
|
Destroyed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
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; }
|
||||||
|
|
||||||
Util.PostScreenMessage("Aerostat loaded");
|
Util.PostDebugScreenMessage("Aerostat loaded");
|
||||||
part.stagingIcon = "PARACHUTES";
|
part.stagingIcon = "PARACHUTES";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +174,19 @@ namespace Aerostats
|
|||||||
Cut();
|
Cut();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CheckKrakensbane()
|
||||||
|
{
|
||||||
|
// 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 > 1000.0f)
|
||||||
|
{
|
||||||
|
Util.PostDebugScreenMessage("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;
|
||||||
|
}
|
||||||
|
EstimatedNextFramePosition = part.rigidbody.position + part.rigidbody.velocity * Time.fixedDeltaTime;
|
||||||
|
}
|
||||||
|
|
||||||
private void FixedUpdate()
|
private void FixedUpdate()
|
||||||
{
|
{
|
||||||
if (Destroyed)
|
if (Destroyed)
|
||||||
@ -167,15 +203,10 @@ namespace Aerostats
|
|||||||
|
|
||||||
if (Deployed)
|
if (Deployed)
|
||||||
{
|
{
|
||||||
// detect Krakensbane teleportation, and fix up the balloon position (otherwise it results in instant ship disintegration due to extreme forces on the spring)
|
// makes sure the balloon can move freely relatively to the vessel (apparently, KSP creates a joint when attaching a part)
|
||||||
if ((part.Rigidbody.position - EstimatedNextFramePosition).magnitude > 1000.0f)
|
RemoveAttachJointBetween(Balloon.part, part);
|
||||||
{
|
|
||||||
Util.PostScreenMessage("Krakensbane teleportation detected! (dist=" + (part.Rigidbody.position - EstimatedNextFramePosition).magnitude+")");
|
CheckKrakensbane();
|
||||||
var offset = part.rigidbody.position - EstimatedNextFramePosition;
|
|
||||||
Balloon.rigidbody.position += offset;
|
|
||||||
Balloon.transform.position = Balloon.rigidbody.position;
|
|
||||||
}
|
|
||||||
EstimatedNextFramePosition = part.rigidbody.position + part.rigidbody.velocity * Time.fixedDeltaTime;
|
|
||||||
|
|
||||||
float currentMaxQuantity = Balloon.GetCurrentMaxQuantity();
|
float currentMaxQuantity = Balloon.GetCurrentMaxQuantity();
|
||||||
|
|
||||||
@ -209,7 +240,7 @@ namespace Aerostats
|
|||||||
Status = "full (venting)";
|
Status = "full (venting)";
|
||||||
}
|
}
|
||||||
|
|
||||||
VolumeStatus = Mathf.Round(Balloon.CurrentVolume) + " / " + Mathf.Round(MaxBalloonVolume);
|
VolumeStatus = Mathf.Round(Balloon.CurrentVolume) + " / " + Mathf.Round(Balloon.MaxVolume);
|
||||||
|
|
||||||
// spring between balloon and base
|
// spring between balloon and base
|
||||||
float restLength = SpringRestLength + Balloon.Radius;
|
float restLength = SpringRestLength + Balloon.Radius;
|
||||||
@ -225,7 +256,7 @@ namespace Aerostats
|
|||||||
part.rigidbody.AddForce(springForce, ForceMode.Force);
|
part.rigidbody.AddForce(springForce, ForceMode.Force);
|
||||||
Balloon.rigidbody.AddForceAtPosition(-springForce, balloonAttachPoint, ForceMode.Force);
|
Balloon.rigidbody.AddForceAtPosition(-springForce, balloonAttachPoint, ForceMode.Force);
|
||||||
}
|
}
|
||||||
Util.PostSingleScreenMessage("spring force", "Spring force = " + springForceMag + "N");
|
Util.PostDebugSingleScreenMessage("spring force", "Spring force = " + springForceMag + "N");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -241,11 +272,23 @@ namespace Aerostats
|
|||||||
|
|
||||||
if (Deployed)
|
if (Deployed)
|
||||||
{
|
{
|
||||||
|
CheckKrakensbane();
|
||||||
var balloonAttachPoint = Balloon.rigidbody.position - Balloon.transform.up.normalized * Balloon.Radius;
|
var balloonAttachPoint = Balloon.rigidbody.position - Balloon.transform.up.normalized * Balloon.Radius;
|
||||||
|
|
||||||
Spring.SetPosition(0, part.transform.position);
|
Spring.SetPosition(0, part.transform.position);
|
||||||
Spring.SetPosition(1, balloonAttachPoint);
|
Spring.SetPosition(1, balloonAttachPoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
if (Destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Deployed)
|
||||||
|
{
|
||||||
|
CheckKrakensbane();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ namespace Aerostats
|
|||||||
{
|
{
|
||||||
private static Dictionary<string, ScreenMessage> messages = new Dictionary<string, ScreenMessage>();
|
private static Dictionary<string, ScreenMessage> messages = new Dictionary<string, ScreenMessage>();
|
||||||
|
|
||||||
public static void PostSingleScreenMessage(string id, string message)
|
public static void PostDebugSingleScreenMessage(string id, string message)
|
||||||
{
|
{
|
||||||
#if ENABLE_ONSCREEN_DEBUG
|
#if ENABLE_ONSCREEN_DEBUG
|
||||||
if (messages.ContainsKey(id))
|
if (messages.ContainsKey(id))
|
||||||
@ -22,7 +22,7 @@ namespace Aerostats
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PostScreenMessage(string message)
|
public static void PostDebugScreenMessage(string message)
|
||||||
{
|
{
|
||||||
#if ENABLE_ONSCREEN_DEBUG
|
#if ENABLE_ONSCREEN_DEBUG
|
||||||
ScreenMessages.PostScreenMessage(message);
|
ScreenMessages.PostScreenMessage(message);
|
||||||
|
Loading…
Reference in New Issue
Block a user