From 99e032f303123508d324ac035f4ae36495a6f1de Mon Sep 17 00:00:00 2001 From: "olof.pettersson" Date: Fri, 12 Sep 2025 15:54:10 +0200 Subject: [PATCH] initial commit --- .editorconfig | 4 + .gitattributes | 2 + .gitignore | 3 + icon.svg | 1 + icon.svg.import | 37 +++++ main.tscn | 25 ++++ project.godot | 43 ++++++ scenes/asteroid.tscn | 7 + scenes/developer_pawn.tscn | 9 ++ scenes/map_canvas.tscn | 11 ++ scenes/map_drawer.gd | 70 +++++++++ scenes/map_drawer.gd.uid | 1 + scenes/moon.tscn | 7 + scenes/planet.tscn | 7 + scenes/star.tscn | 7 + scenes/station.tscn | 7 + scripts/asteroid.gd | 19 +++ scripts/asteroid.gd.uid | 1 + scripts/celestial_body.gd | 94 ++++++++++++ scripts/celestial_body.gd.uid | 1 + scripts/developer_pawn.gd | 86 +++++++++++ scripts/developer_pawn.gd.uid | 1 + scripts/map_canvas.gd | 22 +++ scripts/map_canvas.gd.uid | 1 + scripts/moon.gd | 19 +++ scripts/moon.gd.uid | 1 + scripts/planet.gd | 19 +++ scripts/planet.gd.uid | 1 + scripts/star.gd | 17 +++ scripts/star.gd.uid | 1 + scripts/star_system_generator.gd | 205 +++++++++++++++++++++++++++ scripts/star_system_generator.gd.uid | 1 + scripts/station.gd | 19 +++ scripts/station.gd.uid | 1 + 34 files changed, 750 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 icon.svg create mode 100644 icon.svg.import create mode 100644 main.tscn create mode 100644 project.godot create mode 100644 scenes/asteroid.tscn create mode 100644 scenes/developer_pawn.tscn create mode 100644 scenes/map_canvas.tscn create mode 100644 scenes/map_drawer.gd create mode 100644 scenes/map_drawer.gd.uid create mode 100644 scenes/moon.tscn create mode 100644 scenes/planet.tscn create mode 100644 scenes/star.tscn create mode 100644 scenes/station.tscn create mode 100644 scripts/asteroid.gd create mode 100644 scripts/asteroid.gd.uid create mode 100644 scripts/celestial_body.gd create mode 100644 scripts/celestial_body.gd.uid create mode 100644 scripts/developer_pawn.gd create mode 100644 scripts/developer_pawn.gd.uid create mode 100644 scripts/map_canvas.gd create mode 100644 scripts/map_canvas.gd.uid create mode 100644 scripts/moon.gd create mode 100644 scripts/moon.gd.uid create mode 100644 scripts/planet.gd create mode 100644 scripts/planet.gd.uid create mode 100644 scripts/star.gd create mode 100644 scripts/star.gd.uid create mode 100644 scripts/star_system_generator.gd create mode 100644 scripts/star_system_generator.gd.uid create mode 100644 scripts/station.gd create mode 100644 scripts/station.gd.uid 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