using Godot; using System; using System.Collections.Generic; using Vim.Math3d; [Tool] public class Barycenter : Node, IPointMass { [Export] private NodePath[] _pointMassPaths; 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(); } } public double Mass { get { double mass = 0; foreach (var orbiter in Orbiters) { mass += orbiter.PointMass.Mass; } return mass; } } public DVector3 Position { get; set; } 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 struct Orbiter { public IPointMass PointMass { get; set; } public IOrbit Orbit { get; set; } } private Orbiter[] _orbiters = null; private Orbiter[] Orbiters { get { if (_orbiters == null) { var length = _pointMassPaths.Length; _orbiters = new Orbiter[length]; for (int i = 0; i < length; i++) { var pointMass = GetNode(_pointMassPaths[i]); var orbit = new Orbit(this, pointMass); var orbiter = new Orbiter { PointMass = pointMass, Orbit = orbit }; _orbiters[i] = orbiter; } } return _orbiters; } } private IOrbit[] _orbits; private IOrbit[] Orbits { get { if (_orbits == null) { } return _orbits; } } private float _time = 0; [Export] private float _speed = 3f; public override void _Process(float delta) { _time += delta * _speed; InvalidateGeometry(); } private void InvalidateGeometry() { for (int i = 0; i < Orbiters.Length; i++) { var orbiter = Orbiters[i]; var orbit = orbiter.Orbit; orbit.Ellipse = new Ellipse(SemiMajorAxis, Eccentricity); orbit.Draw(OrbitGeometry); var t = _time + i * Math.PI; orbiter.PointMass.Position = orbit.GetPosition(t); } } }