shmodot/scripts/orbits/OrbitSystem.cs

154 lines
3.2 KiB
C#
Raw Normal View History

2022-08-31 22:18:47 +02:00
using Godot;
using System;
using Vim.Math3d;
2022-08-31 22:18:47 +02:00
[Tool]
2022-08-31 22:18:47 +02:00
public class OrbitSystem : Node, IMassive, ILocation
{
[Export] private NodePath _a;
[Export] private NodePath _b;
[Export] private NodePath _barycenter;
private double _semiMajorAxis;
2022-08-31 22:18:47 +02:00
[Export]
private double SemiMajorAxis
2022-08-31 22:18:47 +02:00
{
get => _semiMajorAxis;
set
2022-08-31 22:18:47 +02:00
{
_semiMajorAxis = value;
if (!Engine.EditorHint) return;
2022-08-31 22:18:47 +02:00
InvalidateGeometry();
2022-08-31 22:18:47 +02:00
}
}
private double _eccentricity;
[Export(PropertyHint.Range, "0,1")]
private double Eccentricity
2022-08-31 22:18:47 +02:00
{
get => _eccentricity;
set
{
_eccentricity = value;
2022-08-31 22:18:47 +02:00
if (!Engine.EditorHint) return;
InvalidateGeometry();
}
2022-08-31 22:18:47 +02:00
}
#region Point Masses
private IPointMass Primary
2022-08-31 22:18:47 +02:00
{
get
2022-08-31 22:18:47 +02:00
{
if (_pointMasses[0] == null)
2022-08-31 22:18:47 +02:00
{
InitPointMasses();
}
return _pointMasses[0];
2022-08-31 22:18:47 +02:00
}
}
private IPointMass Secondary
2022-08-31 22:18:47 +02:00
{
get
{
if (_pointMasses[1] == null)
{
InitPointMasses();
}
return _pointMasses[1];
}
2022-08-31 22:18:47 +02:00
}
private readonly IPointMass[] _pointMasses = new IPointMass[2];
2022-08-31 22:18:47 +02:00
private void InitPointMasses()
{
var a = GetNode<IPointMass>(_a);
var b = GetNode<IPointMass>(_b);
2022-08-31 22:18:47 +02:00
if (a.Mass > b.Mass)
{
_pointMasses[0] = a;
_pointMasses[1] = b;
}
else
{
_pointMasses[0] = b;
_pointMasses[1] = a;
}
}
#endregion
public float Mass => Primary.Mass + Secondary.Mass;
public DVector3 Position
{
get => Barycenter;
set => Barycenter = value;
}
public DVector3 Barycenter
{
get
{
var p0 = Primary.Position;
var p1 = Secondary.Position;
return p0.Lerp(p1, .5f);
}
// TODO - make setting the berycenter do something sensible?
set => _ = value;
}
private Orbit _orbit = null;
private Orbit Orbit
{
get
{
if (_orbit == null)
{
_orbit = new Orbit();
}
return _orbit;
}
}
private ImmediateGeometry _orbitGeometry = null;
public ImmediateGeometry OrbitGeometry
{
get
{
if (_orbitGeometry == null)
{
_orbitGeometry = new ImmediateGeometry();
var m = new SpatialMaterial();
m.VertexColorUseAsAlbedo = true;
m.FlagsUnshaded = true;
_orbitGeometry.MaterialOverride = m;
AddChild(_orbitGeometry);
}
return _orbitGeometry;
}
}
private float _time = 0;
[Export]
private float _speed = 3f;
public override void _Process(float delta)
{
_time += delta * _speed;
InvalidateGeometry();
}
2022-08-31 22:18:47 +02:00
private void InvalidateGeometry()
2022-08-31 22:18:47 +02:00
{
Orbit.Ellipse = new Ellipse(SemiMajorAxis, Eccentricity);
Orbit.Draw(OrbitGeometry);
2022-08-31 22:18:47 +02:00
Secondary.Position = Orbit.GetPosition(_time);
2022-08-31 22:18:47 +02:00
}
}