Scaled down simulation

This commit is contained in:
olof.pettersson
2025-09-15 16:01:22 +02:00
parent 34f1dd0b19
commit e8c04e820d
11 changed files with 241 additions and 135 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
# Godot 4+ specific ignores # Godot 4+ specific ignores
.godot/ .godot/
.vscode/
/android/ /android/
/addons/ /addons/

View File

@ -11,13 +11,17 @@
[node name="Node2D" type="Node2D"] [node name="Node2D" type="Node2D"]
script = ExtResource("1_h2yge") script = ExtResource("1_h2yge")
min_asteroid_belts = 0 min_planets = 1
max_planets = 4
max_moons = 10
max_asteroid_belts = 2
max_star_stations = 0
star_scene = ExtResource("2_7mycd") star_scene = ExtResource("2_7mycd")
planet_scene = ExtResource("3_272bh") planet_scene = ExtResource("3_272bh")
moon_scene = ExtResource("4_5vw27") moon_scene = ExtResource("4_5vw27")
station_scene = ExtResource("5_kek77") station_scene = ExtResource("5_kek77")
asteroid_scene = ExtResource("6_4c57u") asteroid_scene = ExtResource("6_4c57u")
sim_scale = 1e+09 sim_scale = 0.21
[node name="DeveloperPawn" parent="." node_paths=PackedStringArray("map_canvas") instance=ExtResource("7_272bh")] [node name="DeveloperPawn" parent="." node_paths=PackedStringArray("map_canvas") instance=ExtResource("7_272bh")]
input_pickable = true input_pickable = true

27
main.tscn6546160625.tmp Normal file
View File

@ -0,0 +1,27 @@
[gd_scene load_steps=9 format=3 uid="uid://dogqi2c58qdc0"]
[ext_resource type="Script" uid="uid://j3j483itissq" path="res://scripts/star_system_generator.gd" id="1_h2yge"]
[ext_resource type="PackedScene" uid="uid://5uqp4amjj7ww" path="res://scenes/star.tscn" id="2_7mycd"]
[ext_resource type="PackedScene" uid="uid://clt4qlsjcfgln" path="res://scenes/planet.tscn" id="3_272bh"]
[ext_resource type="PackedScene" uid="uid://74ppvxcw8an4" path="res://scenes/moon.tscn" id="4_5vw27"]
[ext_resource type="PackedScene" uid="uid://dm3s33o4xhqfv" path="res://scenes/station.tscn" id="5_kek77"]
[ext_resource type="PackedScene" uid="uid://bawsujtlpmh5r" path="res://scenes/asteroid.tscn" id="6_4c57u"]
[ext_resource type="PackedScene" uid="uid://cm5qsuunboxm3" path="res://scenes/developer_pawn.tscn" id="7_272bh"]
[ext_resource type="PackedScene" uid="uid://ctlw5diis8h1x" path="res://scenes/map_canvas.tscn" id="8_5vw27"]
[node name="Node2D" type="Node2D"]
script = ExtResource("1_h2yge")
min_asteroid_belts = 0
star_scene = ExtResource("2_7mycd")
planet_scene = ExtResource("3_272bh")
moon_scene = ExtResource("4_5vw27")
station_scene = ExtResource("5_kek77")
asteroid_scene = ExtResource("6_4c57u")
sim_scale = 1e+09
[node name="DeveloperPawn" parent="." node_paths=PackedStringArray("map_canvas") instance=ExtResource("7_272bh")]
input_pickable = true
map_canvas = NodePath("../MapCanvas")
[node name="MapCanvas" parent="." node_paths=PackedStringArray("star_system_generator") instance=ExtResource("8_5vw27")]
star_system_generator = NodePath("..")

View File

@ -10,7 +10,7 @@ func get_class_name() -> String:
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
# An Asteroid has negligible mass for physics calculations. # An Asteroid has negligible mass for physics calculations.
mass = 0.001 #mass = 0.001
radius = 5.0 radius = 5.0
# You can set a default texture here. # You can set a default texture here.

View File

@ -5,7 +5,7 @@ extends RigidBody2D
@export var primary: CelestialBody @export var primary: CelestialBody
# Real-world gravitational constant. # Real-world gravitational constant.
const G_REAL = 6.674e-11 const G = 0.0001
# This is a placeholder for your pixel art texture. # This is a placeholder for your pixel art texture.
@export var texture: Texture2D @export var texture: Texture2D
@ -13,8 +13,6 @@ const G_REAL = 6.674e-11
# The radius of the body, used for drawing and future collision detection. # The radius of the body, used for drawing and future collision detection.
@export var radius: float = 10.0 @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. # The scaling factor for the simulation. A value of 1.0 means no scaling.
var sim_scale: float = 1.0 var sim_scale: float = 1.0
@ -27,6 +25,7 @@ var orbit_radius_real : float = 0.0
var linear_velocity_real : Vector2 = Vector2.ZERO var linear_velocity_real : Vector2 = Vector2.ZERO
var global_position_real : Vector2 = Vector2.ZERO var global_position_real : Vector2 = Vector2.ZERO
var current_central_force_real : Vector2 = Vector2.ZERO var current_central_force_real : Vector2 = Vector2.ZERO
var direction_to_primary : Vector2 = Vector2.ZERO
func get_class_name() -> String: func get_class_name() -> String:
return "CelestialBody" return "CelestialBody"
@ -34,13 +33,17 @@ func get_class_name() -> String:
func _ready() -> void: func _ready() -> void:
# Set the scaled mass based on the real-world mass and the simulation scale. # 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. # The scale is applied to the mass, so a smaller scale means a larger apparent mass.
mass = mass_real / sim_scale
# We will handle gravity manually, so we set the built-in gravity scale to 0. # We will handle gravity manually, so we set the built-in gravity scale to 0.
gravity_scale = 0.0 gravity_scale = 0.0
# To make the simulation work without drag, we must set linear damping to 0. # To make the simulation work without drag, we must set linear damping to 0.
linear_damp = 0.0 linear_damp = 0.0
angular_damp = 0.0
can_sleep = false
custom_integrator = true
# Set the color based on the class name for easy differentiation. # Set the color based on the class name for easy differentiation.
match get_class_name(): match get_class_name():
@ -58,24 +61,24 @@ func _ready() -> void:
body_color = Color.ORANGE_RED body_color = Color.ORANGE_RED
var is_first_integration : bool = true
# This callback is the correct place to apply custom forces to a RigidBody2D. # This callback is the correct place to apply custom forces to a RigidBody2D.
func _integrate_forces(state: PhysicsDirectBodyState2D) -> void: func _integrate_forces(state: PhysicsDirectBodyState2D) -> void:
if primary and is_instance_valid(primary): if primary and is_instance_valid(primary):
# Get the vector pointing from this body to its primary. # Get the vector pointing from this body to its primary.
var direction_to_primary = primary.global_position_real - global_position_real direction_to_primary = self.global_position.direction_to(primary.global_position)
var distance_squared = direction_to_primary.length_squared() var distance_squared = self.global_position.distance_squared_to(primary.global_position)
#print(distance_squared / (sim_scale * sim_scale))
# Prevent division by zero or a large force if bodies are on top of each other. # Prevent division by zero or a large force if bodies are on top of each other.
if distance_squared > 1.0: if distance_squared > 1.0:
# Calculate the magnitude of the gravitational force using Newton's law. # 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. # We now use the scaled masses, which is consistent with Godot's physics engine.
# F = G * (m1 * m2) / r^2 # F = G * (m1 * m2) / r^2
var force_magnitude = ((G_REAL) * self.mass_real * primary.mass_real) / (distance_squared) var force_magnitude = (G * self.mass * primary.mass) / (distance_squared)
# Apply the force in the direction of the primary. # Apply the force in the direction of the primary.
current_central_force_real = (direction_to_primary.normalized() * force_magnitude) current_central_force_real = (direction_to_primary * force_magnitude)
state.apply_central_force(current_central_force_real / sim_scale) state.apply_central_force(current_central_force_real)
# We force a redraw here to update the body's visual representation. # We force a redraw here to update the body's visual representation.
queue_redraw() queue_redraw()
@ -94,14 +97,16 @@ func _draw() -> void:
func calculate_initial_orbit_real(primary: CelestialBody, orbiter : CelestialBody): func calculate_initial_orbit_real(primary: CelestialBody, orbiter : CelestialBody):
print("Orbital velocity for: " + str(orbiter))
# The formula for real-world orbital velocity is v = sqrt(G * M / r) # The formula for real-world orbital velocity is v = sqrt(G * M / r)
var magnitude = sqrt((G_REAL * primary.mass_real) / primary.global_position_real.distance_to(orbiter.global_position_real)) var magnitude = sqrt(G * (primary.mass) / primary.global_position.distance_to(orbiter.global_position))
print(magnitude)
# Calculate the relative position vector from the star to the body # Calculate the relative position vector from the star to the body
var unit_vector = primary.global_position_real.direction_to(orbiter.global_position_real) var unit_vector = primary.global_position.direction_to(orbiter.global_position)
print(unit_vector)
# Calculate a perpendicular vector (swapping and negating components) # Calculate a perpendicular vector (swapping and negating components)
var orbit_direction = Vector2(unit_vector.y, -unit_vector.x) var orbit_direction = Vector2(unit_vector.y, -unit_vector.x)
print(orbit_direction)
# Scale this velocity down to the simulation scale before returning. # Scale this velocity down to the simulation scale before returning.
return orbit_direction * magnitude return orbit_direction * magnitude + primary.linear_velocity

View File

@ -1,104 +1,163 @@
class_name MapDrawer class_name MapDrawer
extends Node2D extends Node2D
# A reference to the StarSystemGenerator node, which will be set by the MapCanvas. # The body at the center of the map view.
var star_system_generator: StarSystemGenerator var focal_body: CelestialBody
# The list of bodies to be rendered in the current view.
var bodies_to_draw: Array[CelestialBody] = []
# The scale used for drawing, stored to be accessible by the input handler.
var draw_scale: float = 1.0
# A reference to the generator, with a setter to initialize the view.
var star_system_generator: StarSystemGenerator:
set(value):
star_system_generator = value
# When the reference is set, initialize the view on the star.
if star_system_generator and star_system_generator.has_generated:
set_view(star_system_generator.get_system_data().star)
func _process(_delta: float) -> void: func _process(_delta: float) -> void:
# This forces the canvas to redraw every frame. if not focal_body:
set_view(star_system_generator.get_system_data().star)
queue_redraw() queue_redraw()
func _draw() -> void: # --- Main Public Method ---
if not star_system_generator:
# Sets the view to a new central body and rebuilds the list of what to draw.
func set_view(new_focal_body: CelestialBody) -> void:
if not is_instance_valid(new_focal_body):
return return
focal_body = new_focal_body
bodies_to_draw.clear()
# Draw a black background to obscure the main simulation view. # The view always includes the focal body.
var viewport_size = get_viewport().get_visible_rect().size bodies_to_draw.append(focal_body)
draw_rect(Rect2(Vector2.ZERO, viewport_size), Color("000000"))
# Add all direct children that are celestial bodies.
for child in focal_body.get_children():
if child is CelestialBody:
bodies_to_draw.append(child)
# If the star is the focus, also find and draw the asteroid belts.
if focal_body is Star:
var system_data = star_system_generator.get_system_data()
for belt in system_data.belts:
# We'll handle drawing belts separately in the _draw function.
pass
# --- Input Handling ---
func _unhandled_input(event: InputEvent) -> void:
if not focal_body:
return
# Handle Zoom In with Left Click
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed():
for body in bodies_to_draw:
# Calculate the body's position on screen for hit-testing.
var relative_pos = body.global_position - focal_body.global_position
var scaled_pos = relative_pos * draw_scale + get_viewport_center()
var radius = _get_body_draw_radius(body)
if event.position.distance_to(scaled_pos) < radius * 2.0: # A larger click target
set_view(body)
get_viewport().set_input_as_handled()
return
# Handle Zoom Out with Right Click
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT and event.is_pressed():
if is_instance_valid(focal_body.primary):
set_view(focal_body.primary)
get_viewport().set_input_as_handled()
# --- Drawing Logic ---
func _draw() -> void:
# [cite_start]Draw a black background. [cite: 4]
draw_rect(Rect2(Vector2.ZERO, get_viewport_size()), Color.BLACK)
if not is_instance_valid(focal_body):
focal_body = star_system_generator.get_system_data().star
return
# 1. Determine the scale for the current view.
var max_distance = 0.0 var max_distance = 0.0
var system_data = star_system_generator.get_system_data() for body in bodies_to_draw:
var all_bodies = system_data.all_bodies() if body == focal_body: continue
var distance = body.global_position.distance_to(focal_body.global_position)
# Find the furthest body from the star.
for body in all_bodies:
var distance = body.global_position.length()
#print(body)
if distance > max_distance: if distance > max_distance:
max_distance = distance max_distance = distance
# Determine the scale based on the viewport size. # Add a default zoom level if focused on a body with no children.
if max_distance == 0.0:
max_distance = 5.0e8 # An arbitrary distance for a nice solo view.
var system_diameter = max_distance * 2.0 var system_diameter = max_distance * 2.0
var draw_scale = min(viewport_size.x, viewport_size.y) / system_diameter draw_scale = min(get_viewport_size().x, get_viewport_size().y) / system_diameter
draw_scale *= 0.8 # Add some padding to the view. draw_scale *= 0.8 # Add some padding.
for belt in system_data.belts: # 2. Draw asteroid belts if the star is the focus.
var scaled_radius = Vector2(belt.centered_radius, 0.0) * draw_scale + viewport_size / 2 if focal_body is Star:
draw_circle(viewport_size / 2, (scaled_radius - viewport_size / 2).length(), Color.WHITE, false, 1.0) for belt in star_system_generator.get_system_data().belts:
#draw_string(ThemeDB.fallback_font, scaled_position + Vector2(radius + 2, -5), "Asteroid Belt", HORIZONTAL_ALIGNMENT_LEFT, -1, ThemeDB.fallback_font_size, Color.WHITE) var relative_radius = belt.centered_radius - focal_body.global_position.length()
var scaled_radius = relative_radius * draw_scale
# Draw each celestial body on the canvas. draw_circle(get_viewport_center(), scaled_radius, Color.WHITE, false)
for body in all_bodies:
# Get the scaled position.
var scaled_position = body.global_position * draw_scale + viewport_size / 2
# Define visual size based on body type.
var radius = 0.0
var color = Color.WHITE
match body.get_class_name():
"Star":
color = Color.GOLD
"Planet":
color = Color.BLUE
"Moon":
color = Color.PURPLE
"Station":
color = Color.WHITE
"Asteroid":
color = Color.BROWN
_:
color = Color.ORANGE_RED
if body is Star: # 3. Draw each celestial body relative to the focal body.
radius = 10.0 # Make the star smaller for the map. for body in bodies_to_draw:
elif body is Planet: var relative_pos = body.global_position - focal_body.global_position
radius = 8.0 var scaled_pos = relative_pos * draw_scale + get_viewport_center()
elif body is Moon:
radius = 5.0
elif body is Asteroid:
radius = 4.0 # Make asteroids bigger for visibility.
elif body is Station:
radius = 6.0
# Draw the celestial body.
if body is Planet or body is Moon or body is Station:
draw_string(ThemeDB.fallback_font, scaled_position + Vector2(radius + 2, -5), body.name, HORIZONTAL_ALIGNMENT_LEFT, -1, ThemeDB.fallback_font_size, color)
draw_circle(viewport_size / 2, (scaled_position - viewport_size / 2).length(), Color.WHITE, false, 1.0)
draw_circle(scaled_position, radius, color)
draw_string(ThemeDB.fallback_font, Vector2.ZERO + Vector2(10, 15), str(Engine.time_scale), HORIZONTAL_ALIGNMENT_LEFT, -1, ThemeDB.fallback_font_size, Color.HOT_PINK) var radius = _get_body_draw_radius(body)
var color = _get_body_draw_color(body)
var velocity: Vector2 = body.linear_velocity * draw_scale # Draw orbit line for all children
var force: Vector2 = body.current_central_force_real * draw_scale / body.sim_scale if body != focal_body and body is not Asteroid:
draw_circle(get_viewport_center(), scaled_pos.distance_to(get_viewport_center()), Color(Color.WHITE, 0.2), false)
draw_string(ThemeDB.fallback_font, scaled_pos + Vector2(radius + 5, 5), body.name, HORIZONTAL_ALIGNMENT_LEFT, -1, ThemeDB.fallback_font_size, color)
# Draw the body itself.
draw_circle(scaled_pos, radius, color)
# Draw velocity and force vectors.
var velocity: Vector2 = body.linear_velocity.normalized() * 25.0
var force: Vector2 = body.direction_to_primary * 25.0 # Normalize force for consistent arrow size
draw_arrow(scaled_pos, scaled_pos + velocity, Color.GREEN)
draw_arrow(scaled_pos, scaled_pos + force, Color.RED)
# --- Helper Functions ---
func get_viewport_size() -> Vector2:
return get_viewport().get_visible_rect().size
func get_viewport_center() -> Vector2:
return get_viewport_size() / 2.0
func _get_body_draw_radius(body: CelestialBody) -> float:
if body is Star: return 15.0
elif body is Planet: return 10.0
elif body is Moon: return 6.0
elif body is Station: return 7.0
elif body is Asteroid: return 4.0
return 5.0
func _get_body_draw_color(body: CelestialBody) -> Color:
match body.get_class_name():
"Star": return Color.GOLD
"Planet": return Color.BLUE
"Moon": return Color.PURPLE
"Station": return Color.WHITE
"Asteroid": return Color.BROWN
return Color.ORANGE_RED
# Draw the velocity arrow
#
## Draw the force arrow
draw_arrow(scaled_position, scaled_position + force, Color(1, 0, 0))
draw_arrow(scaled_position, scaled_position + velocity, Color(0, 1, 0))
func draw_arrow(start: Vector2, end: Vector2, color: Color): func draw_arrow(start: Vector2, end: Vector2, color: Color):
var head_size = max(1, (end - start).length() / 50) # Adjust the divisor for desired size draw_line(start, end, color, 2.0)
var direction = (end - start).normalized() var dir = (end - start).normalized()
var p1 = end - dir * 8 + dir.orthogonal() * 5
var p2 = end - dir * 8 - dir.orthogonal() * 5
draw_polygon(PackedVector2Array([end, p1, p2]), PackedColorArray([color, color, color]))
# Draw the line
draw_line(start, end, color)
# Draw the triangular arrowhead at the tip
var points = PackedVector2Array()
points.push_back(end)
points.push_back(end - direction * head_size + Vector2(-head_size, head_size))
points.push_back(end - direction * head_size + Vector2(-head_size, -head_size))
draw_polygon(points, PackedColorArray([color]))

View File

@ -10,7 +10,7 @@ func get_class_name() -> String:
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
# A Moon has a smaller mass than a planet. # A Moon has a smaller mass than a planet.
mass = 100.0 #mass = 100.0
radius = 10.0 radius = 10.0
# You can set a default texture here. # You can set a default texture here.

View File

@ -10,7 +10,7 @@ func get_class_name() -> String:
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
# A Planet has a smaller mass than a star. # A Planet has a smaller mass than a star.
mass = 1000.0 #mass = 1000.0
radius = 25.0 radius = 25.0
# You can set a default texture here. # You can set a default texture here.

View File

@ -8,7 +8,6 @@ func get_class_name() -> String:
func _ready() -> void: func _ready() -> void:
# A Star has no primary and a very large mass. # A Star has no primary and a very large mass.
primary = null primary = null
mass = 100000.0
radius = 50.0 radius = 50.0
# You can set a default texture here, or assign it in the Inspector. # You can set a default texture here, or assign it in the Inspector.

View File

@ -32,13 +32,15 @@ extends Node2D
# A scaling parameter to convert real-world units to game units. # A scaling parameter to convert real-world units to game units.
# 1 meter = sim_scale game units. # 1 meter = sim_scale game units.
@export_group("Simulation Scale") @export_group("Simulation Scale")
@export var sim_scale: float = 1.0e-9 @export_range(10e-12, 1.0, 10.e-3) var sim_scale: float = 1.0e-6
# A factor to scale the initial orbital distances to make the system visually compelling. # A factor to scale the initial orbital distances to make the system visually compelling.
@export var min_ring_distance: float = 2.0e10 @export var min_ring_distance: float = 500
@export var min_planetary_orbit_radius : float = 50
# A factor to determine the buffer between orbits based on mass. # A factor to determine the buffer between orbits based on mass.
@export var orbit_buffer_factor: float = 1 @export var orbit_buffer_factor: float = 1
const orbit_buffer_constant : float = 1.0e-13 const orbit_buffer_constant : float = 300
var orbit_buffer : float = orbit_buffer_constant * orbit_buffer_factor var orbit_buffer : float = orbit_buffer_constant * orbit_buffer_factor
# A flag to check if the system has been generated. # A flag to check if the system has been generated.
@ -46,7 +48,12 @@ var has_generated: bool = false
# Constants for real-world physics calculations. # Constants for real-world physics calculations.
const G = 6.67430e-11 # Gravitational constant (N·m²/kg²) const G = 6.67430e-11 # Gravitational constant (N·m²/kg²)
const SUN_MASS = 1.989e30 # Mass of the sun (kg) #const SUN_MASS = 1.989e30 # Mass of the sun (kg)
const SUN_MASS = 10.000
const PLANETARY_MASS = SUN_MASS / 10
const MOON_MASS = PLANETARY_MASS / 10
const ASTEROID_MASS = MOON_MASS / 10
const STATION_MASS = ASTEROID_MASS / 10
var system_data : SystemData var system_data : SystemData
@ -61,6 +68,8 @@ func generate_star_system() -> void:
# Create the star at the center of the system. # Create the star at the center of the system.
var star_instance = _create_star() var star_instance = _create_star()
add_child(star_instance)
# Generate and place all celestial bodies in randomized order. # Generate and place all celestial bodies in randomized order.
_generate_and_place_bodies(star_instance) _generate_and_place_bodies(star_instance)
@ -69,12 +78,11 @@ func _create_star() -> RigidBody2D:
var star_instance = star_scene.instantiate() as Star var star_instance = star_scene.instantiate() as Star
system_data.star = star_instance system_data.star = star_instance
star_instance.name = "Star" star_instance.name = "Star"
add_child(star_instance)
star_instance.sim_scale = sim_scale star_instance.sim_scale = sim_scale
# Set the star's properties. # Set the star's properties.
star_instance.orbit_radius_real = 0.0 star_instance.orbit_radius_real = 0.0
star_instance.mass_real = SUN_MASS star_instance.mass = SUN_MASS
star_instance.linear_velocity_real = Vector2.ZERO star_instance.linear_velocity_real = Vector2.ZERO
star_instance.modulate = Color("ffe066") # Yellow star_instance.modulate = Color("ffe066") # Yellow
@ -112,15 +120,15 @@ func _generate_and_place_bodies(primary: RigidBody2D) -> void:
planet_instance.name = "Planet " + str(current_orbit_radius) planet_instance.name = "Planet " + str(current_orbit_radius)
planet_instance.primary = primary planet_instance.primary = primary
planet_instance.sim_scale = sim_scale planet_instance.sim_scale = sim_scale
planet_instance.mass_real = randf_range(1e24, 1e25) planet_instance.mass = PLANETARY_MASS # randf_range(1e24, 1e25)
# Calculate orbit based on the last placed body. # Calculate orbit based on the last placed body.
planet_instance.orbit_radius_real = current_orbit_radius + (planet_instance.mass_real * orbit_buffer) planet_instance.orbit_radius_real = current_orbit_radius + (planet_instance.mass * orbit_buffer)
_create_body_in_ring(primary, planet_instance) _create_body_in_ring(primary, planet_instance)
_create_moons_and_stations(planet_instance) _create_moons_and_stations(planet_instance)
current_orbit_radius = planet_instance.orbit_radius_real + (planet_instance.mass_real * orbit_buffer) current_orbit_radius = planet_instance.orbit_radius_real + (planet_instance.mass * orbit_buffer)
"asteroid_belt": "asteroid_belt":
var belt = _create_asteroid_belt(primary, current_orbit_radius) var belt = _create_asteroid_belt(primary, current_orbit_radius)
@ -134,38 +142,40 @@ func _generate_and_place_bodies(primary: RigidBody2D) -> void:
station_instance.name = "Star Station " + str(current_orbit_radius) station_instance.name = "Star Station " + str(current_orbit_radius)
station_instance.primary = primary station_instance.primary = primary
station_instance.sim_scale = sim_scale station_instance.sim_scale = sim_scale
station_instance.mass_real = 1e8 # A very small mass station_instance.mass = STATION_MASS # A very small mass
station_instance.orbit_radius_real = current_orbit_radius + (station_instance.mass_real * orbit_buffer) station_instance.orbit_radius_real = current_orbit_radius + (station_instance.mass * orbit_buffer)
_create_body_in_ring(primary, station_instance) _create_body_in_ring(primary, station_instance)
current_orbit_radius = station_instance.orbit_radius_real + (station_instance.mass_real * orbit_buffer) current_orbit_radius = station_instance.orbit_radius_real + (station_instance.mass * orbit_buffer)
print("Star system generation complete.") print("Star system generation complete.")
# Creates moons and stations around a primary body. # Creates moons and stations around a primary body.
func _create_moons_and_stations(primary: RigidBody2D) -> void: func _create_moons_and_stations(primary: RigidBody2D) -> void:
var num_moons = randi_range(min_moons, max_moons) var num_moons = randi_range(min_moons, max_moons)
var moon_orbit_radius = 5e7 var moon_orbit_radius = min_planetary_orbit_radius
for i in range(num_moons): for i in range(num_moons):
var moon_instance = moon_scene.instantiate() as CelestialBody var moon_instance = moon_scene.instantiate() as CelestialBody
system_data.moons.append(moon_instance)
moon_instance.name = "Moon " + str(i + 1) moon_instance.name = "Moon " + str(i + 1)
moon_instance.primary = primary moon_instance.primary = primary
moon_instance.sim_scale = sim_scale moon_instance.sim_scale = sim_scale
moon_instance.mass_real = randf_range(1e22, 1e23) moon_instance.mass = MOON_MASS # randf_range(1e22, 1e23)
moon_instance.orbit_radius_real = moon_orbit_radius + randf_range(1e7, 5e7) moon_instance.orbit_radius_real = moon_orbit_radius + randf_range(0, 50)
_create_body_in_ring(primary, moon_instance) _create_body_in_ring(primary, moon_instance)
moon_orbit_radius = moon_instance.orbit_radius_real moon_orbit_radius = moon_instance.orbit_radius_real
# Generate a space station. # Generate a space station.
var station_instance = station_scene.instantiate() as CelestialBody var station_instance = station_scene.instantiate() as CelestialBody
system_data.stations.append(station_instance)
station_instance.name = "Station" station_instance.name = "Station"
station_instance.primary = primary station_instance.primary = primary
station_instance.sim_scale = sim_scale station_instance.sim_scale = sim_scale
station_instance.mass_real = 1e8 station_instance.mass = STATION_MASS
station_instance.orbit_radius_real = moon_orbit_radius + 5e7 station_instance.orbit_radius_real = moon_orbit_radius + randf_range(0, 50)
_create_body_in_ring(primary, station_instance) _create_body_in_ring(primary, station_instance)
# Creates a single asteroid belt. # Creates a single asteroid belt.
@ -178,11 +188,11 @@ func _create_asteroid_belt(primary: RigidBody2D, initial_offset: float) -> Aster
asteroid_instance.name = "Asteroid " + str(i + 1) asteroid_instance.name = "Asteroid " + str(i + 1)
asteroid_instance.primary = primary asteroid_instance.primary = primary
asteroid_instance.sim_scale = sim_scale asteroid_instance.sim_scale = sim_scale
asteroid_instance.mass_real = randf_range(1e10, 1e23) asteroid_instance.mass = ASTEROID_MASS # randf_range(1e10, 1e23)
belt.asteroids.append(asteroid_instance) belt.asteroids.append(asteroid_instance)
belt.mass = belt.asteroids.reduce(func(accum, asteroid : CelestialBody): return accum + asteroid.mass_real, 0.0) belt.mass = belt.asteroids.reduce(func(accum, asteroid : CelestialBody): return accum + asteroid.mass, 0.0)
var offset = belt.mass * orbit_buffer var offset = belt.mass * orbit_buffer
belt.centered_radius = initial_offset + offset belt.centered_radius = initial_offset + offset
@ -196,21 +206,19 @@ func _create_asteroid_belt(primary: RigidBody2D, initial_offset: float) -> Aster
# Helper function to instantiate and place a body in a ring. # Helper function to instantiate and place a body in a ring.
func _create_body_in_ring(primary: CelestialBody, body_instance: CelestialBody) -> void: func _create_body_in_ring(primary: CelestialBody, body_instance: CelestialBody) -> void:
var stable_velocity = calculate_stable_orbit_velocity(body_instance.orbit_radius_real, primary.mass_real) #var stable_velocity = calculate_stable_orbit_velocity(body_instance.orbit_radius_real, primary.mass_real)
var initial_position_vector = Vector2(body_instance.orbit_radius_real, 0).rotated(randf() * TAU) var initial_position_vector = Vector2(body_instance.orbit_radius_real, 0).rotated(randf() * TAU)
body_instance.global_position_real = primary.global_position_real + initial_position_vector body_instance.global_position = primary.global_position_real + initial_position_vector
body_instance.global_position = body_instance.global_position_real / sim_scale
var body_velocity_vector = Vector2(0, stable_velocity).rotated(initial_position_vector.angle() + PI / 2)
body_instance.linear_velocity_real = body_instance.calculate_initial_orbit_real(primary, body_instance)
primary.add_child(body_instance) primary.add_child(body_instance)
print("Created " + body_instance.name + " with radius " + str(body_instance.orbit_radius_real) + " and mass " + str(body_instance.mass_real)) body_instance.linear_velocity = body_instance.calculate_initial_orbit_real(primary, body_instance)
print("Created " + body_instance.name + " with radius " + str(body_instance.orbit_radius_real) + " and mass " + str(body_instance.mass))
print("Initial orbital velocity is: " + str(body_instance.linear_velocity))
# Calculates the velocity required for a stable circular orbit. # Calculates the velocity required for a stable circular orbit.
func calculate_stable_orbit_velocity(orbit_radius: float, primary_mass: float) -> float: #func calculate_stable_orbit_velocity(orbit_radius: float, primary_mass: float) -> float:
return sqrt(G * primary_mass / orbit_radius) #return sqrt(G * primary_mass / orbit_radius)
# Recursively finds all celestial bodies in the scene. # Recursively finds all celestial bodies in the scene.
func get_all_bodies() -> Array: func get_all_bodies() -> Array:
@ -236,6 +244,7 @@ class AsteroidBelt:
class SystemData: class SystemData:
var star : CelestialBody var star : CelestialBody
var planets : Array[CelestialBody] var planets : Array[CelestialBody]
var moons: Array[CelestialBody]
var stations : Array[CelestialBody] var stations : Array[CelestialBody]
var belts : Array[AsteroidBelt] var belts : Array[AsteroidBelt]
@ -243,6 +252,8 @@ class SystemData:
var bodies : Array[CelestialBody] = [star] var bodies : Array[CelestialBody] = [star]
bodies.append_array(planets) bodies.append_array(planets)
bodies.append_array(stations) bodies.append_array(stations)
bodies.append_array(moons)
var all_asteroids : Array[CelestialBody] = [] var all_asteroids : Array[CelestialBody] = []
for belt in belts: for belt in belts:

View File

@ -10,7 +10,7 @@ func get_class_name() -> String:
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
# A Station has negligible mass for physics calculations. # A Station has negligible mass for physics calculations.
mass = 0.001 #mass = 0.001
radius = 15.0 radius = 15.0
# You can set a default texture here. # You can set a default texture here.