commit 99e032f303123508d324ac035f4ae36495a6f1de Author: olof.pettersson Date: Fri Sep 12 15:54:10 2025 +0200 initial commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f28239b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +charset = utf-8 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0af181c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Godot 4+ specific ignores +.godot/ +/android/ diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..9d8b7fa --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 0000000..a4787ff --- /dev/null +++ b/icon.svg.import @@ -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 diff --git a/main.tscn b/main.tscn new file mode 100644 index 0000000..888f0cd --- /dev/null +++ b/main.tscn @@ -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("..") diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..aa0e556 --- /dev/null +++ b/project.godot @@ -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 diff --git a/scenes/asteroid.tscn b/scenes/asteroid.tscn new file mode 100644 index 0000000..d9f4cf2 --- /dev/null +++ b/scenes/asteroid.tscn @@ -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" diff --git a/scenes/developer_pawn.tscn b/scenes/developer_pawn.tscn new file mode 100644 index 0000000..3801204 --- /dev/null +++ b/scenes/developer_pawn.tscn @@ -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="."] diff --git a/scenes/map_canvas.tscn b/scenes/map_canvas.tscn new file mode 100644 index 0000000..7014440 --- /dev/null +++ b/scenes/map_canvas.tscn @@ -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") diff --git a/scenes/map_drawer.gd b/scenes/map_drawer.gd new file mode 100644 index 0000000..1e1df66 --- /dev/null +++ b/scenes/map_drawer.gd @@ -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) diff --git a/scenes/map_drawer.gd.uid b/scenes/map_drawer.gd.uid new file mode 100644 index 0000000..7c0e552 --- /dev/null +++ b/scenes/map_drawer.gd.uid @@ -0,0 +1 @@ +uid://uh0k4c3qj4x0 diff --git a/scenes/moon.tscn b/scenes/moon.tscn new file mode 100644 index 0000000..5ac66a9 --- /dev/null +++ b/scenes/moon.tscn @@ -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" diff --git a/scenes/planet.tscn b/scenes/planet.tscn new file mode 100644 index 0000000..583c184 --- /dev/null +++ b/scenes/planet.tscn @@ -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" diff --git a/scenes/star.tscn b/scenes/star.tscn new file mode 100644 index 0000000..dd134df --- /dev/null +++ b/scenes/star.tscn @@ -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" diff --git a/scenes/station.tscn b/scenes/station.tscn new file mode 100644 index 0000000..e6b0287 --- /dev/null +++ b/scenes/station.tscn @@ -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" diff --git a/scripts/asteroid.gd b/scripts/asteroid.gd new file mode 100644 index 0000000..1db5f10 --- /dev/null +++ b/scripts/asteroid.gd @@ -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() diff --git a/scripts/asteroid.gd.uid b/scripts/asteroid.gd.uid new file mode 100644 index 0000000..fe54404 --- /dev/null +++ b/scripts/asteroid.gd.uid @@ -0,0 +1 @@ +uid://c816xae77cbmq diff --git a/scripts/celestial_body.gd b/scripts/celestial_body.gd new file mode 100644 index 0000000..9741f61 --- /dev/null +++ b/scripts/celestial_body.gd @@ -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 diff --git a/scripts/celestial_body.gd.uid b/scripts/celestial_body.gd.uid new file mode 100644 index 0000000..7613398 --- /dev/null +++ b/scripts/celestial_body.gd.uid @@ -0,0 +1 @@ +uid://bn1u2xood3vs6 diff --git a/scripts/developer_pawn.gd b/scripts/developer_pawn.gd new file mode 100644 index 0000000..e038a17 --- /dev/null +++ b/scripts/developer_pawn.gd @@ -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() diff --git a/scripts/developer_pawn.gd.uid b/scripts/developer_pawn.gd.uid new file mode 100644 index 0000000..32a080f --- /dev/null +++ b/scripts/developer_pawn.gd.uid @@ -0,0 +1 @@ +uid://baawsgn3k6wpp diff --git a/scripts/map_canvas.gd b/scripts/map_canvas.gd new file mode 100644 index 0000000..490038e --- /dev/null +++ b/scripts/map_canvas.gd @@ -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 diff --git a/scripts/map_canvas.gd.uid b/scripts/map_canvas.gd.uid new file mode 100644 index 0000000..ed3a84c --- /dev/null +++ b/scripts/map_canvas.gd.uid @@ -0,0 +1 @@ +uid://drsuoxsqdxdql diff --git a/scripts/moon.gd b/scripts/moon.gd new file mode 100644 index 0000000..ad68672 --- /dev/null +++ b/scripts/moon.gd @@ -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() diff --git a/scripts/moon.gd.uid b/scripts/moon.gd.uid new file mode 100644 index 0000000..7d986ea --- /dev/null +++ b/scripts/moon.gd.uid @@ -0,0 +1 @@ +uid://b1xsx7er22nxn diff --git a/scripts/planet.gd b/scripts/planet.gd new file mode 100644 index 0000000..3476462 --- /dev/null +++ b/scripts/planet.gd @@ -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() diff --git a/scripts/planet.gd.uid b/scripts/planet.gd.uid new file mode 100644 index 0000000..b6322e5 --- /dev/null +++ b/scripts/planet.gd.uid @@ -0,0 +1 @@ +uid://5f6ipgu65urb diff --git a/scripts/star.gd b/scripts/star.gd new file mode 100644 index 0000000..6f416d1 --- /dev/null +++ b/scripts/star.gd @@ -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() diff --git a/scripts/star.gd.uid b/scripts/star.gd.uid new file mode 100644 index 0000000..f90bdf4 --- /dev/null +++ b/scripts/star.gd.uid @@ -0,0 +1 @@ +uid://um2sfghmii42 diff --git a/scripts/star_system_generator.gd b/scripts/star_system_generator.gd new file mode 100644 index 0000000..9257c99 --- /dev/null +++ b/scripts/star_system_generator.gd @@ -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 diff --git a/scripts/star_system_generator.gd.uid b/scripts/star_system_generator.gd.uid new file mode 100644 index 0000000..e937e28 --- /dev/null +++ b/scripts/star_system_generator.gd.uid @@ -0,0 +1 @@ +uid://j3j483itissq diff --git a/scripts/station.gd b/scripts/station.gd new file mode 100644 index 0000000..6e3bf92 --- /dev/null +++ b/scripts/station.gd @@ -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() diff --git a/scripts/station.gd.uid b/scripts/station.gd.uid new file mode 100644 index 0000000..c39eb24 --- /dev/null +++ b/scripts/station.gd.uid @@ -0,0 +1 @@ +uid://ulw61oxppwdu