116 lines
5.3 KiB
GDScript
116 lines
5.3 KiB
GDScript
# scripts/star_system_generator.gd
|
|
class_name StarSystemGenerator
|
|
extends RefCounted
|
|
|
|
# --- Stable Mass Ratios & Generation Rules ---
|
|
const STAR_MASS = 50000000.0
|
|
const PLANET_MASS = STAR_MASS / 10000.0 # Planet is 10,000x less massive than the star.
|
|
const MOON_MASS = PLANET_MASS / 1000.0 # Moon is 1,000x less massive than its planet.
|
|
const MIN_PLANETS = 3
|
|
const MAX_PLANETS = 8
|
|
const MAX_MOONS_PER_PLANET = 5
|
|
const ORBIT_SAFETY_FACTOR = 5 # Increase space between orbits
|
|
|
|
# --- The main public method ---
|
|
func generate(star_system: StarSystem) -> SystemData:
|
|
# 1. Create the root Barycenter for the entire system.
|
|
var system_data = SystemData.new()
|
|
|
|
# 2. Create the star itself inside the root Barycenter.
|
|
var star = Star.new()
|
|
system_data.star = star
|
|
star.name = "Star"
|
|
star.base_mass = STAR_MASS
|
|
star_system.add_child(star)
|
|
|
|
# 3. Procedurally generate and place the planetary systems.
|
|
var num_planets = randi_range(MIN_PLANETS, MAX_PLANETS)
|
|
var current_orbit_radius = 15000.0 # OrbitalMechanics.calculate_simplified_roche_limit(star) # Start with the first orbit
|
|
|
|
for i in range(num_planets):
|
|
# A. Create the Barycenter for the new planetary system.
|
|
var planet_barycenter = Barycenter.new()
|
|
|
|
planet_barycenter.name = "PlanetSystem_%d" % (i + 1)
|
|
star_system.add_child(planet_barycenter)
|
|
|
|
# B. Create the planet itself inside its Barycenter.
|
|
var planet = Planet.new()
|
|
system_data.planets.append(planet)
|
|
planet.name = "Planet_%d" % (i + 1)
|
|
planet.base_mass = randf_range(PLANET_MASS * 0.2, PLANET_MASS * 5.0)
|
|
planet_barycenter.add_child(planet)
|
|
planet.owner = planet_barycenter
|
|
planet.position = Vector2.ZERO
|
|
planet_barycenter.recalculate_total_mass()
|
|
# C. Create moons for this planet.
|
|
_generate_moons(planet, planet_barycenter, star_system, system_data)
|
|
|
|
# D. Place the entire planetary system in a stable orbit.
|
|
planet_barycenter.global_position = Vector2(current_orbit_radius, 0).rotated(randf_range(0, TAU))
|
|
planet_barycenter.linear_velocity = OrbitalMechanics.calculate_circular_orbit_velocity(planet_barycenter, star)
|
|
|
|
# Update the new edge of the star's influence
|
|
# 1. Calculate the Hill Sphere (gravitational influence) for the planet we just placed.
|
|
var hill_sphere = OrbitalMechanics.calculate_hill_sphere(planet_barycenter, star)
|
|
# 2. Add this zone of influence (plus a safety margin) to the current radius
|
|
# to determine the starting point for the NEXT planet. This ensures orbits never overlap.
|
|
current_orbit_radius += hill_sphere * ORBIT_SAFETY_FACTOR
|
|
|
|
# --- Spawn the ship at the last planet's L4 point ---
|
|
if i == num_planets - 1:
|
|
_spawn_player_ship(star_system, star, planet_barycenter)
|
|
|
|
return system_data
|
|
|
|
func _generate_moons(planet: OrbitalBody2D, planet_barycenter: Barycenter, star_system: StarSystem, system_data: SystemData):
|
|
var num_moons = randi_range(0, int(planet.mass / MOON_MASS / 2.0)) # Heavier planets get more moons
|
|
num_moons = min(num_moons, MAX_MOONS_PER_PLANET)
|
|
|
|
var current_orbit_radius = 200.0 # OrbitalMechanics.calculate_simplified_roche_limit(planet) # Start with the first orbit
|
|
|
|
for i in range(num_moons):
|
|
var moon = Moon.new()
|
|
system_data.moons.append(moon)
|
|
planet_barycenter.add_child(moon)
|
|
planet_barycenter.recalculate_total_mass()
|
|
moon.owner = planet_barycenter
|
|
moon.name = "Moon_%d" % (i + 1)
|
|
moon.base_mass = randf_range(MOON_MASS * 0.1, MOON_MASS * 2.0)
|
|
|
|
moon.position = Vector2(current_orbit_radius, 0).rotated(randf_range(0, TAU))
|
|
# Velocity is calculated relative to the parent (the planet)
|
|
moon.linear_velocity = OrbitalMechanics.calculate_circular_orbit_velocity(moon, planet_barycenter)
|
|
|
|
# Update the new edge of the planets's influence
|
|
# 1. Calculate the Hill Sphere (gravitational influence) for the moon we just placed.
|
|
var hill_sphere = OrbitalMechanics.calculate_hill_sphere(moon, planet_barycenter)
|
|
# 2. Add this zone of influence (plus a safety margin) to the current radius
|
|
# to determine the starting point for the NEXT planet. This ensures orbits never overlap.
|
|
current_orbit_radius += hill_sphere * ORBIT_SAFETY_FACTOR
|
|
|
|
|
|
# --- NEW FUNCTION: Spawns the player ship at a Lagrange point ---
|
|
func _spawn_player_ship(star_system: StarSystem, star: OrbitalBody2D, planet_system: Barycenter):
|
|
# L4 and L5 Lagrange points form an equilateral triangle with the star and planet.
|
|
# We'll calculate L4 by rotating the star-planet vector by +60 degrees.
|
|
var star_to_planet_vec = planet_system.global_position - star.global_position
|
|
var l4_position = star.global_position + star_to_planet_vec.rotated(PI / 3.0)
|
|
|
|
# The ship's velocity at L4 must match the orbital characteristics of that point.
|
|
# This is an approximation where we rotate the planet's velocity vector by 60 degrees.
|
|
var l4_velocity = planet_system.linear_velocity.rotated(PI / 3.0)
|
|
|
|
# Instantiate, position, and configure the ship.
|
|
var ship_instance = GameManager.config.default_ship_scene.instantiate()
|
|
GameManager.register_ship(ship_instance)
|
|
ship_instance.name = "PlayerShip"
|
|
star_system.add_child(ship_instance) # Add ship to the root StarSystem node
|
|
ship_instance.global_position = l4_position
|
|
ship_instance.linear_velocity = l4_velocity
|
|
ship_instance.rotation = l4_velocity.angle() + (PI / 2.0) # Point prograde
|
|
|
|
# Make sure the new ship is included in the physics simulation
|
|
#_system_data_dict.all_bodies.append(ship_instance)
|
|
print("Player ship spawned at L4 point of %s" % planet_system.name)
|