Files
millimeters-of-aluminum/scripts/celestial_body.gd

95 lines
3.3 KiB
GDScript3
Raw Normal View History

2025-09-12 15:54:10 +02:00
class_name CelestialBody
extends RigidBody2D
# The celestial body that this body orbits.
@export var primary: CelestialBody
# Real-world gravitational constant.
const G_REAL = 6.674e-11
# This is a placeholder for your pixel art texture.
@export var texture: Texture2D
# The radius of the body, used for drawing and future collision detection.
@export var radius: float = 10.0
# Real-world mass of the body in kilograms.
@export_range(1.0, 1.989e+30, 1.0, "exp") var mass_real: float = 1.0
# The scaling factor for the simulation. A value of 1.0 means no scaling.
var sim_scale: float = 1.0
# Default color based on body type for visualization.
var body_color: Color = Color.ORANGE_RED
func get_class_name() -> String:
return "CelestialBody"
func _ready() -> void:
# Set the scaled mass based on the real-world mass and the simulation scale.
# The scale is applied to the mass, so a smaller scale means a larger apparent mass.
mass = mass_real / (sim_scale * sim_scale)
# We will handle gravity manually, so we set the built-in gravity scale to 0.
gravity_scale = 0.0
# To make the simulation work without drag, we must set linear damping to 0.
linear_damp = 0.0
# Set the color based on the class name for easy differentiation.
match get_class_name():
"Star":
body_color = Color.GOLD
"Planet":
body_color = Color.BLUE
"Moon":
body_color = Color.PURPLE
"Station":
body_color = Color.WHITE
"Asteroid":
body_color = Color.BROWN
_:
body_color = Color.ORANGE_RED
# This callback is the correct place to apply custom forces to a RigidBody2D.
func _integrate_forces(state: PhysicsDirectBodyState2D) -> void:
if primary and is_instance_valid(primary):
# Get the vector pointing from this body to its primary.
var direction_to_primary = primary.global_position - state.transform.origin
var distance_squared = direction_to_primary.length_squared()
# Prevent division by zero or a large force if bodies are on top of each other.
if distance_squared > 1.0:
# Calculate the magnitude of the gravitational force using Newton's law.
# We now use the scaled masses, which is consistent with Godot's physics engine.
# F = G * (m1 * m2) / r^2
var force_magnitude = (G_REAL * self.mass * primary.mass) / distance_squared
# Apply the force in the direction of the primary.
state.apply_central_force(direction_to_primary.normalized() * force_magnitude)
# We force a redraw here to update the body's visual representation.
queue_redraw()
# Override the default drawing function to draw the body.
# This is useful for debugging and visualization.
func _draw() -> void:
if texture:
# If a texture is assigned, draw it.
var size = Vector2(radius * 2, radius * 2)
var offset = -size / 2.0
draw_texture_rect(texture, Rect2(offset, size), false)
else:
# Otherwise, draw a simple placeholder circle.
draw_circle(Vector2.ZERO, radius, body_color)
# Calculates the velocity required for a stable circular orbit.
func get_stable_orbit_velocity(primary_mass_real: float, distance_real: float) -> float:
# The formula for real-world orbital velocity is v = sqrt(G * M / r)
var real_world_velocity = sqrt((G_REAL * primary_mass_real) / distance_real)
# Scale this velocity down to the simulation scale before returning.
return real_world_velocity / sim_scale