initial commit

This commit is contained in:
olof.pettersson
2025-09-12 15:54:10 +02:00
commit 99e032f303
34 changed files with 750 additions and 0 deletions

4
.editorconfig Normal file
View File

@ -0,0 +1,4 @@
root = true
[*]
charset = utf-8

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Godot 4+ specific ignores
.godot/
/android/

1
icon.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>

After

Width:  |  Height:  |  Size: 994 B

37
icon.svg.import Normal file
View File

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b7sxyli8cn36w"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

25
main.tscn Normal file
View File

@ -0,0 +1,25 @@
[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_ig7tw"]
[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_ig7tw")
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")
[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("..")

43
project.godot Normal file
View File

@ -0,0 +1,43 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="space_simulation"
run/main_scene="uid://dogqi2c58qdc0"
config/features=PackedStringArray("4.4", "Forward Plus")
config/icon="res://icon.svg"
[input]
scroll_up={
"deadzone": 0.2,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":4,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
scroll_down={
"deadzone": 0.2,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
ui_map_mode={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":77,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
[physics]
3d/default_linear_damp=0.0
3d/sleep_threshold_linear=0.0
2d/default_gravity=0.0
2d/default_gravity_vector=Vector2(0, 0)
2d/default_linear_damp=0.0
2d/sleep_threshold_linear=0.0

7
scenes/asteroid.tscn Normal file
View File

@ -0,0 +1,7 @@
[gd_scene load_steps=2 format=3 uid="uid://bawsujtlpmh5r"]
[ext_resource type="Script" uid="uid://c816xae77cbmq" path="res://scripts/asteroid.gd" id="1_akfqu"]
[node name="Asteroid" type="RigidBody2D"]
script = ExtResource("1_akfqu")
metadata/_custom_type_script = "uid://c816xae77cbmq"

View File

@ -0,0 +1,9 @@
[gd_scene load_steps=2 format=3 uid="uid://cm5qsuunboxm3"]
[ext_resource type="Script" uid="uid://baawsgn3k6wpp" path="res://scripts/developer_pawn.gd" id="1_lme2g"]
[node name="DeveloperPawn" type="CharacterBody2D" node_paths=PackedStringArray("camera")]
script = ExtResource("1_lme2g")
camera = NodePath("Camera2D")
[node name="Camera2D" type="Camera2D" parent="."]

11
scenes/map_canvas.tscn Normal file
View File

@ -0,0 +1,11 @@
[gd_scene load_steps=3 format=3 uid="uid://ctlw5diis8h1x"]
[ext_resource type="Script" uid="uid://drsuoxsqdxdql" path="res://scripts/map_canvas.gd" id="1_r1rlf"]
[ext_resource type="Script" uid="uid://uh0k4c3qj4x0" path="res://scenes/map_drawer.gd" id="2_tspw4"]
[node name="MapCanvas" type="CanvasLayer" node_paths=PackedStringArray("map_drawer")]
script = ExtResource("1_r1rlf")
map_drawer = NodePath("Node2D")
[node name="Node2D" type="Node2D" parent="."]
script = ExtResource("2_tspw4")

70
scenes/map_drawer.gd Normal file
View File

@ -0,0 +1,70 @@
class_name MapDrawer
extends Node2D
# A reference to the StarSystemGenerator node, which will be set by the MapCanvas.
var star_system_generator: Node
func _process(_delta: float) -> void:
# This forces the canvas to redraw every frame.
queue_redraw()
func _draw() -> void:
if not star_system_generator:
return
# Draw a black background to obscure the main simulation view.
var viewport_size = get_viewport().get_visible_rect().size
draw_rect(Rect2(Vector2.ZERO, viewport_size), Color("3d3d3d"))
var max_distance = 0.0
var all_bodies = star_system_generator.get_all_bodies()
# Find the furthest body from the star.
for body in all_bodies:
var distance = body.position.length()
if distance > max_distance:
max_distance = distance
# Determine the scale based on the viewport size.
var system_diameter = max_distance * 2.0
var draw_scale = min(viewport_size.x, viewport_size.y) / system_diameter
draw_scale *= 0.8 # Add some padding to the view.
# Draw each celestial body on the canvas.
for body in all_bodies:
# Get the scaled position.
var scaled_position = body.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:
radius = 10.0 # Make the star smaller for the map.
elif body is Planet:
radius = 8.0
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.
draw_circle(scaled_position, radius, color)
# Position the text slightly to the side of the circle.
draw_string(ThemeDB.fallback_font, scaled_position + Vector2(radius + 2, -5), body.name, HORIZONTAL_ALIGNMENT_LEFT, -1, ThemeDB.fallback_font_size, color)

1
scenes/map_drawer.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://uh0k4c3qj4x0

7
scenes/moon.tscn Normal file
View File

@ -0,0 +1,7 @@
[gd_scene load_steps=2 format=3 uid="uid://74ppvxcw8an4"]
[ext_resource type="Script" uid="uid://b1xsx7er22nxn" path="res://scripts/moon.gd" id="1_530pw"]
[node name="Moon" type="RigidBody2D"]
script = ExtResource("1_530pw")
metadata/_custom_type_script = "uid://bn1u2xood3vs6"

7
scenes/planet.tscn Normal file
View File

@ -0,0 +1,7 @@
[gd_scene load_steps=2 format=3 uid="uid://clt4qlsjcfgln"]
[ext_resource type="Script" uid="uid://5f6ipgu65urb" path="res://scripts/planet.gd" id="1_cktii"]
[node name="Planet" type="RigidBody2D"]
script = ExtResource("1_cktii")
metadata/_custom_type_script = "uid://bn1u2xood3vs6"

7
scenes/star.tscn Normal file
View File

@ -0,0 +1,7 @@
[gd_scene load_steps=2 format=3 uid="uid://5uqp4amjj7ww"]
[ext_resource type="Script" uid="uid://um2sfghmii42" path="res://scripts/star.gd" id="1_mcqwg"]
[node name="Star" type="RigidBody2D"]
script = ExtResource("1_mcqwg")
metadata/_custom_type_script = "uid://bn1u2xood3vs6"

7
scenes/station.tscn Normal file
View File

@ -0,0 +1,7 @@
[gd_scene load_steps=2 format=3 uid="uid://dm3s33o4xhqfv"]
[ext_resource type="Script" uid="uid://ulw61oxppwdu" path="res://scripts/station.gd" id="1_rod8h"]
[node name="Station" type="RigidBody2D"]
script = ExtResource("1_rod8h")
metadata/_custom_type_script = "uid://bn1u2xood3vs6"

19
scripts/asteroid.gd Normal file
View File

@ -0,0 +1,19 @@
class_name Asteroid
extends CelestialBody
# The orbital radius for this asteroid.
var orbital_radius: float
func get_class_name() -> String:
return "Asteroid"
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
# An Asteroid has negligible mass for physics calculations.
mass = 0.001
radius = 5.0
# You can set a default texture here.
# texture = preload("res://assets/asteroid_texture.png")
super._ready()

1
scripts/asteroid.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://c816xae77cbmq

94
scripts/celestial_body.gd Normal file
View File

@ -0,0 +1,94 @@
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

View File

@ -0,0 +1 @@
uid://bn1u2xood3vs6

86
scripts/developer_pawn.gd Normal file
View File

@ -0,0 +1,86 @@
class_name DeveloperPawn
extends CharacterBody2D
# Movement speed in pixels per second.
@export var movement_speed: float = 500.0
# Zoom speed.
@export var zoom_speed: float = 1.0
# Reference to the Camera2D node.
@export var camera: Camera2D
# Reference to the new MapCanvas node.
@export var map_canvas: CanvasLayer
var map_mode : bool = false
func _ready() -> void:
# Ensure all references are set.
if not camera:
print("ERROR: Camera2D reference not set on DeveloperPawn.")
set_physics_process(false)
return
if not map_canvas:
print("ERROR: MapCanvas reference not set on DeveloperPawn.")
set_physics_process(false)
return
# Disable the default physics processing on the pawn itself.
# We will handle all movement manually for direct control.
set_physics_process(false)
# Set the process mode to get input and move the pawn.
set_process(true)
# Hide the map canvas initially.
map_canvas.hide()
# Called every frame to handle input.
func _process(delta: float) -> void:
if not map_mode:
handle_input(delta)
# Handles player input for movement and zooming.
func handle_input(delta: float) -> void:
# Get movement input from WASD keys.
var input_vector = Vector2.ZERO
if Input.is_action_pressed("ui_up"):
input_vector.y -= 1
if Input.is_action_pressed("ui_down"):
input_vector.y += 1
if Input.is_action_pressed("ui_left"):
input_vector.x -= 1
if Input.is_action_pressed("ui_right"):
input_vector.x += 1
# Normalize the vector to prevent faster diagonal movement.
input_vector = input_vector.normalized()
# Update the pawn's position directly.
position += input_vector * movement_speed * delta
# Handles zoom input from the mouse wheel and map mode toggle.
func _input(event: InputEvent) -> void:
if event is InputEventMouseButton:
if camera and not map_mode:
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
# Zoom in by dividing the zoom vector.
camera.zoom -= Vector2(zoom_speed, zoom_speed)
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
# Zoom out by multiplying the zoom vector.
camera.zoom += Vector2(zoom_speed, zoom_speed)
# Clamp the zoom to prevent it from getting too large or too small.
# The minimum zoom is now 0.01, and the maximum is a larger value.
camera.zoom.x = clamp(camera.zoom.x, 0.01, 250.0)
camera.zoom.y = clamp(camera.zoom.y, 0.01, 250.0)
if event.is_action_pressed("ui_map_mode"):
map_mode = not map_mode
if map_mode:
# If entering map mode, show the map canvas.
map_canvas.show()
else:
# If exiting map mode, hide the map canvas.
map_canvas.hide()

View File

@ -0,0 +1 @@
uid://baawsgn3k6wpp

22
scripts/map_canvas.gd Normal file
View File

@ -0,0 +1,22 @@
class_name MapCanvas
extends CanvasLayer
# A reference to the StarSystemGenerator node.
@export var star_system_generator: Node
# A reference to the new MapDrawer node.
@export var map_drawer: Node2D
func _ready() -> void:
# Ensure the generator and drawer references are set.
if not star_system_generator:
print("ERROR: StarSystemGenerator reference not set on MapCanvas.")
set_physics_process(false)
return
if not map_drawer:
print("ERROR: MapDrawer reference not set on MapCanvas.")
set_physics_process(false)
return
# Pass the generator reference to the drawer node.
map_drawer.star_system_generator = star_system_generator

View File

@ -0,0 +1 @@
uid://drsuoxsqdxdql

19
scripts/moon.gd Normal file
View File

@ -0,0 +1,19 @@
class_name Moon
extends CelestialBody
# The orbital radius for this moon.
var orbital_radius: float
func get_class_name() -> String:
return "Moon"
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
# A Moon has a smaller mass than a planet.
mass = 100.0
radius = 10.0
# You can set a default texture here.
# texture = preload("res://assets/moon_texture.png")
super._ready()

1
scripts/moon.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://b1xsx7er22nxn

19
scripts/planet.gd Normal file
View File

@ -0,0 +1,19 @@
class_name Planet
extends CelestialBody
# The orbital radius for this planet.
var orbital_radius: float
func get_class_name() -> String:
return "Planet"
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
# A Planet has a smaller mass than a star.
mass = 1000.0
radius = 25.0
# You can set a default texture here.
# texture = preload("res://assets/planet_texture.png")
super._ready()

1
scripts/planet.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://5f6ipgu65urb

17
scripts/star.gd Normal file
View File

@ -0,0 +1,17 @@
class_name Star
extends CelestialBody
func get_class_name() -> String:
return "Star"
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
# A Star has no primary and a very large mass.
primary = null
mass = 100000.0
radius = 50.0
# You can set a default texture here, or assign it in the Inspector.
# texture = preload("res://assets/star_texture.png")
super._ready()

1
scripts/star.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://um2sfghmii42

View File

@ -0,0 +1,205 @@
class_name StarSystemGenerator
extends Node2D
# Number of bodies to generate for each type.
@export var num_planets: int = 5
@export var num_moons_per_planet: int = 2
@export var num_stations: int = 3
# Exported scenes to be instantiated. Drag and drop the scene files
# for each body from the Godot FileSystem dock into these properties.
@export var star_scene: PackedScene
@export var planet_scene: PackedScene
@export var moon_scene: PackedScene
@export var station_scene: PackedScene
@export var asteroid_scene: PackedScene
# --- Simulation Parameters ---
@export var sim_scale: float = 1e+9 # A scale of 1 unit per 1 billion meters.
# --- Star Parameters ---
# Increasing the star's mass to increase overall gravitational influence.
const STAR_MASS_REAL = 1.989e+30 # Mass of the Sun in kg.
const STAR_RADIUS = 50.0
# --- Planet Parameters ---
# Increasing the distances to give planets more space and allow for higher velocities.
const PLANET_DISTANCE_MIN = 50.0 * 1.5e+10 # 50 AU
const PLANET_DISTANCE_MAX = 500.0 * 1.5e+10 # 500 AU
const PLANET_COUNT_MIN = 3
const PLANET_COUNT_MAX = 8
# --- Moon Parameters ---
const MOON_DISTANCE_MIN = 2e8 # 20,000 km
const MOON_DISTANCE_MAX = 3e9 # 100,000 km
const MOON_COUNT_MIN = 0
const MOON_COUNT_MAX = 4
# --- Asteroid Parameters ---
# Minimum and maximum number of asteroids to generate.
@export var MIN_ASTEROIDS: int = 50
@export var MAX_ASTEROIDS: int = 200
const ASTEROID_DISTANCE_MIN = 3.2e11
const ASTEROID_DISTANCE_MAX = 4.8e11
# --- Station Parameters ---
const STATION_COUNT_MIN = 1
const STATION_COUNT_MAX = 3
var star: CelestialBody
var planets: Array
var moons: Array
var asteroids: Array
var stations: Array
const NAME_TEMPLATE_STR = "%s_%s"
func _ready() -> void:
generate_star_system()
func generate_star_system() -> void:
randomize()
star = create_star()
add_child(star)
planets = create_planets(star)
for planet in planets:
add_child(planet)
asteroids = create_asteroids(star)
for asteroid in asteroids:
add_child(asteroid)
stations = create_stations(star)
for station in stations:
add_child(station)
func get_all_bodies() -> Array:
var all_bodies = []
all_bodies.append(star)
all_bodies.append_array(planets)
all_bodies.append_array(asteroids)
all_bodies.append_array(stations)
all_bodies.append_array(moons)
return all_bodies
func create_star() -> CelestialBody:
var star_instance = star_scene.instantiate() as CelestialBody
star_instance.position = Vector2.ZERO
star_instance.mass_real = STAR_MASS_REAL
star_instance.radius = STAR_RADIUS
star_instance.sim_scale = sim_scale
return star_instance
func create_planets(primary_body: CelestialBody) -> Array:
var planets = []
var planet_count = randi_range(PLANET_COUNT_MIN, PLANET_COUNT_MAX)
for i in range(planet_count):
var planet_instance = planet_scene.instantiate() as CelestialBody
planet_instance.name = NAME_TEMPLATE_STR % [planet_instance.get_class_name(), i]
planet_instance.primary = primary_body
planet_instance.mass_real = randf_range(5.972e+24, 6.39e+26) # Earth to Saturn mass
planet_instance.radius = randf_range(30.0, 80.0)
planet_instance.sim_scale = sim_scale
var distance_real = randf_range(PLANET_DISTANCE_MIN, PLANET_DISTANCE_MAX)
var distance_scaled = distance_real / sim_scale
var velocity_scaled = planet_instance.get_stable_orbit_velocity(primary_body.mass_real, distance_real)
var orbit_angle = randf_range(0.0, PI * 2)
planet_instance.position.x = distance_scaled * cos(orbit_angle)
planet_instance.position.y = distance_scaled * sin(orbit_angle)
planet_instance.linear_velocity = Vector2(0, velocity_scaled).rotated(orbit_angle + PI / 2.0)
planets.append(planet_instance)
var planet_moons = create_moons(planet_instance)
for moon in planet_moons:
planet_instance.add_child(moon)
moons.append(moon)
return planets
func create_moons(primary_body: CelestialBody) -> Array:
var moons = []
var moon_count = randi_range(MOON_COUNT_MIN, MOON_COUNT_MAX)
for i in range(moon_count):
var moon_instance = moon_scene.instantiate() as CelestialBody
moon_instance.name = NAME_TEMPLATE_STR % [moon_instance.get_class_name(), i]
moon_instance.primary = primary_body
moon_instance.mass_real = randf_range(7.342e+22, 1.48e+23) # Moon to Triton mass
moon_instance.radius = randf_range(10.0, 20.0)
moon_instance.sim_scale = sim_scale
var distance_real = randf_range(MOON_DISTANCE_MIN, MOON_DISTANCE_MAX)
var distance_scaled = distance_real / sim_scale
var velocity_scaled = moon_instance.get_stable_orbit_velocity(primary_body.mass_real, distance_real)
var orbit_angle = randf_range(0.0, PI * 2)
moon_instance.position.x = primary_body.position.x + distance_scaled * cos(orbit_angle)
moon_instance.position.y = primary_body.position.y + distance_scaled * sin(orbit_angle)
moon_instance.linear_velocity = primary_body.linear_velocity + Vector2(0, velocity_scaled).rotated(orbit_angle + PI / 2.0)
moons.append(moon_instance)
return moons
func create_asteroids(primary_body: CelestialBody) -> Array:
var asteroids = []
var asteroid_count = randi_range(MIN_ASTEROIDS, MAX_ASTEROIDS)
for i in range(asteroid_count):
var asteroid_instance = asteroid_scene.instantiate() as CelestialBody
asteroid_instance.name = NAME_TEMPLATE_STR % [asteroid_instance.get_class_name(), i]
asteroid_instance.primary = primary_body
asteroid_instance.mass_real = randf_range(1e+12, 1e+16) # A realistic asteroid mass range
asteroid_instance.radius = randf_range(2.0, 8.0)
asteroid_instance.sim_scale = sim_scale
var distance_real = randf_range(ASTEROID_DISTANCE_MIN, ASTEROID_DISTANCE_MAX)
var distance_scaled = distance_real / sim_scale
var velocity_scaled = asteroid_instance.get_stable_orbit_velocity(primary_body.mass_real, distance_real)
var orbit_angle = randf_range(0.0, PI * 2)
asteroid_instance.position.x = distance_scaled * cos(orbit_angle)
asteroid_instance.position.y = distance_scaled * sin(orbit_angle)
asteroid_instance.linear_velocity = Vector2(0, velocity_scaled).rotated(orbit_angle + PI / 2.0)
asteroids.append(asteroid_instance)
return asteroids
func create_stations(primary_body: CelestialBody) -> Array:
var stations = []
var station_count = randi_range(STATION_COUNT_MIN, STATION_COUNT_MAX)
for i in range(station_count):
var station_instance = station_scene.instantiate() as CelestialBody
station_instance.name = NAME_TEMPLATE_STR % [station_instance.get_class_name(), i]
station_instance.primary = primary_body
station_instance.mass_real = randf_range(5e+5, 1e+6) # Realistic mass for a large space station
station_instance.radius = randf_range(15.0, 25.0)
station_instance.sim_scale = sim_scale
var distance_real = randf_range(PLANET_DISTANCE_MIN, PLANET_DISTANCE_MAX)
var distance_scaled = distance_real / sim_scale
var velocity_scaled = station_instance.get_stable_orbit_velocity(primary_body.mass_real, distance_real)
var orbit_angle = randf_range(0.0, PI * 2)
station_instance.position.x = distance_scaled * cos(orbit_angle)
station_instance.position.y = distance_scaled * sin(orbit_angle)
station_instance.linear_velocity = Vector2(0, velocity_scaled).rotated(orbit_angle + PI / 2.0)
stations.append(station_instance)
return stations

View File

@ -0,0 +1 @@
uid://j3j483itissq

19
scripts/station.gd Normal file
View File

@ -0,0 +1,19 @@
class_name Station
extends CelestialBody
# The orbital radius for this station.
var orbital_radius: float
func get_class_name() -> String:
return "Station"
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
# A Station has negligible mass for physics calculations.
mass = 0.001
radius = 15.0
# You can set a default texture here.
# texture = preload("res://assets/station_texture.png")
super._ready()

1
scripts/station.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://ulw61oxppwdu