Files
carto-revive/src/Craft/Krakensbane.cs

108 lines
3.6 KiB
C#
Raw Normal View History

2024-10-31 22:46:27 +08:00
using System.Diagnostics;
using Godot;
2024-11-01 21:39:46 +08:00
using ImGuiNET;
using Quadratic.Carto.MathExt;
2024-11-06 22:16:43 +08:00
using Vim.Math3d;
2024-10-31 22:46:27 +08:00
namespace Quadratic.Carto.Craft;
/// <summary>
/// Krakensbane manages the position of its direct descendants, to ensure the
/// focused vessel is not too far from the origin.
/// </summary>
/// <remarks>
/// The name Krakensbane is a legacy of the original KSP module which does the
/// same thing, i.e. preventing floating point errors from causing the vessel
/// to be thrown into deep space.
/// </remarks>
public sealed partial class Krakensbane : Node3D
{
2024-11-01 21:39:46 +08:00
[Export]
public Node3D? FocusedVessel { get; set; }
2024-10-31 22:46:27 +08:00
const float maxDistance = 500.0f;
2024-11-06 22:16:43 +08:00
const float planetRadius = 6372.0f;
2024-10-31 22:46:27 +08:00
2024-11-06 22:16:43 +08:00
DVector3 originPosition = DVector3.UnitY * planetRadius;
/// <summary>
/// Something to manage the non-inertial frame of reference.
/// </summary>
/// <para>
/// It's good to have an inertial frame of reference when you're close to
/// a lot of static stuff, like on the ground. However, a non-inertial frame
/// of reference might be more appropriate when you're in deep space.
/// </para>
/// <para>
/// This provider field is null if we're using an inertial frame of reference.
/// When it's not null, it should be responsible for managing the acceleration,
/// angular acceleration, and even positions and/or rotations of children
/// objects.
INonInertialFrameProvider? nonInertialFrameProvider;
2024-11-01 21:39:46 +08:00
2024-10-31 22:46:27 +08:00
public override void _PhysicsProcess(double delta)
{
Debug.Assert(
2024-11-01 21:39:46 +08:00
FocusedVessel == null || FocusedVessel.GetParent() == this,
2024-10-31 22:46:27 +08:00
"Focused vessel must be a direct descendant of Krakensbane"
);
2024-11-01 21:39:46 +08:00
if (FocusedVessel == null)
2024-10-31 22:46:27 +08:00
{
return;
}
2024-11-01 21:39:46 +08:00
var vesselPosition = FocusedVessel.Transform.Origin;
2024-10-31 22:46:27 +08:00
var vesselDistance = vesselPosition.Length();
if (vesselDistance > maxDistance)
{
// Reset the vessel's position to the origin
// TODO: save the total offset; we don't yet have a double-precision vector3
var applyTransform = Transform3D.Identity.Translated(-vesselPosition);
int n_children = GetChildCount();
for (int i = 0; i < n_children; i++)
{
var child = GetChild<Node3D>(i);
child.Transform = applyTransform * child.Transform;
}
2024-11-01 21:39:46 +08:00
originPosition += vesselPosition.AsVim().AsDouble();
2024-10-31 22:46:27 +08:00
}
2024-11-06 22:16:43 +08:00
// Apply gravity
foreach (var child in GetChildren())
{
if (child is RigidBody3D rb)
{
var localPosition = rb.Transform.Origin.AsVim().AsDouble();
var globalPosition = originPosition + localPosition;
var gravityVector = -globalPosition.Normalize();
var floatGravityVector = gravityVector.AsSingle().AsGodot();
var distance = globalPosition.Length();
var gravity = 9.81f * planetRadius * planetRadius / (distance * distance);
rb.ApplyCentralForce(floatGravityVector * (float)gravity);
}
}
}
public DVector3 GetPositionOf(Node3D node)
{
var localPosition = node.Transform.Origin.AsVim().AsDouble();
return originPosition + localPosition;
2024-10-31 22:46:27 +08:00
}
2024-11-01 21:39:46 +08:00
public override void _Process(double delta)
{
ImGui.Begin("Krakensbane");
ImGui.Text($"Origin: {originPosition}");
ImGui.End();
}
2024-10-31 22:46:27 +08:00
}
2024-11-06 22:16:43 +08:00
public interface INonInertialFrameProvider
{
public DVector3 GetCurrentAcceleration();
public DVector3 GetCurrentAngularAcceleration();
}