154 lines
3.2 KiB
C#
154 lines
3.2 KiB
C#
using Godot;
|
|
using System;
|
|
using Vim.Math3d;
|
|
|
|
[Tool]
|
|
public class OrbitSystem : Node, IMassive, ILocation
|
|
{
|
|
[Export] private NodePath _a;
|
|
[Export] private NodePath _b;
|
|
[Export] private NodePath _barycenter;
|
|
|
|
private double _semiMajorAxis;
|
|
[Export]
|
|
private double SemiMajorAxis
|
|
{
|
|
get => _semiMajorAxis;
|
|
set
|
|
{
|
|
_semiMajorAxis = value;
|
|
|
|
if (!Engine.EditorHint) return;
|
|
|
|
InvalidateGeometry();
|
|
}
|
|
}
|
|
|
|
|
|
private double _eccentricity;
|
|
[Export(PropertyHint.Range, "0,1")]
|
|
private double Eccentricity
|
|
{
|
|
get => _eccentricity;
|
|
set
|
|
{
|
|
_eccentricity = value;
|
|
|
|
if (!Engine.EditorHint) return;
|
|
|
|
InvalidateGeometry();
|
|
}
|
|
}
|
|
|
|
#region Point Masses
|
|
private IPointMass Primary
|
|
{
|
|
get
|
|
{
|
|
if (_pointMasses[0] == null)
|
|
{
|
|
InitPointMasses();
|
|
}
|
|
return _pointMasses[0];
|
|
}
|
|
}
|
|
private IPointMass Secondary
|
|
{
|
|
get
|
|
{
|
|
if (_pointMasses[1] == null)
|
|
{
|
|
InitPointMasses();
|
|
}
|
|
return _pointMasses[1];
|
|
}
|
|
}
|
|
private readonly IPointMass[] _pointMasses = new IPointMass[2];
|
|
private void InitPointMasses()
|
|
{
|
|
var a = GetNode<IPointMass>(_a);
|
|
var b = GetNode<IPointMass>(_b);
|
|
|
|
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();
|
|
}
|
|
|
|
private void InvalidateGeometry()
|
|
{
|
|
Orbit.Ellipse = new Ellipse(SemiMajorAxis, Eccentricity);
|
|
Orbit.Draw(OrbitGeometry);
|
|
|
|
Secondary.Position = Orbit.GetPosition(_time);
|
|
}
|
|
}
|