Compare commits
29 Commits
tech-test/
...
v0.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ddcbd8000 | |||
| 8968586b0f | |||
| 8f641ab36e | |||
| 9ae32ca6a9 | |||
| ae18d1456a | |||
| ab17242804 | |||
| a5dec9c2fd | |||
| e271c59837 | |||
| f8d140a9b0 | |||
| 67a4b7038a | |||
| 18f9a4fec7 | |||
| 4796a2d5ca | |||
| f8578bc3f2 | |||
| a7583637e9 | |||
| 86762d0d50 | |||
| e2da700bcd | |||
| 466dff11d0 | |||
| 636123344b | |||
| 25d9d55044 | |||
| aafb939cbf | |||
| 3d01edb2d9 | |||
| 398ec829ae | |||
| ec69ed2ee5 | |||
| 3647aa599d | |||
| 1342ca2610 | |||
| 27ce796898 | |||
| cff5ec27f8 | |||
| 245be4a4f5 | |||
| 6b9efda0d2 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@
|
|||||||
/android/
|
/android/
|
||||||
|
|
||||||
*.tmp
|
*.tmp
|
||||||
|
/export/
|
||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "godot_engine"]
|
||||||
|
path = godot_engine
|
||||||
|
url = https://codeberg.org/seedlingattempt/godot.git
|
||||||
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
## 1. Game Vision & Concept
|
## 1. Game Vision & Concept
|
||||||
|
|
||||||
Project Millimeters of Aluminum is a top-down 2D spaceship simulation game that emphasizes realistic orbital mechanics, deep ship management, and cooperative crew gameplay. Players take on roles as members of a multi-species crew aboard a modular, physically simulated spaceship.
|
Project Millimeters of Aluminum is a third-person 3D spaceship simulation game that emphasizes realistic physics, deep ship management, and cooperative crew gameplay. Players take on roles as members of a multi-species crew aboard a modular, physically simulated spaceship.
|
||||||
|
|
||||||
|
The game's aesthetic is inspired by the functional, industrial look of real-world space hardware and sci-fi like The Expanse, focusing on diegetic interfaces and detailed, functional components. The core experience is about planning and executing complex maneuvers in a hazardous, procedurally generated star system, where understanding the ship's systems is as important as piloting skill.
|
||||||
|
|
||||||
The game's aesthetic is inspired by the technical, gritty, and high-contrast 2D style of games like Barotrauma, focusing on diegetic interfaces and detailed, functional components. The core experience is about planning and executing complex maneuvers in a hazardous, procedurally generated star system, where understanding the ship's systems is as important as piloting skill.
|
The game's aesthetic is inspired by the technical, gritty, and high-contrast 2D style of games like Barotrauma, focusing on diegetic interfaces and detailed, functional components. The core experience is about planning and executing complex maneuvers in a hazardous, procedurally generated star system, where understanding the ship's systems is as important as piloting skill.
|
||||||
|
|
||||||
@ -12,26 +14,80 @@ The gameplay is centered around a Plan -> Execute -> Manage loop:
|
|||||||
|
|
||||||
1. Plan: The crew uses the Navigation Computer to analyze their orbit and plan complex maneuvers, such as a Hohmann transfer to another planet. They must account for launch windows, fuel costs, and travel time.
|
1. Plan: The crew uses the Navigation Computer to analyze their orbit and plan complex maneuvers, such as a Hohmann transfer to another planet. They must account for launch windows, fuel costs, and travel time.
|
||||||
|
|
||||||
2. Execute: The crew engages the autopilot or manually pilots the ship. The Thruster Controller executes the planned burns, performing precise, fuel-optimal rotations and main engine thrusts to alter the ship's trajectory.
|
2. Execute: The crew engages the autopilot or manually pilots the ship. The Helm executes the planned burns, performing precise, fuel-optimal rotations and main engine thrusts to alter the ship's trajectory.
|
||||||
|
|
||||||
3. Manage: While underway, the crew manages the ship's modular systems, monitors resources like fuel and power, and responds to emergent events like hull breaches or system failures.
|
3. Manage: While underway, the crew moves about the ship's 3D interior, manages modular systems, monitors resources, and responds to emergent events like hull breaches or system failures.
|
||||||
|
|
||||||
## 3. Key Features
|
|
||||||
|
### 3. Key Features
|
||||||
|
|
||||||
### 1. Procedural Star System
|
### 1. Procedural Star System
|
||||||
The game world is a procedurally generated star system created by the StarSystemGenerator. Each system features a central star, a variable number of planets, moons, and asteroid belts, creating a unique environment for each playthrough.
|
The game world is a procedurally generated star system created by the StarSystemGenerator. Each system features a central star, a variable number of planets, moons, and asteroid belts, creating a unique environment for each playthrough.
|
||||||
|
|
||||||
### 2. N-Body Physics Simulation
|
### 2. N-Body Physics Simulation
|
||||||
Major bodies in orbit (CelestialBody class) are goveerened by a simplified n-body gravity simulation. Physical objects with player interaction (ships, crew characters, detached components, and eventually stations) are governed by a realistic N-body gravitational simulation, managed by the OrbitalMechanics library.
|
|
||||||
- Objects inherit from a base OrbitalBody2D class, ensuring consistent physics.
|
Major bodies in orbit (CelestialBody class) are governed by a 3D n-body gravity simulation, managed by the OrbitalMechanics library. Objects inherit from a base OrbitalBody3D class, ensuring consistent physics. The simulation allows for complex and emergent orbital behaviors.
|
||||||
- This allows for complex and emergent orbital behaviors, such as tidal forces and stable elliptical orbits.
|
|
||||||
|
### 3. Modular Spaceship
|
||||||
|
|
||||||
|
The player's ship is not a monolithic entity but a collection of distinct, physically simulated components attached to a root Module node.
|
||||||
|
|
||||||
|
The Module class extends OrbitalBody3D and aggregates mass and inertia from all child Component and StructuralPiece nodes.
|
||||||
|
|
||||||
|
Ship logic is decentralized into data-driven "databanks," such as the HelmLogicShard and AutopilotShard.
|
||||||
|
|
||||||
|
Hardware, like a Thruster, is a 3D Component that applies force to the root Module.
|
||||||
|
|
||||||
|
### 4. Advanced Navigation Computer
|
||||||
|
|
||||||
|
This is the primary crew interface for long-range travel, presented as a diegetic 2D screen (SensorPanel) within the 3D world.
|
||||||
|
|
||||||
|
Maneuver Planning: The computer can calculate various orbital transfers, each with strategic trade-offs:
|
||||||
|
|
||||||
|
Hohmann Transfer
|
||||||
|
|
||||||
|
Brachistochrone (Torchship) Trajectory
|
||||||
|
|
||||||
|
Tactical Map: A fully interactive UI map featuring:
|
||||||
|
|
||||||
|
Zoom-to-cursor and click-and-drag panning.
|
||||||
|
|
||||||
|
Predictive orbital path drawing.
|
||||||
|
|
||||||
|
Icon culling and detailed tooltips.
|
||||||
|
|
||||||
|
### 5. Physics-Based 3D Character Control
|
||||||
|
|
||||||
|
Character control is built on a robust, physics-based 3D system designed for complex zero-G environments.
|
||||||
|
|
||||||
|
Pawn/Controller Architecture: Player control is split between a PlayerController3D (which gathers hardware input and sends it via RPC) and a CharacterPawn3D (a CharacterBody3D that acts as the physics integrator).
|
||||||
|
|
||||||
|
Modular Movement: The pawn's movement logic is handled by component "brains." The ZeroGMovementComponent manages all zero-G interaction, while the EVAMovementComponent acts as a "dumb tool" providing thruster forces.
|
||||||
|
|
||||||
|
Physics-Based Gripping: Players can grab onto designated GripArea3D nodes. This is not an animation lock; a PD controller applies forces to the player's body to move them to the grip point and align them with its orientation.
|
||||||
|
|
||||||
|
Zero-G Traversal: The ZeroGMovementComponent features a state machine for IDLE (coasting), CLIMBING (moving between grips), REACHING (pending implementation), and CHARGING_LAUNCH (pushing off surfaces).
|
||||||
|
|
||||||
|
### 6. Runtime Component Design & Engineering
|
||||||
|
|
||||||
|
(This future-facing concept remains valid from the original design)
|
||||||
|
|
||||||
|
To move beyond pre-defined ship parts, the game will feature an in-game system for players to design, prototype, and manufacture their own components. This is achieved through a "Component Blueprint" architecture that separates a component's data definition from its physical form.
|
||||||
|
|
||||||
|
Component Blueprints: A ComponentBlueprint is a Resource file (.tres) that acts as a schematic.
|
||||||
|
|
||||||
|
Generic Template Scenes: The game will use a small number of generic, unconfigured "template" scenes (e.g., generic_thruster.tscn).
|
||||||
|
|
||||||
|
The Design Lab: Players will use a dedicated SystemStation to create and modify blueprints.
|
||||||
|
|
||||||
|
Networked Construction: A global ComponentFactory on the server will instantiate and configure components based on player-chosen blueprints, which are then replicated by the MultiplayerSpawner.
|
||||||
|
|
||||||
### 3. Modular Spaceship
|
### 3. Modular Spaceship
|
||||||
|
|
||||||
The player's ship is not a monolithic entity but a collection of distinct, physically simulated components attached by joints. Key modules include:
|
The player's ship is not a monolithic entity but a collection of distinct, physically simulated components attached by joints. Key modules include:
|
||||||
|
|
||||||
- Spaceship: The main RigidBody2D hull that tracks overall mass, inertia, and health.
|
- Spaceship: The main RigidBody3D hull that tracks overall mass, inertia, and health.
|
||||||
- Thruster: Self-contained RigidBody2D components that apply their own force. Their role (main engine, RCS, etc.) is an emergent property of their placement on the hull.
|
- Thruster: Self-contained RigidBody3D components that apply their own force. Their role (main engine, RCS, etc.) is an emergent property of their placement on the hull.
|
||||||
- ThrusterController: The "brains" of the ship's movement, featuring a sophisticated autopilot that can execute fuel-optimal "bang-coast-bang" rotational maneuvers and a PD controller for stable attitude hold.
|
- ThrusterController: The "brains" of the ship's movement, featuring a sophisticated autopilot that can execute fuel-optimal "bang-coast-bang" rotational maneuvers and a PD controller for stable attitude hold.
|
||||||
- FuelSystem & LifeSupport: Centralized managers for resources and internal ship environment. Hull breaches can create thrust vectors from escaping atmosphere.
|
- FuelSystem & LifeSupport: Centralized managers for resources and internal ship environment. Hull breaches can create thrust vectors from escaping atmosphere.
|
||||||
- On-board Sensors: Diegetic components like Accelerometers allow the crew to calibrate ship performance by test-firing thrusters and measuring the true physical output.
|
- On-board Sensors: Diegetic components like Accelerometers allow the crew to calibrate ship performance by test-firing thrusters and measuring the true physical output.
|
||||||
@ -78,19 +134,17 @@ To move beyond pre-defined ship parts, the game will feature an in-game system f
|
|||||||
3. A global `ComponentFactory` singleton on the server takes the blueprint, instantiates the correct generic template scene, and applies the blueprint's property overrides to the new instance.
|
3. A global `ComponentFactory` singleton on the server takes the blueprint, instantiates the correct generic template scene, and applies the blueprint's property overrides to the new instance.
|
||||||
4. This fully-configured node is then passed to the `MultiplayerSpawner`, which replicates the object across the network, ensuring all clients see the correctly customized component.
|
4. This fully-configured node is then passed to the `MultiplayerSpawner`, which replicates the object across the network, ensuring all clients see the correctly customized component.
|
||||||
|
|
||||||
|
|
||||||
## 4. Technical Overview
|
## 4. Technical Overview
|
||||||
|
- Architecture: The project uses a decoupled, modular architecture. A GameManager handles global state, while ship systems are managed by ControlPanel and Databank resources loaded by a SystemStation.
|
||||||
- Architecture: The project uses a decoupled, modular architecture heavily reliant on a global SignalBus for inter-scene communication and a GameManager for global state. Ships feature their own local ShipSignalBus for internal component communication.
|
|
||||||
- Key Scripts:
|
- Key Scripts:
|
||||||
- OrbitalBody2D.gd: The base class for all physical objects.
|
-OrbitalBody3D.gd: The base class for all physical objects.
|
||||||
- Spaceship.gd: The central hub for a player ship.
|
- Module.gd: The central hub for a player ship, aggregating mass, inertia, and components.
|
||||||
- Thruster.gd: A self-contained, physically simulated thruster component.
|
- HelmLogicShard.gd / AutopilotShard.gd: Databanks that contain the advanced autopilot and manual control logic.
|
||||||
- ThrusterController.gd: Contains advanced autopilot and manual control logic (PD controller, bang-coast-bang maneuvers).
|
- SensorPanel.gd: A Control node that manages the interactive map UI.
|
||||||
- NavigationComputer.gd: Manages the UI and high-level maneuver planning.
|
- CharacterPawn3D.gd / ZeroGMovementComponent.gd: Manages all third-person 3D physics-based character movement.
|
||||||
- MapDrawer.gd: A Control node that manages the interactive map UI.
|
|
||||||
- MapIcon.gd: The reusable UI component for map objects.
|
|
||||||
|
|
||||||
- Art Style: Aims for a Barotraumainspired aesthetic using 2D ragdolls (Skeleton2D, PinJoint2D), detailed sprites with normal maps, and high-contrast dynamic lighting (PointLight2D, LightOccluder2D).
|
- Art Style: Aims for a functional, industrial 3D aesthetic. Character movement is physics-based using CharacterBody3D and Area3D grip detection. Ship interiors will be built from 3D modules and viewed from an over-the-shoulder camera.
|
||||||
|
|
||||||
## 5. Game Progression & Economy
|
## 5. Game Progression & Economy
|
||||||
This is the biggest area for potential expansion. A new section could detail how the player engages with the world and improves their situation over time.
|
This is the biggest area for potential expansion. A new section could detail how the player engages with the world and improves their situation over time.
|
||||||
@ -126,11 +180,12 @@ You mention "emergent events" in the gameplay loop. It would be beneficial to de
|
|||||||
|
|
||||||
## 7. Crew Interaction & Ship Interior
|
## 7. Crew Interaction & Ship Interior
|
||||||
Since co-op and crew management are central, detailing this aspect is crucial.
|
Since co-op and crew management are central, detailing this aspect is crucial.
|
||||||
|
|
||||||
### 1. Ship Interior Management:
|
### 1. Ship Interior Management:
|
||||||
- Diegetic Interfaces: You mention this in the vision. It's worth specifying how the crew will interact with systems. Will they need to be at a specific console (like the Navigation Computer) to use it? Do repairs require a character to physically be at the damaged module?
|
- Diegetic Interfaces: The crew will interact with systems from a third-person, over-the-shoulder perspective. They must be at a specific SystemStation to use its panels. Repairs will require a character to physically be at the damaged module.
|
||||||
- Atmospherics & Life Support: How is the ship's interior environment simulated? Will fires or toxic gas leaks be a possibility? This ties directly into your LifeSupport system.
|
- Atmospherics & Life Support: How is the ship's interior environment simulated? This will tie into the LifeSupport system.
|
||||||
|
|
||||||
### 2. Character States:
|
### 2. Character States:
|
||||||
- Health & Injury: How are characters affected by hazards? Can they be injured in high-G maneuvers or from system failures?
|
- Health & Injury: How are characters affected by hazards? Can they be injured in high-G maneuvers or from system failures?
|
||||||
- EVA (Extra-Vehicular Activity): Detail the mechanics for EVAs. What equipment is needed? How is movement handled in zero-G? This would be a perfect role for the "Hard Vacuum Monster" species.
|
- EVA (Extra-Vehicular Activity): This is a core feature. The EVAMovementComponent provides force-based thruster control for linear movement and roll torque. The ZeroGMovementComponent manages gripping, climbing, and launching from the ship's exterior and interior surfaces.
|
||||||
|
- Movement for the "Hard Vacuum Monster" species can be refined from a version of the reaching component where it can grab any nearby surface and can generate enough suction strength to remain attached to a moving object.
|
||||||
|
|||||||
96
README.md
Normal file
96
README.md
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
# Project Millimeters of Aluminum
|
||||||
|
|
||||||
|
A space simulation game built on a custom fork of the Godot Engine (4.x) with 64-bit double-precision physics enabled.
|
||||||
|
|
||||||
|
## 📋 Prerequisites
|
||||||
|
|
||||||
|
Before compiling the engine, ensure you have the following installed on your system.
|
||||||
|
|
||||||
|
### 1. Python & SCons
|
||||||
|
The Godot build system relies on SCons, which is written in Python.
|
||||||
|
* **Install Python (3.6+):** [Download Here](https://www.python.org/downloads/)
|
||||||
|
* *Windows Users:* Ensure "Add Python to PATH" is checked during installation. [Check this stackoverflow answer](https://stackoverflow.com/questions/57421669/question-about-pip-using-python-from-windows-store).
|
||||||
|
|
||||||
|
* **Install SCons:** Open your terminal/command prompt and run:
|
||||||
|
```bash
|
||||||
|
pip install scons
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. C++ Compiler
|
||||||
|
Godot requires a C++ compiler to build from source.
|
||||||
|
|
||||||
|
* **Windows:**
|
||||||
|
* Install **Visual Studio Community** (2019 or later).
|
||||||
|
* During installation, select the **"Desktop development with C++"** workload.
|
||||||
|
* **Linux:**
|
||||||
|
* Install GCC or Clang.
|
||||||
|
* *Debian/Ubuntu:* `sudo apt-get install build-essential pkg-config libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev`
|
||||||
|
* **macOS:**
|
||||||
|
* Install **Xcode** from the App Store.
|
||||||
|
* Run `xcode-select --install` in the terminal.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Setup & Compilation
|
||||||
|
|
||||||
|
This project uses a custom engine build to support solar-system scale coordinates (Double Precision). You **cannot** use the standard Steam or website version of Godot to open this project.
|
||||||
|
|
||||||
|
### 1. Clone the Repository
|
||||||
|
Clone the repository with the `--recursive` flag to automatically pull the engine source code submodule.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --recursive [https://codeberg.org/YOUR_USERNAME/ProjectMillimetersOfAluminum.git](https://codeberg.org/YOUR_USERNAME/ProjectMillimetersOfAluminum.git)
|
||||||
|
cd ProjectMillimetersOfAluminum
|
||||||
|
```
|
||||||
|
|
||||||
|
_If you have already cloned without recursive, run:_
|
||||||
|
|
||||||
|
```
|
||||||
|
git submodule update --init --recursive
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Configure Engine Ignore (Optional but Recommended)
|
||||||
|
To prevent your Editor from trying to import the thousands of raw assets inside the engine source folder:
|
||||||
|
1. Navigate to `godot_engine/`.
|
||||||
|
2. Create a new empty file named `.gdignore`.
|
||||||
|
3. Compile the Engine
|
||||||
|
|
||||||
|
Run the build command for your platform from the godot_engine/ directory.
|
||||||
|
|
||||||
|
**Windows:**
|
||||||
|
```Bash
|
||||||
|
cd godot_engine
|
||||||
|
scons platform=windows target=editor precision=double arch=x86_64
|
||||||
|
```
|
||||||
|
|
||||||
|
**Linux:**
|
||||||
|
```Bash
|
||||||
|
cd godot_engine
|
||||||
|
scons platform=linuxbsd target=editor precision=double arch=x86_64
|
||||||
|
```
|
||||||
|
|
||||||
|
**macOS:**
|
||||||
|
```Bash
|
||||||
|
cd godot_engine
|
||||||
|
scons platform=macos target=editor precision=double arch=x86_64
|
||||||
|
```
|
||||||
|
_Note: (-j6 flag tells the compiler to use 6 CPU cores. Adjust this number based on your hardware to speed up compilation. Not using the flag will use all available cores)_
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Running the Project
|
||||||
|
|
||||||
|
Once compilation is complete (usually 10-30 minutes), the executable will be located in godot_engine/bin/.
|
||||||
|
|
||||||
|
Do not open the project with standard Godot.
|
||||||
|
|
||||||
|
Navigate to `godot_engine/bin/`.
|
||||||
|
|
||||||
|
Run the binary ending in `.double.x86_64` (e.g., `godot.windows.editor.double.x86_64.exe`).
|
||||||
|
|
||||||
|
Import and open the `project.godot` file located in the root `ProjectMillimetersOfAluminum` folder.
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
"No valid compilers found" (Windows): Ensure you installed the C++ Desktop Development workload in the Visual Studio Installer. Just the editor is not enough.
|
||||||
|
|
||||||
|
Jittering Objects: If objects jitter at large distances, ensure you are running the double precision binary and not a standard build.
|
||||||
@ -1,6 +0,0 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://bm1rbv4tuppbc"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://d4jka2etva22s" path="res://scenes/tests/3d/eva_movement_component.gd" id="1_mb22m"]
|
|
||||||
|
|
||||||
[node name="EVASuitController" type="Node3D"]
|
|
||||||
script = ExtResource("1_mb22m")
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://dogqi2c58qdc0"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://bkcouefvi7iup" path="res://scripts/star_system.gd" id="1_ig7tw"]
|
|
||||||
|
|
||||||
[node name="StarSystem" type="Node2D"]
|
|
||||||
script = ExtResource("1_ig7tw")
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
[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("..")
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://b1kpyek60vyof"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://6co67nfy8ngb" path="res://scenes/ship/builder/module.gd" id="1_1abiy"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://bho8x10x4oab7" path="res://scenes/ship/builder/pieces/hullplate.tscn" id="2_risxe"]
|
|
||||||
|
|
||||||
[node name="Module" type="RigidBody2D"]
|
|
||||||
position = Vector2(-50, 50)
|
|
||||||
mass = null
|
|
||||||
center_of_mass_mode = 1
|
|
||||||
center_of_mass = Vector2(-50, 0)
|
|
||||||
inertia = null
|
|
||||||
linear_velocity = null
|
|
||||||
angular_velocity = null
|
|
||||||
script = ExtResource("1_1abiy")
|
|
||||||
base_mass = null
|
|
||||||
inertia = null
|
|
||||||
|
|
||||||
[node name="StructuralContainer" type="Node2D" parent="."]
|
|
||||||
|
|
||||||
[node name="Hullplate" parent="StructuralContainer" instance=ExtResource("2_risxe")]
|
|
||||||
base_mass = null
|
|
||||||
inertia = null
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@23989" parent="StructuralContainer" instance=ExtResource("2_risxe")]
|
|
||||||
position = Vector2(-100, 0)
|
|
||||||
base_mass = null
|
|
||||||
inertia = null
|
|
||||||
|
|
||||||
[node name="HullVolumeContainer" type="Node2D" parent="."]
|
|
||||||
|
|
||||||
[node name="AtmosphereVisualizer" type="Node2D" parent="."]
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://baeikwxkh26fh"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://6co67nfy8ngb" path="res://scenes/ship/builder/module.gd" id="1_1rae4"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://bho8x10x4oab7" path="res://scenes/ship/builder/pieces/hullplate.tscn" id="2_fbnt1"]
|
|
||||||
|
|
||||||
[node name="Module" type="RigidBody2D"]
|
|
||||||
position = Vector2(-50, 50)
|
|
||||||
mass = null
|
|
||||||
center_of_mass_mode = 1
|
|
||||||
center_of_mass = Vector2(-50, 0)
|
|
||||||
inertia = null
|
|
||||||
linear_velocity = null
|
|
||||||
angular_velocity = null
|
|
||||||
script = ExtResource("1_1rae4")
|
|
||||||
base_mass = null
|
|
||||||
inertia = null
|
|
||||||
|
|
||||||
[node name="StructuralContainer" type="Node2D" parent="."]
|
|
||||||
|
|
||||||
[node name="Hullplate" parent="StructuralContainer" instance=ExtResource("2_fbnt1")]
|
|
||||||
base_mass = null
|
|
||||||
inertia = null
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@23989" parent="StructuralContainer" instance=ExtResource("2_fbnt1")]
|
|
||||||
position = Vector2(-100, 0)
|
|
||||||
base_mass = null
|
|
||||||
inertia = null
|
|
||||||
|
|
||||||
[node name="HullVolumeContainer" type="Node2D" parent="."]
|
|
||||||
|
|
||||||
[node name="AtmosphereVisualizer" type="Node2D" parent="."]
|
|
||||||
@ -1,145 +0,0 @@
|
|||||||
[gd_scene load_steps=20 format=3 uid="uid://didt2nsdtbmra"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://6co67nfy8ngb" path="res://scenes/ship/builder/module.gd" id="1_nqe0s"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://bho8x10x4oab7" path="res://scenes/ship/builder/pieces/hullplate.tscn" id="2_foqop"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://d3hitk62fice4" path="res://scenes/ship/builder/pieces/bulkhead.tscn" id="4_dmrms"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://2n42nstcj1n0" path="res://scenes/ship/components/hardware/system_station.tscn" id="5_nqe0s"]
|
|
||||||
[ext_resource type="Script" uid="uid://diu2tgusi3vmt" path="res://scenes/ship/computer/shards/sensor_databank.gd" id="9_ixntg"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dt1t2n7dewucw" path="res://scenes/ship/computer/UI/button_panel.tscn" id="10_px2ne"]
|
|
||||||
[ext_resource type="Script" uid="uid://cfbyqvnvf3hna" path="res://scenes/ship/computer/shards/helm_logic_databank.gd" id="10_wkxbw"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://cdbqjkgsj02or" path="res://scenes/ship/computer/UI/readout_screen_panel.tscn" id="11_erhv3"]
|
|
||||||
[ext_resource type="Script" uid="uid://t12etsdx2h38" path="res://scenes/ship/computer/shards/nav_selection_databank.gd" id="11_xwy4s"]
|
|
||||||
[ext_resource type="Script" uid="uid://ceqdi6jobefnc" path="res://scenes/ship/computer/shards/helm_autopilot_databank.gd" id="12_4epkn"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://rd1c22nsru8y" path="res://scenes/ship/computer/UI/sensor_panel.tscn" id="12_q1rtr"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://c0bb77rmyatr0" path="res://scenes/ship/components/hardware/thruster.tscn" id="12_vmx8o"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dvpy3urgtm62n" path="res://scenes/ship/components/hardware/spawner.tscn" id="13_83bu1"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://pq55j75t3fda" path="res://scenes/ship/computer/UI/throttle_lever_panel.tscn" id="13_rsa1x"]
|
|
||||||
[ext_resource type="Script" uid="uid://ctgl5kxyagw0f" path="res://scenes/ship/computer/shards/helm_ship_status.gd" id="13_wkxbw"]
|
|
||||||
[ext_resource type="Script" uid="uid://ghluwjd5c5ul" path="res://scenes/ship/computer/shards/nav_brachistochrone_planner.gd" id="14_xwy4s"]
|
|
||||||
[ext_resource type="Script" uid="uid://bghu5lhcbcfmh" path="res://scenes/ship/computer/shards/nav_hohman_planner.gd" id="15_fll2s"]
|
|
||||||
[ext_resource type="Script" uid="uid://dsbn7ushwqrko" path="res://scenes/ship/computer/shards/nav_intercept_solver.gd" id="16_vufgi"]
|
|
||||||
[ext_resource type="Script" uid="uid://0f6v6iu3o5qo" path="res://scenes/ship/computer/shards/nav_projection_shard.gd" id="17_34v0b"]
|
|
||||||
|
|
||||||
[node name="Module" type="Node2D"]
|
|
||||||
physics_interpolation_mode = 2
|
|
||||||
script = ExtResource("1_nqe0s")
|
|
||||||
physics_mode = 1
|
|
||||||
mass = 1.0
|
|
||||||
inertia = 0.0
|
|
||||||
metadata/_custom_type_script = "uid://0isnsk356que"
|
|
||||||
|
|
||||||
[node name="Hullplate" parent="." instance=ExtResource("2_foqop")]
|
|
||||||
physics_interpolation_mode = 2
|
|
||||||
is_pressurized = false
|
|
||||||
base_mass = 0.0
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@30634" parent="." instance=ExtResource("2_foqop")]
|
|
||||||
physics_interpolation_mode = 2
|
|
||||||
position = Vector2(0, 100)
|
|
||||||
is_pressurized = false
|
|
||||||
health = 0.0
|
|
||||||
base_mass = 0.0
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@30635" parent="." instance=ExtResource("2_foqop")]
|
|
||||||
physics_interpolation_mode = 2
|
|
||||||
position = Vector2(0, -100)
|
|
||||||
is_pressurized = false
|
|
||||||
health = 0.0
|
|
||||||
base_mass = 0.0
|
|
||||||
|
|
||||||
[node name="Bulkhead" parent="." instance=ExtResource("4_dmrms")]
|
|
||||||
physics_interpolation_mode = 2
|
|
||||||
position = Vector2(-50, 100)
|
|
||||||
is_pressurized = false
|
|
||||||
health = 0.0
|
|
||||||
base_mass = 0.0
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@30636" parent="." instance=ExtResource("4_dmrms")]
|
|
||||||
physics_interpolation_mode = 2
|
|
||||||
position = Vector2(-50, 0)
|
|
||||||
is_pressurized = false
|
|
||||||
health = 0.0
|
|
||||||
base_mass = 0.0
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@30637" parent="." instance=ExtResource("4_dmrms")]
|
|
||||||
physics_interpolation_mode = 2
|
|
||||||
position = Vector2(-50, -100)
|
|
||||||
is_pressurized = false
|
|
||||||
health = 0.0
|
|
||||||
base_mass = 0.0
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@30638" parent="." instance=ExtResource("4_dmrms")]
|
|
||||||
physics_interpolation_mode = 2
|
|
||||||
position = Vector2(50, -100)
|
|
||||||
is_pressurized = false
|
|
||||||
health = 0.0
|
|
||||||
base_mass = 0.0
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@30639" parent="." instance=ExtResource("4_dmrms")]
|
|
||||||
physics_interpolation_mode = 2
|
|
||||||
position = Vector2(0, -150)
|
|
||||||
rotation = 1.5708
|
|
||||||
is_pressurized = false
|
|
||||||
health = 0.0
|
|
||||||
base_mass = 0.0
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@30640" parent="." instance=ExtResource("4_dmrms")]
|
|
||||||
physics_interpolation_mode = 2
|
|
||||||
position = Vector2(0, 150)
|
|
||||||
rotation = 4.71239
|
|
||||||
is_pressurized = false
|
|
||||||
health = 0.0
|
|
||||||
base_mass = 0.0
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@30641" parent="." instance=ExtResource("4_dmrms")]
|
|
||||||
physics_interpolation_mode = 2
|
|
||||||
position = Vector2(50, 100)
|
|
||||||
is_pressurized = false
|
|
||||||
health = 0.0
|
|
||||||
base_mass = 0.0
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@30642" parent="." instance=ExtResource("4_dmrms")]
|
|
||||||
physics_interpolation_mode = 2
|
|
||||||
position = Vector2(50, 0)
|
|
||||||
is_pressurized = false
|
|
||||||
health = 0.0
|
|
||||||
base_mass = 0.0
|
|
||||||
|
|
||||||
[node name="Station" parent="." instance=ExtResource("5_nqe0s")]
|
|
||||||
position = Vector2(0, -10)
|
|
||||||
panel_scenes = Array[PackedScene]([ExtResource("11_erhv3"), ExtResource("11_erhv3"), ExtResource("12_q1rtr"), ExtResource("10_px2ne"), ExtResource("13_rsa1x")])
|
|
||||||
databank_installations = Array[Script]([ExtResource("10_wkxbw"), ExtResource("12_4epkn"), ExtResource("13_wkxbw"), ExtResource("9_ixntg"), ExtResource("11_xwy4s"), ExtResource("14_xwy4s"), ExtResource("15_fll2s"), ExtResource("16_vufgi"), ExtResource("17_34v0b")])
|
|
||||||
physics_mode = 2
|
|
||||||
|
|
||||||
[node name="Thruster" parent="." instance=ExtResource("12_vmx8o")]
|
|
||||||
position = Vector2(-95, -130)
|
|
||||||
rotation = 1.5708
|
|
||||||
main_thruster = false
|
|
||||||
physics_mode = 2
|
|
||||||
|
|
||||||
[node name="Thruster2" parent="." instance=ExtResource("12_vmx8o")]
|
|
||||||
position = Vector2(-95, 130)
|
|
||||||
rotation = 1.5708
|
|
||||||
main_thruster = false
|
|
||||||
physics_mode = 2
|
|
||||||
|
|
||||||
[node name="Thruster3" parent="." instance=ExtResource("12_vmx8o")]
|
|
||||||
position = Vector2(95, 130)
|
|
||||||
rotation = -1.5708
|
|
||||||
main_thruster = false
|
|
||||||
physics_mode = 2
|
|
||||||
|
|
||||||
[node name="Thruster4" parent="." instance=ExtResource("12_vmx8o")]
|
|
||||||
position = Vector2(95, -130)
|
|
||||||
rotation = -1.5708
|
|
||||||
main_thruster = false
|
|
||||||
physics_mode = 2
|
|
||||||
|
|
||||||
[node name="MainEngine" parent="." instance=ExtResource("12_vmx8o")]
|
|
||||||
position = Vector2(0, 195)
|
|
||||||
max_thrust = 10.0
|
|
||||||
physics_mode = 2
|
|
||||||
|
|
||||||
[node name="Spawner" parent="." instance=ExtResource("13_83bu1")]
|
|
||||||
position = Vector2(0, 27)
|
|
||||||
physics_mode = 2
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
class_name Asteroid
|
|
||||||
extends OrbitalBody2D
|
|
||||||
|
|
||||||
# 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 +0,0 @@
|
|||||||
uid://c816xae77cbmq
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://bawsujtlpmh5r"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://0isnsk356que" path="res://scripts/orbital_body_2d.gd" id="1_4q05e"]
|
|
||||||
|
|
||||||
[node name="Asteroid" type="Node2D"]
|
|
||||||
script = ExtResource("1_4q05e")
|
|
||||||
base_mass = 50000.0
|
|
||||||
metadata/_custom_type_script = "uid://0isnsk356que"
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
class_name Moon
|
|
||||||
extends OrbitalBody2D
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
# You can set a default texture here.
|
|
||||||
# texture = preload("res://assets/moon_texture.png")
|
|
||||||
|
|
||||||
super._ready()
|
|
||||||
@ -1 +0,0 @@
|
|||||||
uid://b1xsx7er22nxn
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://74ppvxcw8an4"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://b1xsx7er22nxn" path="res://scenes/celestial_bodies/moon.gd" id="1_530pw"]
|
|
||||||
|
|
||||||
[node name="Moon" type="Node2D"]
|
|
||||||
script = ExtResource("1_530pw")
|
|
||||||
base_mass = 1e+06
|
|
||||||
metadata/_custom_type_script = "uid://0isnsk356que"
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
class_name Planet
|
|
||||||
extends OrbitalBody2D
|
|
||||||
|
|
||||||
# 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:
|
|
||||||
# You can set a default texture here.
|
|
||||||
# texture = preload("res://assets/planet_texture.png")
|
|
||||||
|
|
||||||
super._ready()
|
|
||||||
@ -1 +0,0 @@
|
|||||||
uid://5f6ipgu65urb
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://clt4qlsjcfgln"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://5f6ipgu65urb" path="res://scenes/celestial_bodies/planet.gd" id="1_cktii"]
|
|
||||||
|
|
||||||
[node name="Planet" type="Node2D"]
|
|
||||||
script = ExtResource("1_cktii")
|
|
||||||
base_mass = 2.5e+07
|
|
||||||
metadata/_custom_type_script = "uid://0isnsk356que"
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
class_name Star
|
|
||||||
extends OrbitalBody2D
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
# You can set a default texture here, or assign it in the Inspector.
|
|
||||||
# texture = preload("res://assets/star_texture.png")
|
|
||||||
|
|
||||||
super._ready()
|
|
||||||
@ -1 +0,0 @@
|
|||||||
uid://um2sfghmii42
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://5uqp4amjj7ww"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://um2sfghmii42" path="res://scenes/celestial_bodies/star.gd" id="1_mcqwg"]
|
|
||||||
|
|
||||||
[sub_resource type="CircleShape2D" id="CircleShape2D_508pf"]
|
|
||||||
radius = 200.0
|
|
||||||
|
|
||||||
[node name="Star" type="Node2D"]
|
|
||||||
script = ExtResource("1_mcqwg")
|
|
||||||
base_mass = 5e+08
|
|
||||||
metadata/_custom_type_script = "uid://0isnsk356que"
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
|
||||||
shape = SubResource("CircleShape2D_508pf")
|
|
||||||
debug_color = Color(0.863865, 0.471779, 0.162305, 1)
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
class_name Station
|
|
||||||
extends OrbitalBody2D
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
# You can set a default texture here.
|
|
||||||
# texture = preload("res://assets/station_texture.png")
|
|
||||||
|
|
||||||
super._ready()
|
|
||||||
@ -1 +0,0 @@
|
|||||||
uid://ulw61oxppwdu
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://dm3s33o4xhqfv"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://ulw61oxppwdu" path="res://scenes/celestial_bodies/station.gd" id="1_rod8h"]
|
|
||||||
|
|
||||||
[node name="Station" type="Node2D"]
|
|
||||||
script = ExtResource("1_rod8h")
|
|
||||||
base_mass = 5000.0
|
|
||||||
metadata/_custom_type_script = "uid://0isnsk356que"
|
|
||||||
@ -1,205 +0,0 @@
|
|||||||
extends CharacterBody2D
|
|
||||||
class_name PilotBall
|
|
||||||
|
|
||||||
# --- Movement Constants (Friction Simulation) ---
|
|
||||||
# When in open space (no module overlap), movement is zeroed out quickly.
|
|
||||||
const EXTERIOR_DRAG_FACTOR: float = 0.05
|
|
||||||
|
|
||||||
# When pushing off hullplates (low friction, slow acceleration)
|
|
||||||
const INTERIOR_SLUGGISH_SPEED: float = 100.0
|
|
||||||
const INTERIOR_SLUGGISH_ACCEL: float = 5 # Low acceleration, simulating mass and small push
|
|
||||||
|
|
||||||
# When gripping a ladder (high friction, direct control)
|
|
||||||
const LADDER_SPEED: float = 100.0
|
|
||||||
const LADDER_ACCEL: float = 20 # High acceleration, simulating direct grip
|
|
||||||
|
|
||||||
@onready var camera: Camera2D = $Camera2D
|
|
||||||
@onready var overlap_area: Area2D = $OverlapDetector
|
|
||||||
@onready var ui_container: Control = $CanvasLayer/UIContainer
|
|
||||||
|
|
||||||
var nearby_station: SystemStation = null
|
|
||||||
var current_station: SystemStation = null
|
|
||||||
|
|
||||||
# --- State Variables ---
|
|
||||||
enum MovementState {
|
|
||||||
NO_CONTROL,
|
|
||||||
ZERO_G_INTERIOR,
|
|
||||||
LADDER_GRIP,
|
|
||||||
IN_STATION
|
|
||||||
}
|
|
||||||
|
|
||||||
var current_state: MovementState = MovementState.NO_CONTROL
|
|
||||||
var ladder_area: Area2D = null # Area of the ladder currently overlapped
|
|
||||||
var is_grabbing_ladder: bool = false # True if 'Space' is held while on ladder
|
|
||||||
|
|
||||||
# --- Overlap Detection (Assuming you use Area2D for detection) ---
|
|
||||||
var overlapping_modules: int = 0
|
|
||||||
|
|
||||||
# --- Ladder Constants ---
|
|
||||||
const LAUNCH_VELOCITY: float = 300.0
|
|
||||||
|
|
||||||
var _movement_input: Vector2 = Vector2.ZERO
|
|
||||||
var _interact_just_pressed: bool = false
|
|
||||||
var _interact_held: bool = false
|
|
||||||
|
|
||||||
# --- PUBLIC INPUT METHODS (Called by the PlayerController) ---
|
|
||||||
func set_movement_input(input_dir: Vector2):
|
|
||||||
_movement_input = input_dir
|
|
||||||
|
|
||||||
func set_interaction_input(just_pressed: bool, is_held: bool):
|
|
||||||
_interact_just_pressed = just_pressed
|
|
||||||
_interact_held = is_held
|
|
||||||
|
|
||||||
# --- New: Physics Initialization (Assuming CharacterBody2D is parented to the scene root or Ship) ---
|
|
||||||
# NOTE: CharacterBody2D cannot inherit OrbitalBody2D, so we manage its velocity manually.
|
|
||||||
|
|
||||||
func _ready():
|
|
||||||
# Set up overlap signals if they aren't already connected in the scene file
|
|
||||||
# You must have an Area2D child on PilotBall to detect overlaps.
|
|
||||||
overlap_area.body_entered.connect(on_body_entered)
|
|
||||||
overlap_area.body_exited.connect(on_body_exited)
|
|
||||||
overlap_area.area_entered.connect(_on_station_area_entered)
|
|
||||||
overlap_area.area_exited.connect(_on_station_area_exited)
|
|
||||||
|
|
||||||
camera.make_current()
|
|
||||||
|
|
||||||
func on_body_entered(body: Node2D):
|
|
||||||
# Detect Modules (which all inherit OrbitalBody2D via StructuralPiece)
|
|
||||||
if body is StructuralPiece:
|
|
||||||
overlapping_modules += 1
|
|
||||||
|
|
||||||
# Detect Ladders
|
|
||||||
if body is Ladder:
|
|
||||||
ladder_area = body.find_child("ClimbArea") # Assuming the Ladder has a specific Area2D for climbing
|
|
||||||
|
|
||||||
func on_body_exited(body: Node2D):
|
|
||||||
if body is StructuralPiece:
|
|
||||||
overlapping_modules -= 1
|
|
||||||
|
|
||||||
if body is Ladder:
|
|
||||||
if body.find_child("ClimbArea") == ladder_area:
|
|
||||||
ladder_area = null
|
|
||||||
is_grabbing_ladder = false # Force detach if the ladder moves away
|
|
||||||
|
|
||||||
# --- NEW: Functions to be called by the Station ---
|
|
||||||
func enter_station_state():
|
|
||||||
current_state = MovementState.IN_STATION
|
|
||||||
velocity = Vector2.ZERO # FIX: Stop all movement when entering a station
|
|
||||||
|
|
||||||
func exit_station_state():
|
|
||||||
# When leaving, transition to a sensible default state.
|
|
||||||
current_state = MovementState.ZERO_G_INTERIOR
|
|
||||||
|
|
||||||
func _physics_process(delta):
|
|
||||||
# This script now runs on the server and its state is synced to clients.
|
|
||||||
# It no longer checks for local input authority.
|
|
||||||
if current_state == MovementState.IN_STATION:
|
|
||||||
move_and_slide()
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
_update_movement_state() # This function now uses the new variables
|
|
||||||
process_interaction() # Process any interaction presses
|
|
||||||
|
|
||||||
# Reset input flags for the next frame
|
|
||||||
_interact_just_pressed = false
|
|
||||||
_interact_held = false
|
|
||||||
# The 'input_dir' now comes from our variable, not the Input singleton.
|
|
||||||
var input_dir = _movement_input
|
|
||||||
|
|
||||||
match current_state:
|
|
||||||
MovementState.ZERO_G_INTERIOR:
|
|
||||||
_sluggish_movement(input_dir, delta)
|
|
||||||
MovementState.LADDER_GRIP:
|
|
||||||
_ladder_movement(input_dir, delta)
|
|
||||||
|
|
||||||
# Reset input for the next frame
|
|
||||||
_movement_input = Vector2.ZERO
|
|
||||||
|
|
||||||
move_and_slide()
|
|
||||||
|
|
||||||
# This function is called every physics frame by _physics_process().
|
|
||||||
func process_interaction():
|
|
||||||
# If the interact button was not pressed this frame, do nothing.
|
|
||||||
if not _interact_just_pressed:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Priority 1: Disengage from a station if we are in one.
|
|
||||||
if current_station:
|
|
||||||
current_station.disengage(self)
|
|
||||||
current_station = null
|
|
||||||
return
|
|
||||||
# Priority 2: Occupy a nearby station if we are not in one.
|
|
||||||
elif is_instance_valid(nearby_station):
|
|
||||||
current_station = nearby_station
|
|
||||||
current_station.occupy(self)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Priority 3: Handle ladder launch logic.
|
|
||||||
# This part of the old logic was in _handle_interaction_input,
|
|
||||||
# but it's cleaner to check for the release of the button here.
|
|
||||||
if current_state == MovementState.LADDER_GRIP and not _interact_held:
|
|
||||||
# Launch the player away from the ladder when the interact button is released.
|
|
||||||
var launch_direction = - _movement_input.normalized()
|
|
||||||
if launch_direction == Vector2.ZERO:
|
|
||||||
# Default launch: use the character's forward direction
|
|
||||||
launch_direction = Vector2.UP.rotated(rotation)
|
|
||||||
|
|
||||||
velocity = launch_direction * LAUNCH_VELOCITY
|
|
||||||
|
|
||||||
# Immediately switch to zero-G interior state
|
|
||||||
is_grabbing_ladder = false
|
|
||||||
current_state = MovementState.ZERO_G_INTERIOR
|
|
||||||
|
|
||||||
# --- State Machine Update ---
|
|
||||||
|
|
||||||
func _update_movement_state():
|
|
||||||
# Priority 1: Ladder Grip
|
|
||||||
# This now checks the variable instead of the Input singleton.
|
|
||||||
if ladder_area and _interact_held:
|
|
||||||
is_grabbing_ladder = true
|
|
||||||
current_state = MovementState.LADDER_GRIP
|
|
||||||
return
|
|
||||||
|
|
||||||
# Priority 2: Interior Zero-G (must overlap a module/piece AND not be grabbing)
|
|
||||||
if overlapping_modules > 0:
|
|
||||||
if is_grabbing_ladder:
|
|
||||||
# If we were grabbing a ladder but released 'interact', we transition to zero-G interior
|
|
||||||
is_grabbing_ladder = false
|
|
||||||
current_state = MovementState.ZERO_G_INTERIOR
|
|
||||||
return
|
|
||||||
|
|
||||||
current_state = MovementState.ZERO_G_INTERIOR
|
|
||||||
return
|
|
||||||
|
|
||||||
# Priority 3: No Control (floating free)
|
|
||||||
is_grabbing_ladder = false
|
|
||||||
current_state = MovementState.NO_CONTROL
|
|
||||||
|
|
||||||
|
|
||||||
# --- Movement Implementations ---
|
|
||||||
|
|
||||||
func _sluggish_movement(input_dir: Vector2, delta: float):
|
|
||||||
# Simulates pushing off the wall: slow acceleration, but minimal drag
|
|
||||||
var target_velocity = input_dir * INTERIOR_SLUGGISH_ACCEL
|
|
||||||
velocity = velocity + target_velocity * delta
|
|
||||||
#velocity.lerp(velocity + interi, INTERIOR_SLUGGISH_ACCEL)
|
|
||||||
|
|
||||||
func _ladder_movement(input_dir: Vector2, delta: float):
|
|
||||||
# Simulates direct grip: fast acceleration, perfect control
|
|
||||||
var target_velocity = input_dir * LADDER_SPEED
|
|
||||||
velocity = velocity.lerp(target_velocity, LADDER_ACCEL * delta)
|
|
||||||
|
|
||||||
# --- New Functions for Station Interaction ---
|
|
||||||
func _on_station_area_entered(area: Area2D):
|
|
||||||
if area.get_parent() is SystemStation:
|
|
||||||
nearby_station = area.get_parent()
|
|
||||||
print("Near station: ", nearby_station.name)
|
|
||||||
|
|
||||||
func _on_station_area_exited(area: Area2D):
|
|
||||||
if area.get_parent() == nearby_station:
|
|
||||||
nearby_station = null
|
|
||||||
|
|
||||||
# Stations will call this to get the node where they should place their UIs.
|
|
||||||
func get_ui_container() -> Control:
|
|
||||||
return ui_container
|
|
||||||
@ -1 +0,0 @@
|
|||||||
uid://dxngvoommn5f1
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
[gd_scene load_steps=4 format=3 uid="uid://chgycmkkaf7jv"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://dxngvoommn5f1" path="res://scenes/characters/pilot_ball.gd" id="1_rhbna"]
|
|
||||||
|
|
||||||
[sub_resource type="CircleShape2D" id="CircleShape2D_6jclb"]
|
|
||||||
|
|
||||||
[sub_resource type="CircleShape2D" id="CircleShape2D_rhbna"]
|
|
||||||
|
|
||||||
[node name="PilotBall" type="CharacterBody2D"]
|
|
||||||
collision_layer = 32
|
|
||||||
collision_mask = 16
|
|
||||||
script = ExtResource("1_rhbna")
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
|
||||||
shape = SubResource("CircleShape2D_6jclb")
|
|
||||||
debug_color = Color(0.61528, 0.358023, 1, 1)
|
|
||||||
|
|
||||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
|
||||||
|
|
||||||
[node name="Camera2D" type="Camera2D" parent="."]
|
|
||||||
zoom = Vector2(4, 4)
|
|
||||||
|
|
||||||
[node name="OverlapDetector" type="Area2D" parent="."]
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="OverlapDetector"]
|
|
||||||
shape = SubResource("CircleShape2D_rhbna")
|
|
||||||
|
|
||||||
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
|
||||||
|
|
||||||
[node name="UIContainer" type="Control" parent="CanvasLayer"]
|
|
||||||
layout_mode = 3
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
extends Node
|
|
||||||
|
|
||||||
class_name PlayerController
|
|
||||||
|
|
||||||
# TODO: Change this to custom pawn type
|
|
||||||
var possessed_pawn: Node # The character this controller is currently driving
|
|
||||||
|
|
||||||
func _ready():
|
|
||||||
# --- FIX: Manually enable input processing for this node ---
|
|
||||||
set_process_input(true)
|
|
||||||
|
|
||||||
func _physics_process (delta):
|
|
||||||
if not is_multiplayer_authority():
|
|
||||||
return
|
|
||||||
|
|
||||||
# 1. Gather all input states for this frame.
|
|
||||||
var input_dir = Input.get_vector("move_left", "move_right", "move_up", "move_down")
|
|
||||||
var is_interact_just_pressed = Input.is_action_just_pressed("interact")
|
|
||||||
var is_interact_held = Input.is_action_pressed("interact")
|
|
||||||
#print(is_interact_just_pressed)
|
|
||||||
#print(input_dir)
|
|
||||||
# 2. Send the collected input state to the server via RPC.
|
|
||||||
server_process_input.rpc_id(1, input_dir, is_interact_just_pressed, is_interact_held)
|
|
||||||
|
|
||||||
|
|
||||||
@rpc("any_peer", "call_local")
|
|
||||||
func server_process_input(input_dir: Vector2, is_interact_just_pressed: bool, is_interact_held: bool):
|
|
||||||
if is_instance_valid(possessed_pawn):
|
|
||||||
possessed_pawn.set_movement_input(input_dir)
|
|
||||||
# Pass both interact states to the pawn
|
|
||||||
possessed_pawn.set_interaction_input(is_interact_just_pressed, is_interact_held)
|
|
||||||
|
|
||||||
func possess(pawn_to_control: Node):
|
|
||||||
possessed_pawn = pawn_to_control
|
|
||||||
reparent(pawn_to_control, false)
|
|
||||||
self.owner = pawn_to_control
|
|
||||||
print("PlayerController possessed: ", possessed_pawn.name)
|
|
||||||
@ -1 +0,0 @@
|
|||||||
uid://dmhwqmbwk0t8k
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://dnre6svquwdtb"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://dmhwqmbwk0t8k" path="res://scenes/characters/player_controller.gd" id="1_b8jga"]
|
|
||||||
|
|
||||||
[node name="PlayerController" type="Node"]
|
|
||||||
script = ExtResource("1_b8jga")
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
[gd_scene load_steps=4 format=3 uid="uid://c77wxeb7gpplw"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://6co67nfy8ngb" path="res://scenes/ship/builder/module.gd" id="1_mtskc"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://bho8x10x4oab7" path="res://scenes/ship/builder/pieces/hullplate.tscn" id="2_aovrk"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://d3hitk62fice4" path="res://scenes/ship/builder/pieces/bulkhead.tscn" id="4_dwgsg"]
|
|
||||||
|
|
||||||
[node name="Module" type="Node2D"]
|
|
||||||
position = Vector2(-50, 50)
|
|
||||||
script = ExtResource("1_mtskc")
|
|
||||||
metadata/_custom_type_script = "uid://0isnsk356que"
|
|
||||||
|
|
||||||
[node name="StructuralContainer" type="Node2D" parent="."]
|
|
||||||
|
|
||||||
[node name="Hullplate" parent="StructuralContainer" instance=ExtResource("2_aovrk")]
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31031" parent="StructuralContainer" instance=ExtResource("2_aovrk")]
|
|
||||||
position = Vector2(0, 100)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31033" parent="StructuralContainer" instance=ExtResource("2_aovrk")]
|
|
||||||
position = Vector2(100, 100)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31035" parent="StructuralContainer" instance=ExtResource("2_aovrk")]
|
|
||||||
position = Vector2(100, 0)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31037" parent="StructuralContainer" instance=ExtResource("2_aovrk")]
|
|
||||||
position = Vector2(100, -100)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31039" parent="StructuralContainer" instance=ExtResource("2_aovrk")]
|
|
||||||
position = Vector2(100, -200)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31041" parent="StructuralContainer" instance=ExtResource("2_aovrk")]
|
|
||||||
position = Vector2(0, -200)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31043" parent="StructuralContainer" instance=ExtResource("2_aovrk")]
|
|
||||||
position = Vector2(0, -100)
|
|
||||||
|
|
||||||
[node name="Bulkhead" parent="StructuralContainer" instance=ExtResource("4_dwgsg")]
|
|
||||||
position = Vector2(-50, 100)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31046" parent="StructuralContainer" instance=ExtResource("4_dwgsg")]
|
|
||||||
position = Vector2(-50, 0)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31048" parent="StructuralContainer" instance=ExtResource("4_dwgsg")]
|
|
||||||
position = Vector2(-50, -100)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31050" parent="StructuralContainer" instance=ExtResource("4_dwgsg")]
|
|
||||||
position = Vector2(-50, -200)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31052" parent="StructuralContainer" instance=ExtResource("4_dwgsg")]
|
|
||||||
position = Vector2(150, -200)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31054" parent="StructuralContainer" instance=ExtResource("4_dwgsg")]
|
|
||||||
position = Vector2(150, -100)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31056" parent="StructuralContainer" instance=ExtResource("4_dwgsg")]
|
|
||||||
position = Vector2(150, 0)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31058" parent="StructuralContainer" instance=ExtResource("4_dwgsg")]
|
|
||||||
position = Vector2(150, 100)
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31060" parent="StructuralContainer" instance=ExtResource("4_dwgsg")]
|
|
||||||
position = Vector2(0, 150)
|
|
||||||
rotation = 1.5708
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31062" parent="StructuralContainer" instance=ExtResource("4_dwgsg")]
|
|
||||||
position = Vector2(100, 150)
|
|
||||||
rotation = 1.5708
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31064" parent="StructuralContainer" instance=ExtResource("4_dwgsg")]
|
|
||||||
position = Vector2(0, -250)
|
|
||||||
rotation = 1.5708
|
|
||||||
|
|
||||||
[node name="@StaticBody2D@31066" parent="StructuralContainer" instance=ExtResource("4_dwgsg")]
|
|
||||||
position = Vector2(100, -250)
|
|
||||||
rotation = 1.5708
|
|
||||||
|
|
||||||
[node name="HullVolumeContainer" type="Node2D" parent="."]
|
|
||||||
|
|
||||||
[node name="AtmosphereVisualizer" type="Node2D" parent="."]
|
|
||||||
|
|
||||||
[node name="Camera2D" type="Camera2D" parent="."]
|
|
||||||
position = Vector2(50, -50)
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://cm0rohkr6khd1"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://6co67nfy8ngb" path="res://scenes/ship/builder/module.gd" id="1_b1h2b"]
|
|
||||||
|
|
||||||
[node name="Module" type="Node2D"]
|
|
||||||
script = ExtResource("1_b1h2b")
|
|
||||||
metadata/_custom_type_script = "uid://0isnsk356que"
|
|
||||||
|
|
||||||
[node name="StructuralContainer" type="Node2D" parent="."]
|
|
||||||
|
|
||||||
[node name="HullVolumeContainer" type="Node2D" parent="."]
|
|
||||||
|
|
||||||
[node name="AtmosphereVisualizer" type="Node2D" parent="."]
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
@tool
|
|
||||||
class_name Bulkhead
|
|
||||||
extends StructuralPiece
|
|
||||||
|
|
||||||
# This piece represents a wall or edge.
|
|
||||||
# No additional logic is needed right now, we just need the class_name.
|
|
||||||
@ -1 +0,0 @@
|
|||||||
uid://b4g288mje38nj
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://d3hitk62fice4"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://b4g288mje38nj" path="res://scenes/ship/builder/pieces/bulkhead.gd" id="1_1wp2n"]
|
|
||||||
|
|
||||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_1wp2n"]
|
|
||||||
size = Vector2(10, 100)
|
|
||||||
|
|
||||||
[node name="Bulkhead" type="StaticBody2D"]
|
|
||||||
collision_layer = 16
|
|
||||||
collision_mask = 60
|
|
||||||
script = ExtResource("1_1wp2n")
|
|
||||||
metadata/_custom_type_script = "uid://b7f8x2qimvn37"
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
|
||||||
shape = SubResource("RectangleShape2D_1wp2n")
|
|
||||||
|
|
||||||
[node name="ColorRect" type="ColorRect" parent="."]
|
|
||||||
anchors_preset = 8
|
|
||||||
anchor_left = 0.5
|
|
||||||
anchor_top = 0.5
|
|
||||||
anchor_right = 0.5
|
|
||||||
anchor_bottom = 0.5
|
|
||||||
offset_left = -5.0
|
|
||||||
offset_top = -50.0
|
|
||||||
offset_right = 5.0
|
|
||||||
offset_bottom = 50.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
color = Color(0.6, 0.6, 0.6, 1)
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
@tool
|
|
||||||
class_name Hullplate
|
|
||||||
extends StructuralPiece
|
|
||||||
|
|
||||||
# This piece represents an interior surface.
|
|
||||||
# No additional logic is needed right now, we just need the class_name.
|
|
||||||
@ -1 +0,0 @@
|
|||||||
uid://crmwm623rh1ps
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://bho8x10x4oab7"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://crmwm623rh1ps" path="res://scenes/ship/builder/pieces/hullplate.gd" id="1_ecow4"]
|
|
||||||
|
|
||||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_1wp2n"]
|
|
||||||
size = Vector2(100, 100)
|
|
||||||
|
|
||||||
[node name="Hullplate" type="StaticBody2D"]
|
|
||||||
collision_mask = 0
|
|
||||||
script = ExtResource("1_ecow4")
|
|
||||||
metadata/_custom_type_script = "uid://b7f8x2qimvn37"
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
|
||||||
shape = SubResource("RectangleShape2D_1wp2n")
|
|
||||||
|
|
||||||
[node name="ColorRect" type="ColorRect" parent="."]
|
|
||||||
anchors_preset = 8
|
|
||||||
anchor_left = 0.5
|
|
||||||
anchor_top = 0.5
|
|
||||||
anchor_right = 0.5
|
|
||||||
anchor_bottom = 0.5
|
|
||||||
offset_left = -50.0
|
|
||||||
offset_top = -50.0
|
|
||||||
offset_right = 50.0
|
|
||||||
offset_bottom = 50.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
color = Color(0.4, 0.4, 0.4, 1)
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
@tool
|
|
||||||
class_name StructuralPiece
|
|
||||||
extends OrbitalBody2D
|
|
||||||
|
|
||||||
# Does this piece block atmosphere? (e.g., a hull plate would, a girder would not).
|
|
||||||
@export var is_pressurized: bool = true
|
|
||||||
|
|
||||||
# The health of this specific piece.
|
|
||||||
@export var health: float = 100.0
|
|
||||||
|
|
||||||
# This setter is triggered by the editor.
|
|
||||||
var is_preview: bool = false:
|
|
||||||
set(value):
|
|
||||||
is_preview = value
|
|
||||||
if is_preview:
|
|
||||||
# Make the piece translucent if it's a preview.
|
|
||||||
modulate = Color(1, 1, 1, 0.5)
|
|
||||||
else:
|
|
||||||
# Make it opaque if it's a permanent piece.
|
|
||||||
modulate = Color(1, 1, 1, 1)
|
|
||||||
@ -1 +0,0 @@
|
|||||||
uid://b7f8x2qimvn37
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://ds4eilbvihjy7"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://b7f8x2qimvn37" path="res://scenes/ship/builder/pieces/structural_piece.gd" id="1_6jsoj"]
|
|
||||||
|
|
||||||
[sub_resource type="CircleShape2D" id="CircleShape2D_jsbwo"]
|
|
||||||
|
|
||||||
[node name="StructuralPiece" type="Node2D"]
|
|
||||||
script = ExtResource("1_6jsoj")
|
|
||||||
metadata/_custom_type_script = "uid://0isnsk356que"
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
|
||||||
shape = SubResource("CircleShape2D_jsbwo")
|
|
||||||
|
|
||||||
[node name="ColorRect" type="ColorRect" parent="."]
|
|
||||||
offset_right = 40.0
|
|
||||||
offset_bottom = 40.0
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
extends Databank
|
|
||||||
|
|
||||||
class_name ShipStatusShard
|
|
||||||
|
|
||||||
## This shard emits a signal with the formatted ship status text.
|
|
||||||
signal status_updated(text: String)
|
|
||||||
|
|
||||||
# Called by the Station when it's created.
|
|
||||||
func initialize(ship_root: Module):
|
|
||||||
self.root_module = ship_root
|
|
||||||
|
|
||||||
## Describes the functions this shard needs as input.
|
|
||||||
func get_input_sockets() -> Array[String]:
|
|
||||||
return []
|
|
||||||
|
|
||||||
## Describes the signals this shard can output.
|
|
||||||
func get_output_sockets() -> Array[String]:
|
|
||||||
return ["status_updated"]
|
|
||||||
|
|
||||||
func _physics_process(delta):
|
|
||||||
if not is_instance_valid(root_module):
|
|
||||||
return
|
|
||||||
# 1. Gather all the data from the root module.
|
|
||||||
var rotation_deg = rad_to_deg(root_module.rotation)
|
|
||||||
var angular_vel_dps = rad_to_deg(root_module.angular_velocity)
|
|
||||||
var linear_vel_mps = root_module.linear_velocity.length()
|
|
||||||
|
|
||||||
# 2. Build the string that will be displayed.
|
|
||||||
var status_text = """
|
|
||||||
[font_size=24]Ship Status[/font_size]
|
|
||||||
[font_size=18]Rotation: %.1f deg[/font_size]
|
|
||||||
[font_size=18]Ang. Vel.: %.2f deg/s[/font_size]
|
|
||||||
[font_size=18]Velocity: %.2f m/s[/font_size]
|
|
||||||
""" % [rotation_deg, angular_vel_dps, linear_vel_mps]
|
|
||||||
|
|
||||||
# 3. Emit the signal with the formatted text.
|
|
||||||
status_updated.emit(status_text)
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
[gd_scene load_steps=9 format=3 uid="uid://7yc6a07xoccy"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://cdmmiixa75f3x" path="res://scenes/tests/3d/character_pawn_3d.gd" id="1_4frsu"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://bm1rbv4tuppbc" path="res://eva_suit_controller.tscn" id="3_gnddn"]
|
|
||||||
[ext_resource type="Script" uid="uid://y3vo40i16ek3" path="res://scenes/tests/3d/zero_g_movement_component.gd" id="4_8jhjh"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://ba3ijdstp2bvt" path="res://scenes/tests/3d/player_controller_3d.tscn" id="4_bcy3l"]
|
|
||||||
|
|
||||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_6vm80"]
|
|
||||||
|
|
||||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_6vm80"]
|
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_gnddn"]
|
|
||||||
radius = 1.0
|
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_gnddn"]
|
|
||||||
properties/0/path = NodePath(".:position")
|
|
||||||
properties/0/spawn = true
|
|
||||||
properties/0/replication_mode = 1
|
|
||||||
properties/1/path = NodePath(".:rotation")
|
|
||||||
properties/1/spawn = true
|
|
||||||
properties/1/replication_mode = 1
|
|
||||||
properties/2/path = NodePath("CameraPivot:rotation")
|
|
||||||
properties/2/spawn = true
|
|
||||||
properties/2/replication_mode = 2
|
|
||||||
|
|
||||||
[node name="CharacterPawn3D" type="CharacterBody3D"]
|
|
||||||
script = ExtResource("1_4frsu")
|
|
||||||
metadata/_custom_type_script = "uid://cdmmiixa75f3x"
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
|
||||||
shape = SubResource("CapsuleShape3D_6vm80")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
|
||||||
mesh = SubResource("CapsuleMesh_6vm80")
|
|
||||||
|
|
||||||
[node name="CameraAnchor" type="Marker3D" parent="."]
|
|
||||||
|
|
||||||
[node name="CameraPivot" type="Node3D" parent="."]
|
|
||||||
physics_interpolation_mode = 1
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.75, 0)
|
|
||||||
top_level = true
|
|
||||||
|
|
||||||
[node name="SpringArm" type="SpringArm3D" parent="CameraPivot"]
|
|
||||||
spring_length = 3.0
|
|
||||||
|
|
||||||
[node name="Camera3D" type="Camera3D" parent="CameraPivot/SpringArm"]
|
|
||||||
|
|
||||||
[node name="GripDetector" type="Area3D" parent="."]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1)
|
|
||||||
collision_layer = 0
|
|
||||||
collision_mask = 32768
|
|
||||||
monitorable = false
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="GripDetector"]
|
|
||||||
shape = SubResource("SphereShape3D_gnddn")
|
|
||||||
|
|
||||||
[node name="ZeroGMovementComponent" type="Node3D" parent="."]
|
|
||||||
script = ExtResource("4_8jhjh")
|
|
||||||
metadata/_custom_type_script = "uid://y3vo40i16ek3"
|
|
||||||
|
|
||||||
[node name="EVAMovementComponent" parent="." instance=ExtResource("3_gnddn")]
|
|
||||||
|
|
||||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
|
||||||
replication_config = SubResource("SceneReplicationConfig_gnddn")
|
|
||||||
|
|
||||||
[node name="PlayerController3d" parent="." instance=ExtResource("4_bcy3l")]
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
extends Node
|
|
||||||
|
|
||||||
var port = 42069
|
|
||||||
|
|
||||||
func create_server() -> void:
|
|
||||||
print(multiplayer.multiplayer_peer)
|
|
||||||
var peer = ENetMultiplayerPeer.new()
|
|
||||||
|
|
||||||
setup_connections()
|
|
||||||
|
|
||||||
var error = peer.create_server(port)
|
|
||||||
if error:
|
|
||||||
push_error(error)
|
|
||||||
return
|
|
||||||
|
|
||||||
multiplayer.multiplayer_peer = peer
|
|
||||||
|
|
||||||
print("Server Unique ID: ", multiplayer.get_unique_id())
|
|
||||||
|
|
||||||
func create_client() -> void:
|
|
||||||
setup_connections()
|
|
||||||
|
|
||||||
var peer = ENetMultiplayerPeer.new()
|
|
||||||
var error = peer.create_client("127.0.0.1", port)
|
|
||||||
if error:
|
|
||||||
push_error(error)
|
|
||||||
return
|
|
||||||
|
|
||||||
multiplayer.multiplayer_peer = peer
|
|
||||||
print("Client Unique ID: ", multiplayer.get_unique_id())
|
|
||||||
|
|
||||||
func setup_connections():
|
|
||||||
multiplayer.peer_connected.connect(on_peer_connected)
|
|
||||||
multiplayer.peer_disconnected.connect(on_peer_disconnected)
|
|
||||||
multiplayer.connected_to_server.connect(on_connected_to_server)
|
|
||||||
|
|
||||||
func on_peer_connected(peer_id: int) -> void:
|
|
||||||
print("Peer %s recieved connection: %s" % [multiplayer.get_unique_id(), peer_id])
|
|
||||||
|
|
||||||
# For each peer that connects, we put them in the queue to spawn
|
|
||||||
if multiplayer.is_server():
|
|
||||||
GameManager.queue_spawn_player(peer_id)
|
|
||||||
|
|
||||||
|
|
||||||
func on_peer_disconnected(peer_id: int) -> void:
|
|
||||||
print("Peer %s lost connection to: %s" % [multiplayer.get_unique_id(), peer_id])
|
|
||||||
print(multiplayer.get_peers())
|
|
||||||
|
|
||||||
func on_connected_to_server() -> void:
|
|
||||||
print("%s connected to server!" % multiplayer.get_unique_id())
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
extends Node2D
|
|
||||||
class_name OrbitalBody2D
|
|
||||||
|
|
||||||
# Defines the physical behavior of this body.
|
|
||||||
enum PhysicsMode {
|
|
||||||
INDEPENDENT, # An independent body with its own physics simulation (planets, characters in EVA).
|
|
||||||
COMPOSITE, # A body that aggregates mass and forces from ANCHORED children (ships, modules).
|
|
||||||
ANCHORED # A component that is "bolted on" and defers physics to a COMPOSITE parent.
|
|
||||||
}
|
|
||||||
|
|
||||||
@export var physics_mode: PhysicsMode = PhysicsMode.INDEPENDENT
|
|
||||||
|
|
||||||
var current_grid_authority: OrbitalBody2D = null
|
|
||||||
|
|
||||||
# Mass of this individual component
|
|
||||||
@export var base_mass: float = 1.0
|
|
||||||
@export var mass: float = 0.0 # Aggregated mass of this body and all its OrbitalBody2D children
|
|
||||||
@export var linear_velocity: Vector2 = Vector2.ZERO
|
|
||||||
@export var angular_velocity: float = 0.0
|
|
||||||
|
|
||||||
# Variables to accumulate forces applied during the current physics frame
|
|
||||||
var accumulated_force: Vector2 = Vector2.ZERO
|
|
||||||
var accumulated_torque: float = 0.0
|
|
||||||
|
|
||||||
# Placeholder for Moment of Inertia.
|
|
||||||
@export var inertia: float = 1.0
|
|
||||||
|
|
||||||
func _ready():
|
|
||||||
# Ensure mass update runs immediately before the first _physics_process.
|
|
||||||
recalculate_physical_properties()
|
|
||||||
|
|
||||||
set_physics_process(not Engine.is_editor_hint())
|
|
||||||
physics_interpolation_mode = Node.PHYSICS_INTERPOLATION_MODE_OFF
|
|
||||||
|
|
||||||
# --- PUBLIC FORCE APPLICATION METHODS ---
|
|
||||||
# This method is called by a component (like Thruster) at its global position.
|
|
||||||
func apply_force(force: Vector2, pos: Vector2 = self.global_position):
|
|
||||||
# This is the force routing logic.
|
|
||||||
match physics_mode:
|
|
||||||
PhysicsMode.INDEPENDENT:
|
|
||||||
_add_forces(force, pos)
|
|
||||||
PhysicsMode.COMPOSITE:
|
|
||||||
_add_forces(force, pos)
|
|
||||||
## If we are the root, accumulate the force and calculate torque on the total body.
|
|
||||||
#accumulated_force += force
|
|
||||||
#
|
|
||||||
## Calculate torque (2D cross product: T = r x F = r.x * F.y - r.y * F.x)
|
|
||||||
## 'r' is the vector from the center of mass (global_position) to the point of force application (position).
|
|
||||||
#var r = position - global_position
|
|
||||||
#var torque = r.x * force.y - r.y * force.x
|
|
||||||
#accumulated_torque += torque
|
|
||||||
PhysicsMode.ANCHORED:
|
|
||||||
# If we are not the root, we must route the force to the next OrbitalBody2D parent.
|
|
||||||
var p = get_parent()
|
|
||||||
while p:
|
|
||||||
if p is OrbitalBody2D:
|
|
||||||
# Recursively call the parent's apply_force method.
|
|
||||||
# This sends the force (and its original global position) up the chain.
|
|
||||||
p.apply_force(force, pos)
|
|
||||||
return # Stop at the first OrbitalBody2D parent
|
|
||||||
p = p.get_parent()
|
|
||||||
|
|
||||||
push_error("Anchored OrbitalBody2D has become dislodged and is now Composite.")
|
|
||||||
physics_mode = PhysicsMode.COMPOSITE
|
|
||||||
apply_force(force, position)
|
|
||||||
|
|
||||||
func _add_forces(force: Vector2, pos: Vector2 = Vector2.ZERO):
|
|
||||||
# If we are the root, accumulate the force and calculate torque on the total body.
|
|
||||||
accumulated_force += force
|
|
||||||
|
|
||||||
# Calculate torque (2D cross product: T = r x F = r.x * F.y - r.y * F.x)
|
|
||||||
# 'r' is the vector from the center of mass (global_position) to the point of force application (position).
|
|
||||||
var r = pos - global_position
|
|
||||||
var torque = r.x * force.y - r.y * force.x
|
|
||||||
accumulated_torque += torque
|
|
||||||
|
|
||||||
func _update_mass_and_inertia():
|
|
||||||
mass = base_mass
|
|
||||||
for child in get_children():
|
|
||||||
if child is OrbitalBody2D:
|
|
||||||
child._update_mass_and_inertia() # Recurse into children
|
|
||||||
mass += child.mass
|
|
||||||
|
|
||||||
print("Node: %s, Mass: %f" % [self, mass])
|
|
||||||
|
|
||||||
func _physics_process(delta):
|
|
||||||
if not Engine.is_editor_hint():
|
|
||||||
# Note: We're not integrating forces for anchored bodies
|
|
||||||
# anchored bodies add forces to their parents and
|
|
||||||
match physics_mode:
|
|
||||||
PhysicsMode.INDEPENDENT:
|
|
||||||
_integrate_forces(delta)
|
|
||||||
PhysicsMode.COMPOSITE:
|
|
||||||
_integrate_forces(delta)
|
|
||||||
|
|
||||||
func _integrate_forces(delta):
|
|
||||||
# Safety Check for Division by Zero
|
|
||||||
var sim_mass = mass
|
|
||||||
if sim_mass <= 0.0:
|
|
||||||
# If mass is zero, stop all physics to prevent NaN explosion.
|
|
||||||
accumulated_force = Vector2.ZERO
|
|
||||||
accumulated_torque = 0.0
|
|
||||||
return
|
|
||||||
|
|
||||||
## 1. Calculate and accumulate gravitational force (F_g)
|
|
||||||
#var total_gravity_force = OrbitalMechanics.calculate_n_body_gravity_forces(self)
|
|
||||||
#
|
|
||||||
## 2. Total all forces: F_total = F_g + F_accumulated_from_thrusters
|
|
||||||
#var total_force = total_gravity_force +
|
|
||||||
|
|
||||||
# 3. Apply Linear Physics (F = ma)
|
|
||||||
var linear_acceleration = accumulated_force / sim_mass # Division is now safe
|
|
||||||
linear_velocity += linear_acceleration * delta
|
|
||||||
global_position += linear_velocity * delta
|
|
||||||
|
|
||||||
# 4. Apply Rotational Physics (T = I * angular_acceleration)
|
|
||||||
var angular_acceleration = accumulated_torque / inertia
|
|
||||||
angular_velocity += angular_acceleration * delta
|
|
||||||
rotation += angular_velocity * delta
|
|
||||||
|
|
||||||
# 5. Reset accumulated forces for the next frame
|
|
||||||
accumulated_force = Vector2.ZERO
|
|
||||||
accumulated_torque = 0.0
|
|
||||||
|
|
||||||
# This is the new, corrected function.
|
|
||||||
func recalculate_physical_properties():
|
|
||||||
# For non-composite bodies, the calculation is simple.
|
|
||||||
if physics_mode != PhysicsMode.COMPOSITE:
|
|
||||||
mass = base_mass
|
|
||||||
# --- THE FIX ---
|
|
||||||
# An independent body doesn't calculate inertia from parts.
|
|
||||||
# We ensure it has a non-zero default value to prevent division by zero.
|
|
||||||
if inertia <= 0.0:
|
|
||||||
inertia = 1.0
|
|
||||||
return
|
|
||||||
|
|
||||||
var all_parts: Array[OrbitalBody2D] = []
|
|
||||||
_collect_anchored_parts(all_parts)
|
|
||||||
|
|
||||||
if all_parts.is_empty():
|
|
||||||
mass = base_mass
|
|
||||||
inertia = 1.0
|
|
||||||
return
|
|
||||||
|
|
||||||
# --- Step 1: Calculate Total Mass and LOCAL Center of Mass ---
|
|
||||||
var total_mass = 0.0
|
|
||||||
var weighted_local_pos_sum = Vector2.ZERO
|
|
||||||
for part in all_parts:
|
|
||||||
total_mass += part.base_mass
|
|
||||||
# We get the part's position *relative to the root module*
|
|
||||||
var local_pos = part.global_position - self.global_position
|
|
||||||
weighted_local_pos_sum += local_pos * part.base_mass
|
|
||||||
|
|
||||||
var local_center_of_mass = Vector2.ZERO
|
|
||||||
if total_mass > 0:
|
|
||||||
local_center_of_mass = weighted_local_pos_sum / total_mass
|
|
||||||
|
|
||||||
# --- Step 2: Calculate Total Moment of Inertia around the LOCAL CoM ---
|
|
||||||
var total_inertia = 0.0
|
|
||||||
for part in all_parts:
|
|
||||||
# Get the part's position relative to the root module again
|
|
||||||
var local_pos = part.global_position - self.global_position
|
|
||||||
# The radius is the distance from the part's local position to the ship's local center of mass
|
|
||||||
var r_squared = (local_pos - local_center_of_mass).length_squared()
|
|
||||||
total_inertia += part.base_mass * r_squared
|
|
||||||
|
|
||||||
# --- Step 3: Assign the final values ---
|
|
||||||
self.mass = total_mass
|
|
||||||
# We apply a scaling factor here because our "units" are pixels.
|
|
||||||
# This brings the final value into a range that feels good for gameplay.
|
|
||||||
# You can tune this factor to make ships feel heavier or lighter.
|
|
||||||
self.inertia = total_inertia * 0.01
|
|
||||||
|
|
||||||
#print("Physics Recalculated: Mass=%.2f kg, Inertia=%.2f" % [mass, inertia])
|
|
||||||
|
|
||||||
# A recursive helper function to get an array of all OrbitalBody2D children
|
|
||||||
func _collect_anchored_parts(parts_array: Array):
|
|
||||||
parts_array.append(self)
|
|
||||||
for child in get_children():
|
|
||||||
# TODO: this assumes that all OrbitalBody2D that are attached are done in a clean chain without breaks, which may not be the case
|
|
||||||
if child is OrbitalBody2D and child.physics_mode == PhysicsMode.ANCHORED:
|
|
||||||
child._collect_anchored_parts(parts_array)
|
|
||||||
@ -1 +0,0 @@
|
|||||||
uid://0isnsk356que
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
[gd_resource type="Resource" script_class="GameConfig" load_steps=5 format=3 uid="uid://cv15sck8rl2b7"]
|
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://chgycmkkaf7jv" path="res://scenes/characters/pilot_ball.tscn" id="1_s0mxw"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://didt2nsdtbmra" path="res://modules/Tube.tscn" id="2_75b4c"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dnre6svquwdtb" path="res://scenes/characters/player_controller.tscn" id="2_sk8k5"]
|
|
||||||
[ext_resource type="Script" uid="uid://bfc6u1f8sigxj" path="res://scripts/singletons/game_config.gd" id="3_75b4c"]
|
|
||||||
|
|
||||||
[resource]
|
|
||||||
script = ExtResource("3_75b4c")
|
|
||||||
player_controller_scene = ExtResource("2_sk8k5")
|
|
||||||
default_pawn_scene = ExtResource("1_s0mxw")
|
|
||||||
default_ship_scene = ExtResource("2_75b4c")
|
|
||||||
metadata/_custom_type_script = "uid://bfc6u1f8sigxj"
|
|
||||||
@ -1,241 +0,0 @@
|
|||||||
# OrbitalMechanics.gd
|
|
||||||
extends Node
|
|
||||||
|
|
||||||
# This singleton holds all universal physics constants and functions.
|
|
||||||
|
|
||||||
# The scaled gravitational constant for the entire simulation.
|
|
||||||
const G = 1.0 # Adjust this to control the "speed" of your simulation
|
|
||||||
|
|
||||||
const MIN_INFLUENCE_THRESHOLD = 0.00001
|
|
||||||
const ROCHE_LIMIT_MASS_MULTIPLIER = 0.5
|
|
||||||
|
|
||||||
class BodyTuple:
|
|
||||||
var body_a: OrbitalBody2D
|
|
||||||
var body_b: OrbitalBody2D
|
|
||||||
|
|
||||||
var cached_forces: Dictionary[BodyTuple, Vector2] = {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Centralized Physics Process ---
|
|
||||||
func _physics_process(_delta: float) -> void:
|
|
||||||
var star_system: StarSystem = GameManager.current_star_system
|
|
||||||
if not star_system:
|
|
||||||
return
|
|
||||||
|
|
||||||
var star = star_system.get_star()
|
|
||||||
var planetary_systems = star_system.get_planetary_systems()
|
|
||||||
|
|
||||||
# TODO: Would this be true in case we are working with a system that is just a rouge planet or a brown dwarf?
|
|
||||||
if not star:
|
|
||||||
return
|
|
||||||
|
|
||||||
# 1: Calculate star system pull
|
|
||||||
# a: Get the star and top level Barycenters
|
|
||||||
var top_level_bodies: Array[OrbitalBody2D] = [star]
|
|
||||||
top_level_bodies.append_array(planetary_systems)
|
|
||||||
# b: calculate and apply pull between these
|
|
||||||
apply_n_body_forces(top_level_bodies)
|
|
||||||
|
|
||||||
# 2: Calculate Barycenters local pull
|
|
||||||
for system in planetary_systems:
|
|
||||||
# a: Get each Planetary Barycenters OrbitalBody2Ds (including Ships, Satelites, and Stations fully within the Barycenter)
|
|
||||||
var system_attractors = system.get_internal_attractors()
|
|
||||||
# b: Calculate and apply pull within each Barycenter
|
|
||||||
apply_n_body_forces(system_attractors)
|
|
||||||
|
|
||||||
# 3: Calculate top level Ships, Satelites, and Stations pull
|
|
||||||
# a: Get top level OrbitalBody2Ds of non-celestial classes
|
|
||||||
for star_orbiter in star_system.get_orbital_bodies():
|
|
||||||
# b: Split into Star Orbiting and On-Approach using mass/distance ratios to Barycenters
|
|
||||||
# TODO: Check for distance to Barycenter
|
|
||||||
# c: For Star Orbiting objects -> Calculate and apply pull to star and Barycenter
|
|
||||||
star_orbiter.apply_force(calculate_n_body_force(star_orbiter, top_level_bodies))
|
|
||||||
# d: For On Approach -> Calculate and apply pull to star and distant Barycenters
|
|
||||||
# as well as individual bodies within approaching Barycenter
|
|
||||||
|
|
||||||
func calculate_gravitational_force(orbiter: OrbitalBody2D, primary: OrbitalBody2D) -> Vector2:
|
|
||||||
if not is_instance_valid(orbiter) or not is_instance_valid(primary):
|
|
||||||
return Vector2.ZERO
|
|
||||||
|
|
||||||
var distance_sq = orbiter.global_position.distance_squared_to(primary.global_position)
|
|
||||||
|
|
||||||
if distance_sq < 1.0:
|
|
||||||
return Vector2.ZERO
|
|
||||||
|
|
||||||
# --- Influence Pruning (Culling) ---
|
|
||||||
# We check both directions of influence
|
|
||||||
var influence_a = primary.mass / distance_sq
|
|
||||||
var influence_b = orbiter.mass / distance_sq
|
|
||||||
|
|
||||||
if influence_a < MIN_INFLUENCE_THRESHOLD and influence_b < MIN_INFLUENCE_THRESHOLD:
|
|
||||||
return Vector2.ZERO
|
|
||||||
|
|
||||||
var force_magnitude = (G * primary.mass * orbiter.mass) / distance_sq
|
|
||||||
var direction = orbiter.global_position.direction_to(primary.global_position)
|
|
||||||
return direction * force_magnitude
|
|
||||||
|
|
||||||
# Calculates the pull between a set number of bodies
|
|
||||||
# Use carefully to simulate each level of the simulation
|
|
||||||
# Iterate through every unique pair of bodies (i, j) where j > i
|
|
||||||
func apply_n_body_forces(attractors: Array[OrbitalBody2D]):
|
|
||||||
# Iterate through every unique pair of bodies (i, j) where j > i
|
|
||||||
for i in range(attractors.size()):
|
|
||||||
var body_a: OrbitalBody2D = attractors[i]
|
|
||||||
if not is_instance_valid(body_a): continue
|
|
||||||
|
|
||||||
for j in range(i + 1, attractors.size()):
|
|
||||||
var body_b: OrbitalBody2D = attractors[j]
|
|
||||||
if not is_instance_valid(body_b): continue
|
|
||||||
|
|
||||||
# Calculate the force vector ONCE
|
|
||||||
var force_vector = calculate_gravitational_force(body_a, body_b)
|
|
||||||
|
|
||||||
# Apply the force symmetrically
|
|
||||||
if force_vector != Vector2.ZERO:
|
|
||||||
body_a.apply_force(force_vector)
|
|
||||||
body_b.apply_force(-force_vector)
|
|
||||||
|
|
||||||
func calculate_n_body_force(body: OrbitalBody2D, attractors: Array[OrbitalBody2D]) -> Vector2:
|
|
||||||
var total_pull: Vector2 = Vector2.ZERO
|
|
||||||
for attractor in attractors:
|
|
||||||
total_pull += calculate_gravitational_force(body, attractor)
|
|
||||||
return total_pull
|
|
||||||
|
|
||||||
func calculate_n_body_gravity_forces(body_to_affect: Node2D) -> Vector2:
|
|
||||||
var total_force = Vector2.ZERO
|
|
||||||
if not is_instance_valid(body_to_affect):
|
|
||||||
return total_force
|
|
||||||
|
|
||||||
# Get the list of all major gravitational bodies from the GameManager.
|
|
||||||
var system_data = GameManager.get_system_data()
|
|
||||||
if not system_data:
|
|
||||||
return total_force
|
|
||||||
|
|
||||||
# We only consider planets and the star as major attractors for performance.
|
|
||||||
var attractors = system_data.all_bodies()
|
|
||||||
|
|
||||||
for attractor in attractors:
|
|
||||||
if is_instance_valid(attractor) and attractor != body_to_affect:
|
|
||||||
total_force += calculate_gravitational_force(body_to_affect, attractor)
|
|
||||||
|
|
||||||
return total_force
|
|
||||||
|
|
||||||
# Calculates the perfect initial velocity for a stable circular orbit.
|
|
||||||
func calculate_circular_orbit_velocity(orbiter: OrbitalBody2D, primary: OrbitalBody2D) -> Vector2:
|
|
||||||
if not is_instance_valid(primary):
|
|
||||||
return Vector2.ZERO
|
|
||||||
|
|
||||||
var distance = orbiter.global_position.distance_to(primary.global_position)
|
|
||||||
if distance == 0:
|
|
||||||
return Vector2.ZERO
|
|
||||||
|
|
||||||
# v = sqrt(G * M / r)
|
|
||||||
var speed_magnitude = sqrt(G * primary.mass / distance)
|
|
||||||
|
|
||||||
var direction_to_orbiter = primary.global_position.direction_to(orbiter.global_position)
|
|
||||||
var perpendicular_direction = Vector2(direction_to_orbiter.y, -direction_to_orbiter.x)
|
|
||||||
|
|
||||||
return perpendicular_direction * speed_magnitude
|
|
||||||
|
|
||||||
func _calculate_n_body_orbital_path(body_to_trace: OrbitalBody2D) -> PackedVector2Array:
|
|
||||||
var num_steps = 10
|
|
||||||
var time_step = 60
|
|
||||||
|
|
||||||
var ghost_position = body_to_trace.global_position
|
|
||||||
var ghost_velocity = body_to_trace.linear_velocity
|
|
||||||
|
|
||||||
var path_points = PackedVector2Array()
|
|
||||||
|
|
||||||
for i in range(num_steps):
|
|
||||||
# Create a temporary "ghost" body to calculate forces on.
|
|
||||||
var ghost_body = OrbitalBody2D.new()
|
|
||||||
ghost_body.global_position = ghost_position
|
|
||||||
ghost_body.mass = body_to_trace.mass
|
|
||||||
|
|
||||||
# Use our library to get the total gravitational force at the ghost's position.
|
|
||||||
var total_force = calculate_n_body_gravity_forces(ghost_body)
|
|
||||||
var acceleration = total_force / ghost_body.mass
|
|
||||||
|
|
||||||
ghost_velocity += acceleration * time_step
|
|
||||||
ghost_position += ghost_velocity * time_step
|
|
||||||
path_points.append(ghost_position)
|
|
||||||
|
|
||||||
ghost_body.free() # Clean up the temporary node
|
|
||||||
|
|
||||||
return path_points
|
|
||||||
|
|
||||||
# Calculates an array of points for the orbit RELATIVE to the primary body.
|
|
||||||
func _calculate_relative_orbital_path(body_to_trace: OrbitalBody2D) -> PackedVector2Array:
|
|
||||||
if not is_instance_valid(body_to_trace) or not body_to_trace.has_method("get_primary") or not is_instance_valid(body_to_trace.get_primary()):
|
|
||||||
return PackedVector2Array()
|
|
||||||
|
|
||||||
var primary = body_to_trace.get_primary()
|
|
||||||
var primary_mass = primary.mass
|
|
||||||
var body_mass = body_to_trace.mass
|
|
||||||
|
|
||||||
var ghost_relative_pos = body_to_trace.global_position - primary.global_position
|
|
||||||
var ghost_relative_vel = body_to_trace.linear_velocity - primary.linear_velocity
|
|
||||||
|
|
||||||
var r_magnitude = ghost_relative_pos.length()
|
|
||||||
if r_magnitude == 0:
|
|
||||||
return PackedVector2Array()
|
|
||||||
|
|
||||||
var v_sq = ghost_relative_vel.length_squared()
|
|
||||||
var mu = G * primary_mass
|
|
||||||
|
|
||||||
var specific_energy = v_sq / 2.0 - mu / r_magnitude
|
|
||||||
|
|
||||||
var num_steps = 200
|
|
||||||
var time_step: float
|
|
||||||
if specific_energy >= 0:
|
|
||||||
time_step = 0.1
|
|
||||||
else:
|
|
||||||
var semi_major_axis = -mu / (2.0 * specific_energy)
|
|
||||||
var orbital_period = 2.0 * PI * sqrt(pow(semi_major_axis, 3) / mu)
|
|
||||||
time_step = orbital_period / float(num_steps)
|
|
||||||
|
|
||||||
var path_points = PackedVector2Array()
|
|
||||||
|
|
||||||
for i in range(num_steps):
|
|
||||||
var distance_sq = ghost_relative_pos.length_squared()
|
|
||||||
if distance_sq < 1.0:
|
|
||||||
break
|
|
||||||
|
|
||||||
var direction = -ghost_relative_pos.normalized()
|
|
||||||
var force_magnitude = (G * primary_mass * body_mass) / distance_sq
|
|
||||||
var force_vector = direction * force_magnitude
|
|
||||||
var acceleration = force_vector / body_mass
|
|
||||||
|
|
||||||
ghost_relative_vel += acceleration * time_step
|
|
||||||
ghost_relative_pos += ghost_relative_vel * time_step
|
|
||||||
path_points.append(ghost_relative_pos)
|
|
||||||
|
|
||||||
return path_points
|
|
||||||
|
|
||||||
# Calculates the Hill Sphere radius for a satellite.
|
|
||||||
# This is the region where the satellite's gravity is dominant over its primary's.
|
|
||||||
func calculate_hill_sphere(orbiter: OrbitalBody2D, primary: OrbitalBody2D) -> float:
|
|
||||||
if not is_instance_valid(orbiter) or not is_instance_valid(primary) or primary.mass <= 0:
|
|
||||||
return 0.0
|
|
||||||
|
|
||||||
var distance = orbiter.global_position.distance_to(primary.global_position)
|
|
||||||
# The formula is: a * (m / 3M)^(1/3)
|
|
||||||
var mass_ratio = orbiter.mass / (3.0 * primary.mass)
|
|
||||||
if mass_ratio < 0: return 0.0
|
|
||||||
|
|
||||||
return distance * pow(mass_ratio, 1.0/3.0)
|
|
||||||
|
|
||||||
# Calculates a simplified Roche Limit, or minimum safe orbital distance.
|
|
||||||
func calculate_simplified_roche_limit(primary: OrbitalBody2D) -> float:
|
|
||||||
if not is_instance_valid(primary) or primary.mass <= 0:
|
|
||||||
return 100.0 # Return a small default if primary is invalid
|
|
||||||
|
|
||||||
# We approximate a "radius" from the square root of the mass, then apply a multiplier.
|
|
||||||
# This ensures more massive stars and planets have larger "keep-out" zones.
|
|
||||||
return sqrt(primary.mass) * ROCHE_LIMIT_MASS_MULTIPLIER
|
|
||||||
|
|
||||||
func get_orbital_time_in_seconds(orbiter: OrbitalBody2D, primary: OrbitalBody2D) -> float:
|
|
||||||
var mu = OrbitalMechanics.G * primary.mass
|
|
||||||
var r = orbiter.global_position.distance_to(primary.global_position)
|
|
||||||
return TAU * sqrt(pow(r, 3) / mu)
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
# scripts/star_system.gd
|
|
||||||
class_name StarSystem
|
|
||||||
extends Node2D
|
|
||||||
|
|
||||||
@export_group("System Metadata")
|
|
||||||
@export var system_name: String = "Kepler-186"
|
|
||||||
@export var galactic_coordinates: Vector2i = Vector2i.ZERO
|
|
||||||
|
|
||||||
var system_data: SystemData
|
|
||||||
|
|
||||||
func _ready():
|
|
||||||
# 1. Create the generator tool.
|
|
||||||
var generator = StarSystemGenerator.new()
|
|
||||||
|
|
||||||
# 2. Tell the generator to build the system within this StarSystem node.
|
|
||||||
system_data = generator.generate(self)
|
|
||||||
|
|
||||||
# 3. Register the completed system with the GameManager.
|
|
||||||
GameManager.register_star_system(self)
|
|
||||||
GameManager.start_game()
|
|
||||||
|
|
||||||
# --- Public API for accessing system data ---
|
|
||||||
func get_star() -> OrbitalBody2D:
|
|
||||||
if is_instance_valid(system_data):
|
|
||||||
return system_data.star
|
|
||||||
return null
|
|
||||||
|
|
||||||
func get_planetary_systems() -> Array[Barycenter]:
|
|
||||||
var bodies: Array[Barycenter] = []
|
|
||||||
for child in get_children():
|
|
||||||
if child is Barycenter:
|
|
||||||
bodies.append(child)
|
|
||||||
|
|
||||||
return bodies
|
|
||||||
|
|
||||||
func get_orbital_bodies() -> Array[OrbitalBody2D]:
|
|
||||||
var bodies: Array[OrbitalBody2D] = []
|
|
||||||
for child in get_children():
|
|
||||||
if child is Star or child is Barycenter:
|
|
||||||
continue
|
|
||||||
if child is OrbitalBody2D:
|
|
||||||
bodies.append(child)
|
|
||||||
|
|
||||||
return bodies
|
|
||||||
|
|
||||||
func get_system_data() -> SystemData:
|
|
||||||
return system_data
|
|
||||||
|
|
||||||
class AsteroidBelt:
|
|
||||||
var width : float
|
|
||||||
var mass : float
|
|
||||||
var centered_radius : float = 0.0
|
|
||||||
var asteroids : Array[OrbitalBody2D]
|
|
||||||
@ -1,115 +0,0 @@
|
|||||||
# scripts/star_system_generator.gd
|
|
||||||
class_name StarSystemGenerator
|
|
||||||
extends RefCounted
|
|
||||||
|
|
||||||
# --- Stable Mass Ratios & Generation Rules ---
|
|
||||||
const STAR_MASS = 50000000.0
|
|
||||||
const PLANET_MASS = STAR_MASS / 10000.0 # Planet is 10,000x less massive than the star.
|
|
||||||
const MOON_MASS = PLANET_MASS / 1000.0 # Moon is 1,000x less massive than its planet.
|
|
||||||
const MIN_PLANETS = 3
|
|
||||||
const MAX_PLANETS = 8
|
|
||||||
const MAX_MOONS_PER_PLANET = 5
|
|
||||||
const ORBIT_SAFETY_FACTOR = 5 # Increase space between orbits
|
|
||||||
|
|
||||||
# --- The main public method ---
|
|
||||||
func generate(star_system: StarSystem) -> SystemData:
|
|
||||||
# 1. Create the root Barycenter for the entire system.
|
|
||||||
var system_data = SystemData.new()
|
|
||||||
|
|
||||||
# 2. Create the star itself inside the root Barycenter.
|
|
||||||
var star = Star.new()
|
|
||||||
system_data.star = star
|
|
||||||
star.name = "Star"
|
|
||||||
star.base_mass = STAR_MASS
|
|
||||||
star_system.add_child(star)
|
|
||||||
|
|
||||||
# 3. Procedurally generate and place the planetary systems.
|
|
||||||
var num_planets = randi_range(MIN_PLANETS, MAX_PLANETS)
|
|
||||||
var current_orbit_radius = 15000.0 # OrbitalMechanics.calculate_simplified_roche_limit(star) # Start with the first orbit
|
|
||||||
|
|
||||||
for i in range(num_planets):
|
|
||||||
# A. Create the Barycenter for the new planetary system.
|
|
||||||
var planet_barycenter = Barycenter.new()
|
|
||||||
|
|
||||||
planet_barycenter.name = "PlanetSystem_%d" % (i + 1)
|
|
||||||
star_system.add_child(planet_barycenter)
|
|
||||||
|
|
||||||
# B. Create the planet itself inside its Barycenter.
|
|
||||||
var planet = Planet.new()
|
|
||||||
system_data.planets.append(planet)
|
|
||||||
planet.name = "Planet_%d" % (i + 1)
|
|
||||||
planet.base_mass = randf_range(PLANET_MASS * 0.2, PLANET_MASS * 5.0)
|
|
||||||
planet_barycenter.add_child(planet)
|
|
||||||
planet.owner = planet_barycenter
|
|
||||||
planet.position = Vector2.ZERO
|
|
||||||
planet_barycenter.recalculate_total_mass()
|
|
||||||
# C. Create moons for this planet.
|
|
||||||
_generate_moons(planet, planet_barycenter, system_data)
|
|
||||||
|
|
||||||
# D. Place the entire planetary system in a stable orbit.
|
|
||||||
planet_barycenter.global_position = Vector2(current_orbit_radius, 0).rotated(randf_range(0, TAU))
|
|
||||||
planet_barycenter.linear_velocity = OrbitalMechanics.calculate_circular_orbit_velocity(planet_barycenter, star)
|
|
||||||
|
|
||||||
# Update the new edge of the star's influence
|
|
||||||
# 1. Calculate the Hill Sphere (gravitational influence) for the planet we just placed.
|
|
||||||
var hill_sphere = OrbitalMechanics.calculate_hill_sphere(planet_barycenter, star)
|
|
||||||
# 2. Add this zone of influence (plus a safety margin) to the current radius
|
|
||||||
# to determine the starting point for the NEXT planet. This ensures orbits never overlap.
|
|
||||||
current_orbit_radius += hill_sphere * ORBIT_SAFETY_FACTOR
|
|
||||||
|
|
||||||
# --- Spawn the ship at the last planet's L4 point ---
|
|
||||||
if i == num_planets - 1:
|
|
||||||
_spawn_player_ship(star_system, star, planet_barycenter)
|
|
||||||
|
|
||||||
return system_data
|
|
||||||
|
|
||||||
func _generate_moons(planet: OrbitalBody2D, planet_barycenter: Barycenter, system_data: SystemData):
|
|
||||||
var num_moons = randi_range(0, int(planet.mass / MOON_MASS / 2.0)) # Heavier planets get more moons
|
|
||||||
num_moons = min(num_moons, MAX_MOONS_PER_PLANET)
|
|
||||||
|
|
||||||
var current_orbit_radius = 200.0 # OrbitalMechanics.calculate_simplified_roche_limit(planet) # Start with the first orbit
|
|
||||||
|
|
||||||
for i in range(num_moons):
|
|
||||||
var moon = Moon.new()
|
|
||||||
system_data.moons.append(moon)
|
|
||||||
planet_barycenter.add_child(moon)
|
|
||||||
planet_barycenter.recalculate_total_mass()
|
|
||||||
moon.owner = planet_barycenter
|
|
||||||
moon.name = "Moon_%d" % (i + 1)
|
|
||||||
moon.base_mass = randf_range(MOON_MASS * 0.1, MOON_MASS * 2.0)
|
|
||||||
|
|
||||||
moon.position = Vector2(current_orbit_radius, 0).rotated(randf_range(0, TAU))
|
|
||||||
# Velocity is calculated relative to the parent (the planet)
|
|
||||||
moon.linear_velocity = OrbitalMechanics.calculate_circular_orbit_velocity(moon, planet_barycenter)
|
|
||||||
|
|
||||||
# Update the new edge of the planets's influence
|
|
||||||
# 1. Calculate the Hill Sphere (gravitational influence) for the moon we just placed.
|
|
||||||
var hill_sphere = OrbitalMechanics.calculate_hill_sphere(moon, planet_barycenter)
|
|
||||||
# 2. Add this zone of influence (plus a safety margin) to the current radius
|
|
||||||
# to determine the starting point for the NEXT planet. This ensures orbits never overlap.
|
|
||||||
current_orbit_radius += hill_sphere * ORBIT_SAFETY_FACTOR
|
|
||||||
|
|
||||||
|
|
||||||
# --- NEW FUNCTION: Spawns the player ship at a Lagrange point ---
|
|
||||||
func _spawn_player_ship(star_system: StarSystem, star: OrbitalBody2D, planet_system: Barycenter):
|
|
||||||
# L4 and L5 Lagrange points form an equilateral triangle with the star and planet.
|
|
||||||
# We'll calculate L4 by rotating the star-planet vector by +60 degrees.
|
|
||||||
var star_to_planet_vec = planet_system.global_position - star.global_position
|
|
||||||
var l4_position = star.global_position + star_to_planet_vec.rotated(PI / 3.0)
|
|
||||||
|
|
||||||
# The ship's velocity at L4 must match the orbital characteristics of that point.
|
|
||||||
# This is an approximation where we rotate the planet's velocity vector by 60 degrees.
|
|
||||||
var l4_velocity = planet_system.linear_velocity.rotated(PI / 3.0)
|
|
||||||
|
|
||||||
# Instantiate, position, and configure the ship.
|
|
||||||
var ship_instance = GameManager.config.default_ship_scene.instantiate()
|
|
||||||
GameManager.register_ship(ship_instance)
|
|
||||||
ship_instance.name = "PlayerShip"
|
|
||||||
star_system.add_child(ship_instance) # Add ship to the root StarSystem node
|
|
||||||
ship_instance.global_position = l4_position
|
|
||||||
ship_instance.linear_velocity = l4_velocity
|
|
||||||
ship_instance.rotation = l4_velocity.angle() + (PI / 2.0) # Point prograde
|
|
||||||
|
|
||||||
# Make sure the new ship is included in the physics simulation
|
|
||||||
#_system_data_dict.all_bodies.append(ship_instance)
|
|
||||||
print("Player ship spawned at L4 point of %s" % planet_system.name)
|
|
||||||
67
src/export_presets.cfg
Normal file
67
src/export_presets.cfg
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
[preset.0]
|
||||||
|
|
||||||
|
name="Windows Desktop"
|
||||||
|
platform="Windows Desktop"
|
||||||
|
runnable=true
|
||||||
|
advanced_options=true
|
||||||
|
dedicated_server=false
|
||||||
|
custom_features=""
|
||||||
|
export_filter="all_resources"
|
||||||
|
include_filter=""
|
||||||
|
exclude_filter=""
|
||||||
|
export_path="../export/moa.exe"
|
||||||
|
patches=PackedStringArray()
|
||||||
|
encryption_include_filters=""
|
||||||
|
encryption_exclude_filters=""
|
||||||
|
seed=0
|
||||||
|
encrypt_pck=false
|
||||||
|
encrypt_directory=false
|
||||||
|
script_export_mode=2
|
||||||
|
|
||||||
|
[preset.0.options]
|
||||||
|
|
||||||
|
custom_template/debug=""
|
||||||
|
custom_template/release=""
|
||||||
|
debug/export_console_wrapper=1
|
||||||
|
binary_format/embed_pck=true
|
||||||
|
texture_format/s3tc_bptc=true
|
||||||
|
texture_format/etc2_astc=false
|
||||||
|
shader_baker/enabled=false
|
||||||
|
binary_format/architecture="x86_64"
|
||||||
|
codesign/enable=false
|
||||||
|
codesign/timestamp=true
|
||||||
|
codesign/timestamp_server_url=""
|
||||||
|
codesign/digest_algorithm=1
|
||||||
|
codesign/description=""
|
||||||
|
codesign/custom_options=PackedStringArray()
|
||||||
|
application/modify_resources=true
|
||||||
|
application/icon=""
|
||||||
|
application/console_wrapper_icon=""
|
||||||
|
application/icon_interpolation=4
|
||||||
|
application/file_version=""
|
||||||
|
application/product_version=""
|
||||||
|
application/company_name=""
|
||||||
|
application/product_name=""
|
||||||
|
application/file_description=""
|
||||||
|
application/copyright=""
|
||||||
|
application/trademarks=""
|
||||||
|
application/export_angle=0
|
||||||
|
application/export_d3d12=0
|
||||||
|
application/d3d12_agility_sdk_multiarch=true
|
||||||
|
ssh_remote_deploy/enabled=false
|
||||||
|
ssh_remote_deploy/host="user@host_ip"
|
||||||
|
ssh_remote_deploy/port="22"
|
||||||
|
ssh_remote_deploy/extra_args_ssh=""
|
||||||
|
ssh_remote_deploy/extra_args_scp=""
|
||||||
|
ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'
|
||||||
|
$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'
|
||||||
|
$trigger = New-ScheduledTaskTrigger -Once -At 00:00
|
||||||
|
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
|
||||||
|
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings
|
||||||
|
Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true
|
||||||
|
Start-ScheduledTask -TaskName godot_remote_debug
|
||||||
|
while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }
|
||||||
|
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"
|
||||||
|
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
|
||||||
|
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
|
||||||
|
Remove-Item -Recurse -Force '{temp_dir}'"
|
||||||
|
Before Width: | Height: | Size: 994 B After Width: | Height: | Size: 994 B |
7
src/main.tscn
Normal file
7
src/main.tscn
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://dogqi2c58qdc0"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://ojcho3pi3u7n" path="res://scenes/UI/main_menu/main_menu.tscn" id="1_ig7tw"]
|
||||||
|
|
||||||
|
[node name="StartMenu" type="Node3D" unique_id=1392183658]
|
||||||
|
|
||||||
|
[node name="MainMenu" parent="." unique_id=2099645465 instance=ExtResource("1_ig7tw")]
|
||||||
573
src/modules/3d_test_ship.tscn
Normal file
573
src/modules/3d_test_ship.tscn
Normal file
@ -0,0 +1,573 @@
|
|||||||
|
[gd_scene load_steps=5 format=3 uid="uid://bkwogkfqk2uxo"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://6co67nfy8ngb" path="res://scenes/ship/builder/module.gd" id="1_ktv2t"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bsyufiv0m1018" path="res://scenes/ship/builder/pieces/hullplate.tscn" id="2_shb7f"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dvpy3urgtm62n" path="res://scenes/ship/components/hardware/spawner.tscn" id="3_ism2t"]
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_ism2t"]
|
||||||
|
properties/0/path = NodePath(".:position")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 1
|
||||||
|
properties/1/path = NodePath(".:linear_velocity")
|
||||||
|
properties/1/spawn = true
|
||||||
|
properties/1/replication_mode = 1
|
||||||
|
properties/2/path = NodePath(".:rotation")
|
||||||
|
properties/2/spawn = true
|
||||||
|
properties/2/replication_mode = 1
|
||||||
|
|
||||||
|
[node name="3dTestShip" type="RigidBody3D" unique_id=246037729]
|
||||||
|
physics_interpolation_mode = 1
|
||||||
|
script = ExtResource("1_ktv2t")
|
||||||
|
physics_mode = 1
|
||||||
|
base_mass = 10000.0
|
||||||
|
metadata/_custom_type_script = "uid://6co67nfy8ngb"
|
||||||
|
|
||||||
|
[node name="Hullplate7" parent="." unique_id=1182121679 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, -1, 0)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate8" parent="." unique_id=294855274 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, -1, -1)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate9" parent="." unique_id=130054924 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, -1, 1)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate4" parent="." unique_id=2133064539 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, 1, 0)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate5" parent="." unique_id=1436331513 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, 1, -1)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate6" parent="." unique_id=1249365999 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, 1, 1)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate11" parent="." unique_id=1656979163 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, 0, -4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate13" parent="." unique_id=1426276711 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, -1, -3)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate14" parent="." unique_id=1212526811 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, -1, -4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate15" parent="." unique_id=403515873 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, -1, -2)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate16" parent="." unique_id=145935239 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, 1, -3)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate17" parent="." unique_id=1662804653 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, 1, -4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate18" parent="." unique_id=741829932 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, 1, -2)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate21" parent="." unique_id=31417961 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, 0, 4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate22" parent="." unique_id=1845702661 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, -1, 3)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate23" parent="." unique_id=1747432968 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, -1, 2)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate24" parent="." unique_id=1486518216 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, -1, 4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate25" parent="." unique_id=1880158566 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, 1, 3)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate26" parent="." unique_id=1506445603 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, 1, 2)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate27" parent="." unique_id=1749302489 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2, 1, 4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate31" parent="." unique_id=1965678834 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, -1, -4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate32" parent="." unique_id=515940324 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, -1, -3)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate33" parent="." unique_id=313389603 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, -1, -2)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate34" parent="." unique_id=363616195 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, 1, 0)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate35" parent="." unique_id=568985619 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, 1, -1)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate36" parent="." unique_id=193191417 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, 1, 1)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate38" parent="." unique_id=1152815429 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, 0, -4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate40" parent="." unique_id=1303768723 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, -1, -1)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate41" parent="." unique_id=1489680526 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, -1, 0)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate42" parent="." unique_id=1454642421 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, -1, 1)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate43" parent="." unique_id=1322280114 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, 1, -3)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate44" parent="." unique_id=1380061102 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, 1, -4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate45" parent="." unique_id=1740305308 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, 1, -2)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate48" parent="." unique_id=587023569 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, 0, 4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate49" parent="." unique_id=1103858035 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, -1, 3)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate50" parent="." unique_id=916625356 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, -1, 2)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate51" parent="." unique_id=2115734988 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, -1, 4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate52" parent="." unique_id=1715698306 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, 1, 3)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate53" parent="." unique_id=369018899 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, 1, 2)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate54" parent="." unique_id=1618415296 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2, 1, 4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate57" parent="." unique_id=1148292814 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, 0, 1, 0, -0.014328662, 0, 0.99989736, -1.5, 0, 4.5)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate58" parent="." unique_id=1183219370 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.50098634, -1, 4.4908433)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate59" parent="." unique_id=95522376 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.49901366, -1, 4.4908433)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate60" parent="." unique_id=960534764 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, 0, 1, 0, -0.014328662, 0, 0.99989736, -1.5, -1, 4.5)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate61" parent="." unique_id=1862079328 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.50098634, 1.000001, 4.4908433)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate62" parent="." unique_id=876185578 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.49901366, 1.000001, 4.4908433)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate64" parent="." unique_id=622302151 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.4990137, 9.536743e-07, 4.4908433)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate65" parent="." unique_id=2027647666 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.4990137, -1, 4.4908433)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate66" parent="." unique_id=335333911 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.4990137, 1.000001, 4.4908433)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate63" parent="." unique_id=779321466 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, 0, 1, 0, -0.014328662, 0, 0.99989736, -1.5, 1, 4.5)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate69" parent="." unique_id=391423682 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, 0, 1, 0, -0.014328662, 0, 0.99989736, -1.5009866, 9.536743e-07, -4.5091567)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate70" parent="." unique_id=1436426809 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.50098634, -1, -4.5091567)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate71" parent="." unique_id=1045660804 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.49901366, -1, -4.5091567)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate72" parent="." unique_id=1696784058 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, 0, 1, 0, -0.014328662, 0, 0.99989736, -1.5009866, -1, -4.5091567)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate73" parent="." unique_id=1709873058 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.50098634, 1.000001, -4.5091567)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate74" parent="." unique_id=1071906843 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.49901366, 1.000001, -4.5091567)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate75" parent="." unique_id=413542580 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.4990137, 9.536743e-07, -4.5091567)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate76" parent="." unique_id=448578032 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.4990137, -1, -4.5091567)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate77" parent="." unique_id=1162322851 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.4990137, 1.000001, -4.5091567)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate78" parent="." unique_id=790206161 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, 0, 1, 0, -0.014328662, 0, 0.99989736, -1.5009866, 1.000001, -4.5091567)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate79" parent="." unique_id=1019136641 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, 1.5000012, -3.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate80" parent="." unique_id=152922175 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, 1.5000012, -3.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate81" parent="." unique_id=771888008 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, 1.5000012, -3.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate82" parent="." unique_id=816092557 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, 1.5000012, -2.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate83" parent="." unique_id=1871920861 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, 1.5000012, -2.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate84" parent="." unique_id=103727539 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, 1.5000012, -2.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate85" parent="." unique_id=1457444620 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, 1.5000012, -4.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate86" parent="." unique_id=1402217859 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, 1.5000012, -4.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate87" parent="." unique_id=293240152 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, 1.5000012, -3.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate88" parent="." unique_id=158231735 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, 1.5000012, -2.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate89" parent="." unique_id=2017317978 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, 1.5000012, -4.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate90" parent="." unique_id=1810711362 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, 1.5000012, -4.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate91" parent="." unique_id=648502427 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, 1.5000012, -0.009156942)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate92" parent="." unique_id=1280848561 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, 1.5000012, -0.009156942)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate93" parent="." unique_id=1000182357 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, 1.5000012, -0.009156942)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate94" parent="." unique_id=663755561 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, 1.5000012, 0.99084306)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate95" parent="." unique_id=977211031 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, 1.5000012, 0.99084306)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate96" parent="." unique_id=1017704164 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, 1.5000012, 0.99084306)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate97" parent="." unique_id=2095269489 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, 1.5000012, -1.0091572)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate98" parent="." unique_id=615154295 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, 1.5000012, -1.0091572)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate99" parent="." unique_id=1435686924 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, 1.5000012, -0.009156942)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate100" parent="." unique_id=361501534 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, 1.5000012, 0.99084306)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate101" parent="." unique_id=776176100 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, 1.5000012, -1.0091572)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate102" parent="." unique_id=1146417492 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, 1.5000012, -1.0091572)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate103" parent="." unique_id=1413321748 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, 1.5000012, 2.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate104" parent="." unique_id=1044980803 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, 1.5000012, 2.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate105" parent="." unique_id=1804409489 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, 1.5000012, 2.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate106" parent="." unique_id=1076107521 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.5, 1.5, 4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate107" parent="." unique_id=1190510681 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.5, 1.5, 4)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate108" parent="." unique_id=855909591 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, 1.5000012, 3.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate109" parent="." unique_id=946006990 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, 1.5000012, 1.9908428)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate110" parent="." unique_id=1957722835 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, 1.5000012, 1.9908428)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate111" parent="." unique_id=1708941560 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, 1.5000012, 2.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate112" parent="." unique_id=598393913 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, 1.5000012, 3.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate113" parent="." unique_id=629535431 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, 1.5000012, 1.9908428)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate114" parent="." unique_id=1483594858 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, 1.5000012, 1.9908428)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate115" parent="." unique_id=1186769437 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, -1.4999988, -3.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate116" parent="." unique_id=752889015 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, -1.4999988, -3.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate117" parent="." unique_id=175698677 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, -1.4999988, -3.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate118" parent="." unique_id=670641245 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, -1.4999988, -2.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate119" parent="." unique_id=988678524 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, -1.4999988, -2.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate120" parent="." unique_id=896262764 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, -1.4999988, -2.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate121" parent="." unique_id=1336630931 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, -1.4999988, -4.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate122" parent="." unique_id=101919359 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, -1.4999988, -4.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate123" parent="." unique_id=1356736016 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, -1.4999988, -3.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate124" parent="." unique_id=742815341 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, -1.4999988, -2.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate125" parent="." unique_id=1651537246 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, -1.4999988, -4.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate126" parent="." unique_id=1253078352 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, -1.4999988, -4.009157)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate127" parent="." unique_id=519787812 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, -1.4999988, -0.009156942)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate128" parent="." unique_id=629828036 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, -1.4999988, -0.009156942)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate129" parent="." unique_id=2010663580 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, -1.4999988, -0.009156942)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate130" parent="." unique_id=1705163002 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, -1.4999988, 0.99084306)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate131" parent="." unique_id=1635599014 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, -1.4999988, 0.99084306)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate132" parent="." unique_id=789401102 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, -1.4999988, 0.99084306)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate133" parent="." unique_id=1671040057 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, -1.4999988, -1.0091572)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate134" parent="." unique_id=2118015321 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, -1.4999988, -1.0091572)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate135" parent="." unique_id=1970124357 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, -1.4999988, -0.009156942)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate136" parent="." unique_id=2129372302 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, -1.4999988, 0.99084306)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate137" parent="." unique_id=543355427 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, -1.4999988, -1.0091572)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate138" parent="." unique_id=1885736043 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, -1.4999988, -1.0091572)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate139" parent="." unique_id=654209436 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, -1.4999988, 2.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate140" parent="." unique_id=1938132143 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, -1.4999988, 2.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate141" parent="." unique_id=486424951 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, -1.4999988, 2.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate142" parent="." unique_id=910140496 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, -1.4999988, 3.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate143" parent="." unique_id=515293159 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, -1.4999988, 3.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate144" parent="." unique_id=890871001 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, -1.4999988, 3.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate145" parent="." unique_id=1626468827 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.50098634, -1.4999988, 1.9908428)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate146" parent="." unique_id=578516444 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.49901366, -1.4999988, 1.9908428)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate147" parent="." unique_id=402255852 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, -1.4999988, 2.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate148" parent="." unique_id=1631434711 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, -1.4999988, 3.990843)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate149" parent="." unique_id=726702930 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 1.4990137, -1.4999988, 1.9908428)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="Hullplate150" parent="." unique_id=1001521061 instance=ExtResource("2_shb7f")]
|
||||||
|
transform = Transform3D(0.99989736, 0, 0.014328662, -0.014328662, -4.371139e-08, 0.99989736, 6.263257e-10, -1, -4.37069e-08, -1.5009866, -1.4999988, 1.9908428)
|
||||||
|
physics_mode = 2
|
||||||
|
|
||||||
|
[node name="OmniLight3D" type="OmniLight3D" parent="." unique_id=1071155008]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.4, 1, -3)
|
||||||
|
|
||||||
|
[node name="OmniLight3D2" type="OmniLight3D" parent="." unique_id=151820223]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.6, 1, -3)
|
||||||
|
|
||||||
|
[node name="OmniLight3D3" type="OmniLight3D" parent="." unique_id=390575041]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.6, 1, 4)
|
||||||
|
|
||||||
|
[node name="OmniLight3D4" type="OmniLight3D" parent="." unique_id=1659652061]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.4, 1, 4)
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="." unique_id=1905582997]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 3)
|
||||||
|
current = true
|
||||||
|
|
||||||
|
[node name="Spawner" parent="." unique_id=6714366 instance=ExtResource("3_ism2t")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2)
|
||||||
|
|
||||||
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=2096937457]
|
||||||
|
replication_config = SubResource("SceneReplicationConfig_ism2t")
|
||||||
26
src/modules/physics_testing_ship.tscn
Normal file
26
src/modules/physics_testing_ship.tscn
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://xcgmicfdqqb1"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://6co67nfy8ngb" path="res://scenes/ship/builder/module.gd" id="1_ogx5r"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bsyufiv0m1018" path="res://scenes/ship/builder/pieces/hullplate.tscn" id="2_nyqc6"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dvpy3urgtm62n" path="res://scenes/ship/components/hardware/spawner.tscn" id="3_3bya3"]
|
||||||
|
|
||||||
|
[node name="PhysicsTestingShip" type="RigidBody3D"]
|
||||||
|
script = ExtResource("1_ogx5r")
|
||||||
|
base_mass = 200.0
|
||||||
|
metadata/_custom_type_script = "uid://6co67nfy8ngb"
|
||||||
|
|
||||||
|
[node name="Hullplate" parent="." instance=ExtResource("2_nyqc6")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, -1, 0)
|
||||||
|
|
||||||
|
[node name="Spawner" parent="." instance=ExtResource("3_3bya3")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.021089494, 0)
|
||||||
|
|
||||||
|
[node name="OmniLight3D" type="OmniLight3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0, -2)
|
||||||
|
|
||||||
|
[node name="OmniLight3D2" type="OmniLight3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0, -2)
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 3)
|
||||||
|
current = true
|
||||||
7
src/modules/test_ship.tscn
Normal file
7
src/modules/test_ship.tscn
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://cwblg6q5qse6c"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://d3hitk62fice4" path="res://scenes/ship/builder/pieces/bulkhead.tscn" id="1_obkto"]
|
||||||
|
|
||||||
|
[node name="TestShip" type="Node3D"]
|
||||||
|
|
||||||
|
[node name="Bulkhead" parent="." instance=ExtResource("1_obkto")]
|
||||||
@ -10,9 +10,10 @@ config_version=5
|
|||||||
|
|
||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="space_simulation"
|
config/name="Millimeters of Aluminum"
|
||||||
|
config/version="0.1"
|
||||||
run/main_scene="uid://dogqi2c58qdc0"
|
run/main_scene="uid://dogqi2c58qdc0"
|
||||||
config/features=PackedStringArray("4.5", "Forward Plus")
|
config/features=PackedStringArray("4.5", "Double Precision", "Forward Plus")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
[autoload]
|
[autoload]
|
||||||
@ -21,6 +22,7 @@ OrbitalMechanics="*res://scripts/singletons/orbital_mechanics.gd"
|
|||||||
GameManager="*res://scripts/singletons/game_manager.gd"
|
GameManager="*res://scripts/singletons/game_manager.gd"
|
||||||
Constants="*res://scripts/singletons/constants.gd"
|
Constants="*res://scripts/singletons/constants.gd"
|
||||||
NetworkHandler="*res://scripts/network/network_handler.gd"
|
NetworkHandler="*res://scripts/network/network_handler.gd"
|
||||||
|
MotionUtils="*res://scripts/singletons/motion_utils.gd"
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
|
|
||||||
@ -166,18 +168,20 @@ left_click={
|
|||||||
2d_physics/layer_4="projectiles"
|
2d_physics/layer_4="projectiles"
|
||||||
2d_physics/layer_5="bulkheads"
|
2d_physics/layer_5="bulkheads"
|
||||||
2d_physics/layer_6="characters"
|
2d_physics/layer_6="characters"
|
||||||
|
3d_physics/layer_15="weld"
|
||||||
3d_physics/layer_16="grip"
|
3d_physics/layer_16="grip"
|
||||||
|
|
||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
common/physics_jitter_fix=0.0
|
3d/default_gravity=0.0
|
||||||
|
3d/default_gravity_vector=Vector3(0, 0, 0)
|
||||||
3d/default_linear_damp=0.0
|
3d/default_linear_damp=0.0
|
||||||
|
3d/default_angular_damp=0.0
|
||||||
3d/sleep_threshold_linear=0.0
|
3d/sleep_threshold_linear=0.0
|
||||||
2d/default_gravity=0.0
|
2d/default_gravity=0.0
|
||||||
2d/default_gravity_vector=Vector2(0, 0)
|
2d/default_gravity_vector=Vector2(0, 0)
|
||||||
2d/default_linear_damp=0.0
|
2d/default_linear_damp=0.0
|
||||||
2d/sleep_threshold_linear=0.0
|
2d/sleep_threshold_linear=0.0
|
||||||
common/physics_interpolation=true
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
|
|
||||||
35
src/scenes/UI/ingame_menu/ingame_menu.gd
Normal file
35
src/scenes/UI/ingame_menu/ingame_menu.gd
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
@onready var resume_button: Button = %ResumeButton
|
||||||
|
@onready var disconnect_button: Button = %DisconnectButton
|
||||||
|
@onready var quit_button: Button = %QuitButton
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
resume_button.pressed.connect(toggle_menu)
|
||||||
|
disconnect_button.pressed.connect(_on_disconnect_pressed)
|
||||||
|
quit_button.pressed.connect(_on_quit_pressed)
|
||||||
|
|
||||||
|
hide()
|
||||||
|
|
||||||
|
func _input(event):
|
||||||
|
if event.is_action_pressed("ui_cancel"):
|
||||||
|
toggle_menu()
|
||||||
|
|
||||||
|
func toggle_menu():
|
||||||
|
visible = !visible
|
||||||
|
|
||||||
|
if visible:
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
||||||
|
else:
|
||||||
|
# Only capture mouse if we are actually playing a pawn
|
||||||
|
# You might need a smarter check here depending on game state
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||||
|
|
||||||
|
func _on_disconnect_pressed():
|
||||||
|
NetworkHandler.close_connection()
|
||||||
|
toggle_menu()
|
||||||
|
# Return to main menu
|
||||||
|
get_tree().change_scene_to_file("res://main.tscn")
|
||||||
|
|
||||||
|
func _on_quit_pressed():
|
||||||
|
get_tree().quit()
|
||||||
1
src/scenes/UI/ingame_menu/ingame_menu.gd.uid
Normal file
1
src/scenes/UI/ingame_menu/ingame_menu.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://2aoy8ivk2hgl
|
||||||
58
src/scenes/UI/ingame_menu/ingame_menu.tscn
Normal file
58
src/scenes/UI/ingame_menu/ingame_menu.tscn
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://pausemenu456"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://2aoy8ivk2hgl" path="res://scenes/UI/ingame_menu/ingame_menu.gd" id="1_pm_script"]
|
||||||
|
|
||||||
|
[node name="IngameeMenu" type="Control" unique_id=8878860]
|
||||||
|
process_mode = 3
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_pm_script")
|
||||||
|
|
||||||
|
[node name="ColorRect" type="ColorRect" parent="." unique_id=1882361500]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
color = Color(0, 0, 0, 0.05)
|
||||||
|
|
||||||
|
[node name="CenterContainer" type="CenterContainer" parent="." unique_id=1122355242]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer" unique_id=1948011184]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 15
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="CenterContainer/VBoxContainer" unique_id=214886966]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 32
|
||||||
|
text = "Menu"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="ResumeButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1856665966]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(150, 40)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Resume"
|
||||||
|
|
||||||
|
[node name="DisconnectButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=4948876]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(150, 40)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Disconnect"
|
||||||
|
|
||||||
|
[node name="QuitButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1695513560]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(150, 40)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Quit Game"
|
||||||
47
src/scenes/UI/main_menu/main_menu.gd
Normal file
47
src/scenes/UI/main_menu/main_menu.gd
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
# @export var lobby_menu: Control
|
||||||
|
# @export var settings_menu: Control
|
||||||
|
|
||||||
|
# Buttons and input fields
|
||||||
|
@onready var host_button: Button = %HostButton
|
||||||
|
@onready var join_button: Button = %JoinButton
|
||||||
|
@onready var settings_button: Button = %SettingsButton
|
||||||
|
@onready var quit_button: Button = %QuitButton
|
||||||
|
@onready var address_entry: LineEdit = %AddressEntry
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
host_button.pressed.connect(_on_host_pressed)
|
||||||
|
join_button.pressed.connect(_on_join_pressed)
|
||||||
|
quit_button.pressed.connect(_on_quit_pressed)
|
||||||
|
|
||||||
|
# Ensure we start with a clean slate
|
||||||
|
# lobby_menu.visible = false
|
||||||
|
|
||||||
|
# If we just returned from a game, ensure mouse is visible
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
||||||
|
|
||||||
|
func _on_host_pressed():
|
||||||
|
# For a simple test, hosting immediately starts the server and the game
|
||||||
|
NetworkHandler.create_server()
|
||||||
|
NetworkHandler.on_peer_connected(multiplayer.get_unique_id())
|
||||||
|
_transition_to_game()
|
||||||
|
|
||||||
|
func _on_join_pressed():
|
||||||
|
var ip = address_entry.text
|
||||||
|
if ip.is_empty():
|
||||||
|
ip = "127.0.0.1" # Default to localhost
|
||||||
|
|
||||||
|
NetworkHandler.create_client(ip)
|
||||||
|
# The NetworkHandler signals will handle the actual transition once connected
|
||||||
|
# But for UI feedback, we might want to show a "Connecting..." label here.
|
||||||
|
|
||||||
|
func _on_quit_pressed():
|
||||||
|
get_tree().quit()
|
||||||
|
|
||||||
|
func _transition_to_game():
|
||||||
|
# This would typically load the main game scene.
|
||||||
|
# Since your main scene IS the game loop currently, we might need to
|
||||||
|
# just hide the menu if it's an overlay, OR change scenes.
|
||||||
|
# Assuming Main.tscn is the game world:
|
||||||
|
get_tree().change_scene_to_file("res://scripts/star_system.tscn")
|
||||||
1
src/scenes/UI/main_menu/main_menu.gd.uid
Normal file
1
src/scenes/UI/main_menu/main_menu.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://dypq4h3hy1l3v
|
||||||
78
src/scenes/UI/main_menu/main_menu.tscn
Normal file
78
src/scenes/UI/main_menu/main_menu.tscn
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://ojcho3pi3u7n"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dypq4h3hy1l3v" path="res://scenes/UI/main_menu/main_menu.gd" id="1_script"]
|
||||||
|
|
||||||
|
[node name="MainMenu" type="Control" unique_id=2099645465]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_script")
|
||||||
|
|
||||||
|
[node name="Background" type="ColorRect" parent="." unique_id=2137889995]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
color = Color(0.05, 0.05, 0.08, 1)
|
||||||
|
|
||||||
|
[node name="CenterContainer" type="CenterContainer" parent="." unique_id=1954458945]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer" unique_id=542164632]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 20
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="CenterContainer/VBoxContainer" unique_id=973405608]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 48
|
||||||
|
text = "Millimeters of Aluminium"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="AddressEntry" type="LineEdit" parent="CenterContainer/VBoxContainer" unique_id=994010326]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
placeholder_text = "127.0.0.1"
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="HostButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1548149031]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(200, 50)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Host Game"
|
||||||
|
|
||||||
|
[node name="JoinButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1826215269]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(200, 50)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Join Game"
|
||||||
|
|
||||||
|
[node name="SettingsButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=811999044]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(200, 50)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Settings"
|
||||||
|
|
||||||
|
[node name="QuitButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1005717980]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(200, 50)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Quit to Desktop"
|
||||||
|
|
||||||
|
[node name="LobbyMenu" type="Control" parent="." unique_id=604668798]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
@ -7,7 +7,7 @@ signal follow_requested(body: Node2D)
|
|||||||
|
|
||||||
@onready var name_label: Label = $NameLabel
|
@onready var name_label: Label = $NameLabel
|
||||||
|
|
||||||
var body_reference: OrbitalBody2D
|
var body_reference: OrbitalBody3D
|
||||||
var dot_color: Color = Color.WHITE
|
var dot_color: Color = Color.WHITE
|
||||||
|
|
||||||
var hover_tween: Tween
|
var hover_tween: Tween
|
||||||
@ -27,18 +27,11 @@ func _ready() -> void:
|
|||||||
mouse_entered.connect(_on_mouse_entered)
|
mouse_entered.connect(_on_mouse_entered)
|
||||||
mouse_exited.connect(_on_mouse_exited)
|
mouse_exited.connect(_on_mouse_exited)
|
||||||
|
|
||||||
func initialize(body: OrbitalBody2D):
|
func initialize(body: OrbitalBody3D):
|
||||||
body_reference = body
|
body_reference = body
|
||||||
name_label.text = body.name
|
name_label.text = body.name
|
||||||
|
|
||||||
if body is Star:
|
dot_color = Color.CYAN
|
||||||
dot_color = Color.GOLD
|
|
||||||
elif body is Planet:
|
|
||||||
dot_color = Color.DODGER_BLUE
|
|
||||||
elif body is Moon:
|
|
||||||
dot_color = Color.PURPLE
|
|
||||||
else:
|
|
||||||
dot_color = Color.CYAN
|
|
||||||
|
|
||||||
self.tooltip_text = _generate_tooltip_text()
|
self.tooltip_text = _generate_tooltip_text()
|
||||||
|
|
||||||
@ -98,7 +91,7 @@ func _on_mouse_exited():
|
|||||||
func _generate_tooltip_text() -> String:
|
func _generate_tooltip_text() -> String:
|
||||||
var info = [body_reference.name]
|
var info = [body_reference.name]
|
||||||
|
|
||||||
if body_reference is Planet:
|
if body_reference is CelestialBody:
|
||||||
var planet_system = body_reference.get_parent() as Barycenter
|
var planet_system = body_reference.get_parent() as Barycenter
|
||||||
var period_seconds = OrbitalMechanics.get_orbital_time_in_seconds(planet_system, GameManager.get_system_data().star)
|
var period_seconds = OrbitalMechanics.get_orbital_time_in_seconds(planet_system, GameManager.get_system_data().star)
|
||||||
|
|
||||||
@ -106,18 +99,11 @@ func _generate_tooltip_text() -> String:
|
|||||||
|
|
||||||
var moon_count = 0
|
var moon_count = 0
|
||||||
for child in planet_system.get_internal_attractors():
|
for child in planet_system.get_internal_attractors():
|
||||||
if child is Moon:
|
if child is CelestialBody:
|
||||||
moon_count += 1
|
moon_count += 1
|
||||||
if moon_count > 0:
|
if moon_count > 0:
|
||||||
info.append("Moons: %d" % moon_count)
|
info.append("Moons: %d" % moon_count)
|
||||||
|
|
||||||
|
|
||||||
if body_reference is Moon:
|
|
||||||
var planet_system = body_reference.get_parent() as Barycenter
|
|
||||||
var period_seconds = OrbitalMechanics.get_orbital_time_in_seconds(body_reference as Moon, planet_system)
|
|
||||||
|
|
||||||
info.append("Orbital Period: %s" % _format_seconds_to_mmss(period_seconds))
|
|
||||||
|
|
||||||
if body_reference is Module:
|
if body_reference is Module:
|
||||||
info.append("Class: Player Vessel")
|
info.append("Class: Player Vessel")
|
||||||
info.append("Mass: %.0f kg" % body_reference.mass)
|
info.append("Mass: %.0f kg" % body_reference.mass)
|
||||||
@ -1,6 +1,6 @@
|
|||||||
# scripts/barycenter.gd
|
# scripts/barycenter.gd
|
||||||
class_name Barycenter
|
class_name Barycenter
|
||||||
extends OrbitalBody2D
|
extends OrbitalBody3D
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
physics_mode = PhysicsMode.INDEPENDENT
|
physics_mode = PhysicsMode.INDEPENDENT
|
||||||
@ -10,10 +10,10 @@ func _ready():
|
|||||||
# We only need physics_process to integrate our own movement.
|
# We only need physics_process to integrate our own movement.
|
||||||
set_physics_process(true)
|
set_physics_process(true)
|
||||||
|
|
||||||
func get_internal_attractors() -> Array[OrbitalBody2D]:
|
func get_internal_attractors() -> Array[OrbitalBody3D]:
|
||||||
var internal_attractors: Array[OrbitalBody2D] = []
|
var internal_attractors: Array[OrbitalBody3D] = []
|
||||||
for child in get_children():
|
for child in get_children():
|
||||||
if child is OrbitalBody2D:
|
if child is OrbitalBody3D:
|
||||||
internal_attractors.append(child)
|
internal_attractors.append(child)
|
||||||
|
|
||||||
return internal_attractors
|
return internal_attractors
|
||||||
22
src/scenes/celestial_bodies/barycenter.tscn
Normal file
22
src/scenes/celestial_bodies/barycenter.tscn
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://b7bh45nrtdom5"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://b2hb3bwrlh40c" path="res://scenes/celestial_bodies/barycenter.gd" id="1_e776o"]
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_e776o"]
|
||||||
|
properties/0/path = NodePath(".:linear_velocity")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 1
|
||||||
|
properties/1/path = NodePath(".:position")
|
||||||
|
properties/1/spawn = true
|
||||||
|
properties/1/replication_mode = 1
|
||||||
|
|
||||||
|
[node name="Barycenter" type="RigidBody3D" unique_id=1389317234]
|
||||||
|
script = ExtResource("1_e776o")
|
||||||
|
metadata/_custom_type_script = "uid://wlm40n8ywr"
|
||||||
|
|
||||||
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=717759965]
|
||||||
|
replication_config = SubResource("SceneReplicationConfig_e776o")
|
||||||
|
|
||||||
|
[node name="MultiplayerSpawner" type="MultiplayerSpawner" parent="." unique_id=2061784354]
|
||||||
|
_spawnable_scenes = PackedStringArray("uid://dv18eg4xrlefe")
|
||||||
|
spawn_path = NodePath("..")
|
||||||
16
src/scenes/celestial_bodies/celestial_body.gd
Normal file
16
src/scenes/celestial_bodies/celestial_body.gd
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
class_name CelestialBody extends OrbitalBody3D
|
||||||
|
|
||||||
|
# --- Set in corresponding scene ---
|
||||||
|
# var auto_proxy_gravity = false
|
||||||
|
@export var radius: float = 100.0:
|
||||||
|
set(value):
|
||||||
|
radius = value
|
||||||
|
_set_radi()
|
||||||
|
|
||||||
|
func _set_radi():
|
||||||
|
if $Surface.mesh is SphereMesh:
|
||||||
|
$Surface.mesh.radius = radius
|
||||||
|
$Surface.mesh.height = radius * 2.0
|
||||||
|
|
||||||
|
if $CollisionShape3D.shape is SphereShape3D:
|
||||||
|
$CollisionShape3D.shape.radius = radius
|
||||||
1
src/scenes/celestial_bodies/celestial_body.gd.uid
Normal file
1
src/scenes/celestial_bodies/celestial_body.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://dok35h0q4pseh
|
||||||
48
src/scenes/celestial_bodies/celestial_body.tscn
Normal file
48
src/scenes/celestial_bodies/celestial_body.tscn
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
[gd_scene load_steps=6 format=3 uid="uid://dv18eg4xrlefe"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dok35h0q4pseh" path="res://scenes/celestial_bodies/celestial_body.gd" id="1_uxu4s"]
|
||||||
|
[ext_resource type="Material" uid="uid://de0xnmjf12ted" path="res://scenes/celestial_bodies/materials/sun_mat.tres" id="2_vi0nt"]
|
||||||
|
|
||||||
|
[sub_resource type="SphereMesh" id="SphereMesh_vi0nt"]
|
||||||
|
resource_local_to_scene = true
|
||||||
|
material = ExtResource("2_vi0nt")
|
||||||
|
radius = 2000.0
|
||||||
|
height = 4000.0
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_uxu4s"]
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_vi0nt"]
|
||||||
|
properties/0/path = NodePath(".:position")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 1
|
||||||
|
properties/1/path = NodePath(".:rotation")
|
||||||
|
properties/1/spawn = true
|
||||||
|
properties/1/replication_mode = 1
|
||||||
|
properties/2/path = NodePath(".:linear_velocity")
|
||||||
|
properties/2/spawn = true
|
||||||
|
properties/2/replication_mode = 1
|
||||||
|
properties/3/path = NodePath(".:angular_velocity")
|
||||||
|
properties/3/spawn = true
|
||||||
|
properties/3/replication_mode = 1
|
||||||
|
properties/4/path = NodePath(".:radius")
|
||||||
|
properties/4/spawn = true
|
||||||
|
properties/4/replication_mode = 1
|
||||||
|
|
||||||
|
[node name="CelestialBody" type="RigidBody3D" unique_id=345490070]
|
||||||
|
script = ExtResource("1_uxu4s")
|
||||||
|
auto_proxy_gravity = false
|
||||||
|
metadata/_custom_type_script = "uid://dok35h0q4pseh"
|
||||||
|
|
||||||
|
[node name="Surface" type="MeshInstance3D" parent="." unique_id=193823349]
|
||||||
|
mesh = SubResource("SphereMesh_vi0nt")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=232085687]
|
||||||
|
shape = SubResource("SphereShape3D_uxu4s")
|
||||||
|
|
||||||
|
[node name="OmniLight3D" type="OmniLight3D" parent="." unique_id=1965995953]
|
||||||
|
light_color = Color(0.958646, 0.7997282, 0.55087835, 1)
|
||||||
|
omni_range = 200000.0
|
||||||
|
omni_attenuation = 2.0
|
||||||
|
|
||||||
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=2090029903]
|
||||||
|
replication_config = SubResource("SceneReplicationConfig_vi0nt")
|
||||||
52
src/scenes/celestial_bodies/materials/sun_mat.gdshader
Normal file
52
src/scenes/celestial_bodies/materials/sun_mat.gdshader
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// https://godotshaders.com/shader/3d-sun-shader/
|
||||||
|
shader_type spatial;
|
||||||
|
render_mode specular_schlick_ggx;
|
||||||
|
|
||||||
|
uniform float Glow_Power : hint_range(0,10) = 3;
|
||||||
|
uniform float Lightness_Difference : hint_range(0,10) = 3;
|
||||||
|
uniform vec4 Sun_Color: source_color;
|
||||||
|
|
||||||
|
uniform sampler2D voronoi_noise;
|
||||||
|
uniform sampler2D emission_noise;
|
||||||
|
varying vec3 vertex_pos;
|
||||||
|
uniform float waveSpeed : hint_range(0,1) = 0.1;
|
||||||
|
uniform float fresnel : hint_range(0,2) = 1.0;
|
||||||
|
|
||||||
|
uniform float scale : hint_range(0,2) = 0.01;
|
||||||
|
uniform float blendSharpness : hint_range(0,2) = 0.0;
|
||||||
|
|
||||||
|
// TRIPLANAR FUNCTION
|
||||||
|
vec4 triplanar_texture(vec3 position, vec3 normal, vec2 offset, sampler2D noise) {
|
||||||
|
vec4 colX = texture(noise, position.xy * scale + offset);
|
||||||
|
vec4 colY = texture(noise, position.xz * scale + offset);
|
||||||
|
vec4 colZ = texture(noise, position.zy * scale + offset);
|
||||||
|
|
||||||
|
vec3 blendWeight = abs(normal);
|
||||||
|
blendWeight = vec3(pow(blendWeight.x, blendSharpness), pow(blendWeight.y, blendSharpness), pow(blendWeight.z, blendSharpness));
|
||||||
|
blendWeight /= (blendWeight.x + blendWeight.y + blendWeight.z);
|
||||||
|
|
||||||
|
return colX * blendWeight.x + colY * blendWeight.y + colZ * blendWeight.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vertex() {
|
||||||
|
vertex_pos = VERTEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
// Fresnel
|
||||||
|
float fresnel_out = pow(fresnel - clamp(dot(NORMAL, VIEW), 0.0, fresnel), fresnel);
|
||||||
|
|
||||||
|
vec2 waveOffsetA = vec2(TIME * waveSpeed, TIME * waveSpeed * 0.8);
|
||||||
|
vec2 waveOffsetB = vec2(TIME * waveSpeed * - 0.8, TIME * waveSpeed * -0.3);
|
||||||
|
vec2 result_offset = waveOffsetA + waveOffsetB;
|
||||||
|
|
||||||
|
vec3 cloud_tex = triplanar_texture(vertex_pos, NORMAL, result_offset, voronoi_noise).rgb;
|
||||||
|
vec3 cloud_tex_with_light = cloud_tex * vec3(Lightness_Difference);
|
||||||
|
vec3 cloud_tex_with_light_with_color = cloud_tex_with_light * Sun_Color.rgb;
|
||||||
|
vec3 cloud_tex_with_light_with_color_with_glow = vec3(Glow_Power) * cloud_tex_with_light_with_color;
|
||||||
|
|
||||||
|
vec3 noise_tex = triplanar_texture(vertex_pos, NORMAL, result_offset, emission_noise).rgb;
|
||||||
|
vec3 result = cloud_tex_with_light_with_color_with_glow * noise_tex;
|
||||||
|
|
||||||
|
EMISSION = vec3(fresnel_out) * result;
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
uid://0cjdd62t25g1
|
||||||
27
src/scenes/celestial_bodies/materials/sun_mat.tres
Normal file
27
src/scenes/celestial_bodies/materials/sun_mat.tres
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
[gd_resource type="ShaderMaterial" load_steps=6 format=3 uid="uid://de0xnmjf12ted"]
|
||||||
|
|
||||||
|
[ext_resource type="Shader" uid="uid://0cjdd62t25g1" path="res://scenes/celestial_bodies/materials/sun_mat.gdshader" id="1_f1bp4"]
|
||||||
|
|
||||||
|
[sub_resource type="FastNoiseLite" id="FastNoiseLite_f1bp4"]
|
||||||
|
|
||||||
|
[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_1eyo5"]
|
||||||
|
noise = SubResource("FastNoiseLite_f1bp4")
|
||||||
|
|
||||||
|
[sub_resource type="FastNoiseLite" id="FastNoiseLite_6484p"]
|
||||||
|
|
||||||
|
[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_oxjal"]
|
||||||
|
noise = SubResource("FastNoiseLite_6484p")
|
||||||
|
in_3d_space = true
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
render_priority = 0
|
||||||
|
shader = ExtResource("1_f1bp4")
|
||||||
|
shader_parameter/Glow_Power = 10.0
|
||||||
|
shader_parameter/Lightness_Difference = 4.26400020254
|
||||||
|
shader_parameter/Sun_Color = Color(0.90528274, 0.8164857, 0.6356678, 1)
|
||||||
|
shader_parameter/voronoi_noise = SubResource("NoiseTexture2D_oxjal")
|
||||||
|
shader_parameter/emission_noise = SubResource("NoiseTexture2D_1eyo5")
|
||||||
|
shader_parameter/waveSpeed = 0.1
|
||||||
|
shader_parameter/fresnel = 1.0
|
||||||
|
shader_parameter/scale = 0.01
|
||||||
|
shader_parameter/blendSharpness = 0.0
|
||||||
@ -1,5 +1,5 @@
|
|||||||
# CharacterPawn.gd
|
# CharacterPawn.gd
|
||||||
extends CharacterBody3D
|
extends OrbitalBody3D
|
||||||
class_name CharacterPawn3D
|
class_name CharacterPawn3D
|
||||||
|
|
||||||
## Core Parameters
|
## Core Parameters
|
||||||
@ -17,8 +17,8 @@ var _pitch_yaw_input: Vector2 = Vector2.ZERO
|
|||||||
|
|
||||||
## Rotation Variables
|
## Rotation Variables
|
||||||
@onready var camera_anchor: Marker3D = $CameraAnchor
|
@onready var camera_anchor: Marker3D = $CameraAnchor
|
||||||
@onready var camera_pivot: Node3D = $CameraPivot
|
@onready var camera_pivot: Node3D = $CameraAnchor/CameraPivot
|
||||||
@onready var camera: Camera3D = $CameraPivot/SpringArm/Camera3D
|
@onready var camera: Camera3D = $CameraAnchor/CameraPivot/SpringArm/Camera3D
|
||||||
@export_range(0.1, PI / 2.0) var max_yaw_rad: float = deg_to_rad(80.0)
|
@export_range(0.1, PI / 2.0) var max_yaw_rad: float = deg_to_rad(80.0)
|
||||||
@export_range(-PI / 2.0 + 0.01, 0) var min_pitch_rad: float = deg_to_rad(-75.0)
|
@export_range(-PI / 2.0 + 0.01, 0) var min_pitch_rad: float = deg_to_rad(-75.0)
|
||||||
@export_range(0, PI / 2.0 - 0.01) var max_pitch_rad: float = deg_to_rad(60.0)
|
@export_range(0, PI / 2.0 - 0.01) var max_pitch_rad: float = deg_to_rad(60.0)
|
||||||
@ -29,7 +29,6 @@ var _pitch_yaw_input: Vector2 = Vector2.ZERO
|
|||||||
@onready var zero_g_movemement_component: ZeroGMovementComponent = $ZeroGMovementComponent
|
@onready var zero_g_movemement_component: ZeroGMovementComponent = $ZeroGMovementComponent
|
||||||
|
|
||||||
## Physics State (Managed by Pawn)
|
## Physics State (Managed by Pawn)
|
||||||
var angular_velocity: Vector3 = Vector3.ZERO
|
|
||||||
@export var angular_damping: float = 0.95 # Base damping
|
@export var angular_damping: float = 0.95 # Base damping
|
||||||
|
|
||||||
## Other State Variables
|
## Other State Variables
|
||||||
@ -53,42 +52,39 @@ func _ready():
|
|||||||
else:
|
else:
|
||||||
printerr("GripDetector Area3D node not found on CharacterPawn!")
|
printerr("GripDetector Area3D node not found on CharacterPawn!")
|
||||||
|
|
||||||
if is_multiplayer_authority():
|
if name == str(multiplayer.get_unique_id()):
|
||||||
camera.make_current()
|
camera.make_current()
|
||||||
camera.process_mode = Node.PROCESS_MODE_ALWAYS
|
camera.process_mode = Node.PROCESS_MODE_ALWAYS
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
func _process(delta: float) -> void:
|
|
||||||
camera_pivot.global_transform = camera_anchor.get_global_transform_interpolated()
|
camera_pivot.global_transform = camera_anchor.get_global_transform_interpolated()
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(delta: float):
|
func _physics_process(_delta: float):
|
||||||
# 1. Apply Mouse Rotation (Universal head look)
|
|
||||||
_apply_mouse_rotation()
|
_apply_mouse_rotation()
|
||||||
|
|
||||||
if zero_g_movemement_component: # Fallback to ZeroG controller (for initiating reach)
|
|
||||||
zero_g_movemement_component.process_movement(delta, _move_input, _vertical_input, _roll_input, _l_click_input, _r_click_input)
|
|
||||||
|
|
||||||
# 3. Integrate Angular Velocity (Universal)
|
|
||||||
_integrate_angular_velocity(delta)
|
|
||||||
|
|
||||||
# 4. Apply Linear Velocity & Collision (Universal)
|
|
||||||
# Use move_and_slide for states affected by gravity/floor or zero-g collisions
|
|
||||||
move_and_slide()
|
|
||||||
|
|
||||||
# Check for collision response AFTER move_and_slide
|
|
||||||
var collision_count = get_slide_collision_count()
|
|
||||||
if collision_count > 0:
|
|
||||||
var collision = get_slide_collision(collision_count - 1) # Get last collision
|
|
||||||
# Delegate or handle basic bounce
|
|
||||||
if eva_suit_component:
|
|
||||||
eva_suit_component.handle_collision(collision, collision_energy_loss)
|
|
||||||
else:
|
|
||||||
_handle_basic_collision(collision)
|
|
||||||
|
|
||||||
# 5. Reset Inputs
|
|
||||||
_reset_inputs()
|
_reset_inputs()
|
||||||
|
|
||||||
|
|
||||||
|
func _integrate_forces(state: PhysicsDirectBodyState3D):
|
||||||
|
if not is_multiplayer_authority(): return
|
||||||
|
super (state)
|
||||||
|
|
||||||
|
|
||||||
|
# print("Integrating forces for pawn %s" % name)
|
||||||
|
# print(" Move Input: %s, Vertical Input: %f, Roll Input: %f" % [_move_input, _vertical_input, _roll_input])
|
||||||
|
|
||||||
|
# Zero-G Movement
|
||||||
|
if zero_g_movemement_component:
|
||||||
|
# We pass the physics state
|
||||||
|
zero_g_movemement_component.process_movement(state, _move_input, _vertical_input, _roll_input, _l_click_input, _r_click_input)
|
||||||
|
|
||||||
|
# EVA Suit Movement
|
||||||
|
if eva_suit_component and zero_g_movemement_component.movement_state == ZeroGMovementComponent.MovementState.IDLE:
|
||||||
|
eva_suit_component.process_eva_movement(state, _move_input, _vertical_input, _roll_input, _r_click_input)
|
||||||
|
|
||||||
|
|
||||||
# --- Universal Rotation ---
|
# --- Universal Rotation ---
|
||||||
func _apply_mouse_rotation():
|
func _apply_mouse_rotation():
|
||||||
if _pitch_yaw_input != Vector2.ZERO:
|
if _pitch_yaw_input != Vector2.ZERO:
|
||||||
@ -112,28 +108,6 @@ func _integrate_angular_velocity(delta: float):
|
|||||||
if angular_velocity.length_squared() < 0.0001:
|
if angular_velocity.length_squared() < 0.0001:
|
||||||
angular_velocity = Vector3.ZERO
|
angular_velocity = Vector3.ZERO
|
||||||
|
|
||||||
func _handle_basic_collision(collision: KinematicCollision3D):
|
|
||||||
var surface_normal = collision.get_normal()
|
|
||||||
velocity = velocity.bounce(surface_normal)
|
|
||||||
velocity *= (1.0 - collision_energy_loss * 0.5)
|
|
||||||
|
|
||||||
# --- Public Helper for Controllers ---
|
|
||||||
# Applies torque affecting angular velocity
|
|
||||||
func add_torque(torque_global: Vector3, delta: float):
|
|
||||||
# Calculate effective inertia (base + suit multiplier if applicable)
|
|
||||||
var effective_inertia = base_inertia * (eva_suit_component.inertia_multiplier if eva_suit_component else 1.0)
|
|
||||||
if effective_inertia <= 0: effective_inertia = 1.0 # Safety prevent division by zero
|
|
||||||
# Apply change directly to angular velocity using the global torque
|
|
||||||
|
|
||||||
angular_velocity += (torque_global / effective_inertia) * delta
|
|
||||||
|
|
||||||
# --- Movement Implementations (Keep non-EVA ones here) ---
|
|
||||||
func _apply_walking_movement(_delta: float): pass # TODO
|
|
||||||
func _apply_ladder_floating_drag(delta: float):
|
|
||||||
velocity = velocity.lerp(Vector3.ZERO, delta * 2.0);
|
|
||||||
angular_velocity = angular_velocity.lerp(Vector3.ZERO, delta * 2.0)
|
|
||||||
func _apply_ladder_movement(_delta: float): pass # TODO
|
|
||||||
|
|
||||||
# --- Input Setters/Resets (Add vertical to set_movement_input) ---
|
# --- Input Setters/Resets (Add vertical to set_movement_input) ---
|
||||||
func set_movement_input(move: Vector2, roll: float, vertical: float): _move_input = move; _roll_input = roll; _vertical_input = vertical
|
func set_movement_input(move: Vector2, roll: float, vertical: float): _move_input = move; _roll_input = roll; _vertical_input = vertical
|
||||||
func set_interaction_input(interact_input: PlayerController3D.KeyInput): _interact_input = interact_input
|
func set_interaction_input(interact_input: PlayerController3D.KeyInput): _interact_input = interact_input
|
||||||
@ -157,7 +131,8 @@ func _reset_head_yaw(delta: float):
|
|||||||
# Smoothly apply the reset target to the actual pivot rotation
|
# Smoothly apply the reset target to the actual pivot rotation
|
||||||
camera_anchor.rotation.y = lerpf(camera_anchor.rotation.y, 0.0, delta * head_turn_lerp_speed)
|
camera_anchor.rotation.y = lerpf(camera_anchor.rotation.y, 0.0, delta * head_turn_lerp_speed)
|
||||||
|
|
||||||
func _notification(what: int) -> void:
|
# TODO: Re-enable when multiplayer authority per pawn is functional
|
||||||
match what:
|
# func _notification(what: int) -> void:
|
||||||
NOTIFICATION_ENTER_TREE:
|
# match what:
|
||||||
set_multiplayer_authority(int(name))
|
# NOTIFICATION_ENTER_TREE:
|
||||||
|
# set_multiplayer_authority(int(name))
|
||||||
81
src/scenes/character/character_pawn_3d.tscn
Normal file
81
src/scenes/character/character_pawn_3d.tscn
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
[gd_scene load_steps=10 format=3 uid="uid://7yc6a07xoccy"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://cdmmiixa75f3x" path="res://scenes/character/character_pawn_3d.gd" id="1_4frsu"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bm1rbv4tuppbc" path="res://scenes/character/eva_suit_controller.tscn" id="3_gnddn"]
|
||||||
|
[ext_resource type="Script" uid="uid://y3vo40i16ek3" path="res://scenes/character/zero_g_movement_component.gd" id="4_8jhjh"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://ba3ijdstp2bvt" path="res://scenes/character/player_controller_3d.tscn" id="4_bcy3l"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_6vm80"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleMesh" id="CapsuleMesh_6vm80"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_673rh"]
|
||||||
|
radius = 0.1
|
||||||
|
height = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_gnddn"]
|
||||||
|
radius = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_gnddn"]
|
||||||
|
properties/0/path = NodePath(".:position")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 1
|
||||||
|
properties/1/path = NodePath(".:rotation")
|
||||||
|
properties/1/spawn = true
|
||||||
|
properties/1/replication_mode = 1
|
||||||
|
properties/2/path = NodePath("CameraAnchor:rotation")
|
||||||
|
properties/2/spawn = true
|
||||||
|
properties/2/replication_mode = 1
|
||||||
|
properties/3/path = NodePath(".:linear_velocity")
|
||||||
|
properties/3/spawn = false
|
||||||
|
properties/3/replication_mode = 0
|
||||||
|
properties/4/path = NodePath(".:angular_velocity")
|
||||||
|
properties/4/spawn = false
|
||||||
|
properties/4/replication_mode = 0
|
||||||
|
|
||||||
|
[node name="CharacterPawn3D" type="RigidBody3D" unique_id=288275840]
|
||||||
|
physics_interpolation_mode = 1
|
||||||
|
top_level = true
|
||||||
|
script = ExtResource("1_4frsu")
|
||||||
|
metadata/_custom_type_script = "uid://cdmmiixa75f3x"
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1967015232]
|
||||||
|
shape = SubResource("CapsuleShape3D_6vm80")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=1703183586]
|
||||||
|
mesh = SubResource("CapsuleMesh_6vm80")
|
||||||
|
|
||||||
|
[node name="CameraAnchor" type="Marker3D" parent="." unique_id=462168232]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.7000000000000001, 0)
|
||||||
|
|
||||||
|
[node name="CameraPivot" type="Node3D" parent="CameraAnchor" unique_id=794640520]
|
||||||
|
physics_interpolation_mode = 1
|
||||||
|
|
||||||
|
[node name="SpringArm" type="SpringArm3D" parent="CameraAnchor/CameraPivot" unique_id=1399441728]
|
||||||
|
shape = SubResource("CapsuleShape3D_673rh")
|
||||||
|
spring_length = 2.0
|
||||||
|
margin = 0.1
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="CameraAnchor/CameraPivot/SpringArm" unique_id=1779046272]
|
||||||
|
far = 200000.0
|
||||||
|
|
||||||
|
[node name="GripDetector" type="Area3D" parent="." unique_id=734413990]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1)
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 32768
|
||||||
|
monitorable = false
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="GripDetector" unique_id=1939219836]
|
||||||
|
shape = SubResource("SphereShape3D_gnddn")
|
||||||
|
|
||||||
|
[node name="ZeroGMovementComponent" type="Node3D" parent="." unique_id=594953523]
|
||||||
|
script = ExtResource("4_8jhjh")
|
||||||
|
metadata/_custom_type_script = "uid://y3vo40i16ek3"
|
||||||
|
|
||||||
|
[node name="EVAMovementComponent" parent="." unique_id=1806288315 instance=ExtResource("3_gnddn")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.13939085347041424, 0.5148942200402955)
|
||||||
|
|
||||||
|
[node name="PlayerController3d" parent="." unique_id=1450011826 instance=ExtResource("4_bcy3l")]
|
||||||
|
|
||||||
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=732324183]
|
||||||
|
replication_config = SubResource("SceneReplicationConfig_gnddn")
|
||||||
@ -6,14 +6,18 @@ class_name EVAMovementComponent
|
|||||||
var pawn: CharacterPawn3D
|
var pawn: CharacterPawn3D
|
||||||
|
|
||||||
## EVA Parameters (Moved from ZeroGPawn)
|
## EVA Parameters (Moved from ZeroGPawn)
|
||||||
@export var orientation_speed: float = 2.0 # Used for orienting body to camera
|
@export var orientation_speed: float = 1.0 # Used for orienting body to camera
|
||||||
@export var move_speed: float = 2.0
|
@export var linear_acceleration: float = 1.0
|
||||||
@export var roll_torque: float = 2.5
|
@export var roll_torque_acceleration: float = 0.25
|
||||||
@export var angular_damping: float = 0.95 # Base damping applied by pawn, suit might add more?
|
@export var angular_damping: float = 0.95 # Base damping applied by pawn, suit might add more?
|
||||||
@export var inertia_multiplier: float = 1.0 # How much the suit adds to pawn's base inertia (placeholder)
|
@export var inertia_multiplier: float = 1.0 # How much the suit adds to pawn's base inertia (placeholder)
|
||||||
@export var stabilization_kp: float = 5.0
|
@export var stabilization_kp: float = 5.0
|
||||||
@export var stabilization_kd: float = 1.0
|
@export var stabilization_kd: float = 1.0
|
||||||
|
|
||||||
|
var _auto_orient_target: Basis = Basis() # Stores the target orientation
|
||||||
|
var _is_auto_orienting: bool = false # Flag to signal the pawn
|
||||||
|
@export var auto_orient_stop_velocity_threshold: float = 0.01 # (in rad/s)
|
||||||
|
|
||||||
## State
|
## State
|
||||||
var stabilization_target: Node3D = null
|
var stabilization_target: Node3D = null
|
||||||
var stabilization_enabled: bool = false
|
var stabilization_enabled: bool = false
|
||||||
@ -23,54 +27,21 @@ func _ready():
|
|||||||
if not pawn:
|
if not pawn:
|
||||||
printerr("EVAMovementComponent must be a child of a CharacterBody3D pawn.")
|
printerr("EVAMovementComponent must be a child of a CharacterBody3D pawn.")
|
||||||
return
|
return
|
||||||
# Make sure the paths match your CharacterPawn scene structure
|
|
||||||
# if camera_anchor:
|
|
||||||
# camera = camera_anchor.get_node_or_null("SpringArm/Camera3D") # Adjusted path for SpringArm
|
|
||||||
|
|
||||||
# if not camera_anchor or not camera:
|
## Called by Pawn's _integrate_forces when suit equipped
|
||||||
# printerr("EVAMovementComponent could not find CameraPivot/SpringArm/Camera3D on pawn.")
|
func process_eva_movement(state: PhysicsDirectBodyState3D, move_input: Vector2, vertical_input: float, roll_input: float, orienting_input: PlayerController3D.KeyInput):
|
||||||
|
# --- 1. Handle Orient Input ---
|
||||||
|
if orienting_input.pressed or orienting_input.held:
|
||||||
|
_set_auto_orient_target(state)
|
||||||
|
|
||||||
# --- Standardized Movement API ---
|
_process_auto_orientation(state) # [Function 2] Run the controller
|
||||||
|
|
||||||
## Called by Pawn's _physics_process when in FLOATING state with suit equipped
|
|
||||||
func process_movement(delta: float, move_input: Vector2, vertical_input: float, roll_input: float, orienting_input: PlayerController3D.KeyInput):
|
|
||||||
var orienting = orienting_input.held
|
|
||||||
if not is_instance_valid(pawn): return
|
|
||||||
if orienting:
|
|
||||||
_orient_pawn(delta)
|
|
||||||
|
|
||||||
# Check if stabilization is active and handle it first
|
# Check if stabilization is active and handle it first
|
||||||
if stabilization_enabled and is_instance_valid(stabilization_target):
|
if stabilization_enabled and is_instance_valid(stabilization_target):
|
||||||
_apply_stabilization_torques(delta)
|
_apply_stabilization_torques(state)
|
||||||
else:
|
else:
|
||||||
# Apply regular movement/torque only if not stabilizing
|
# Apply regular movement/torque only if not stabilizing
|
||||||
_apply_floating_movement(delta, move_input, vertical_input, roll_input)
|
_apply_floating_movement(state, move_input, vertical_input, roll_input)
|
||||||
|
|
||||||
func apply_thrusters(pawn: CharacterPawn3D, delta: float, move_input: Vector2, vertical_input: float, roll_input: float):
|
|
||||||
if not is_instance_valid(pawn): return
|
|
||||||
|
|
||||||
# Apply Linear Velocity
|
|
||||||
var pawn_forward = -pawn.global_basis.z
|
|
||||||
var pawn_right = pawn.global_basis.x
|
|
||||||
var pawn_up = pawn.global_basis.y
|
|
||||||
var move_dir_horizontal = (pawn_forward * move_input.y + pawn_right * move_input.x)
|
|
||||||
var move_dir_vertical = pawn_up * vertical_input
|
|
||||||
var combined_move_dir = move_dir_horizontal + move_dir_vertical
|
|
||||||
|
|
||||||
if combined_move_dir != Vector3.ZERO:
|
|
||||||
pawn.velocity += combined_move_dir.normalized() * move_speed * delta
|
|
||||||
|
|
||||||
# Apply Roll Torque
|
|
||||||
var roll_torque_global = -pawn.global_basis.z * (roll_input) * roll_torque # Sign fixed
|
|
||||||
pawn.add_torque(roll_torque_global, delta)
|
|
||||||
|
|
||||||
## Called by Pawn to handle collision response in FLOATING state
|
|
||||||
func handle_collision(collision: KinematicCollision3D, collision_energy_loss: float):
|
|
||||||
if not is_instance_valid(pawn): return
|
|
||||||
var surface_normal = collision.get_normal()
|
|
||||||
var reflected_velocity = pawn.velocity.bounce(surface_normal)
|
|
||||||
reflected_velocity *= (1.0 - collision_energy_loss)
|
|
||||||
pawn.velocity = reflected_velocity # Update pawn's velocity directly
|
|
||||||
|
|
||||||
## Called by Pawn when entering FLOATING state with suit
|
## Called by Pawn when entering FLOATING state with suit
|
||||||
func on_enter_state():
|
func on_enter_state():
|
||||||
@ -84,78 +55,67 @@ func on_exit_state():
|
|||||||
|
|
||||||
# --- Internal Logic ---
|
# --- Internal Logic ---
|
||||||
|
|
||||||
func _apply_floating_movement(delta: float, move_input: Vector2, vertical_input: float, roll_input: float):
|
func _apply_floating_movement(state: PhysicsDirectBodyState3D, move_input: Vector2, vertical_input: float, roll_input: float):
|
||||||
# Apply Linear Velocity
|
# Apply Linear Velocity
|
||||||
var pawn_forward = -pawn.global_basis.z
|
var move_dir_horizontal = (-state.transform.basis.z * move_input.y + state.transform.basis.x * move_input.x)
|
||||||
var pawn_right = pawn.global_basis.x # Use pawn's right for consistency
|
var move_dir_vertical = state.transform.basis.y * vertical_input
|
||||||
var pawn_up = pawn.global_basis.y
|
|
||||||
var move_dir_horizontal = (pawn_forward * move_input.y + pawn_right * move_input.x)
|
|
||||||
var move_dir_vertical = pawn_up * vertical_input
|
|
||||||
var combined_move_dir = move_dir_horizontal + move_dir_vertical
|
var combined_move_dir = move_dir_horizontal + move_dir_vertical
|
||||||
|
|
||||||
if combined_move_dir != Vector3.ZERO:
|
if combined_move_dir != Vector3.ZERO:
|
||||||
pawn.velocity += combined_move_dir.normalized() * move_speed * delta
|
state.apply_central_force(combined_move_dir.normalized() * linear_acceleration)
|
||||||
|
|
||||||
# --- Apply Roll Torque ---
|
# --- Apply Roll Torque ---
|
||||||
# Calculate torque magnitude based on input
|
# Calculate torque magnitude based on input
|
||||||
var roll_torque_vector = pawn.transform.basis.z * (-roll_input) * roll_torque
|
if roll_input != 0.0:
|
||||||
|
_is_auto_orienting = false # Cancel auto-orientation if rolling manually
|
||||||
|
|
||||||
# Apply the global torque vector using the pawn's helper function
|
var roll_acceleration = state.transform.basis.z * (-roll_input) * roll_torque_acceleration
|
||||||
pawn.add_torque(roll_torque_vector, delta)
|
# Apply the global torque vector using the pawn's helper function
|
||||||
|
state.apply_torque(roll_acceleration)
|
||||||
|
|
||||||
|
func _set_auto_orient_target(state: PhysicsDirectBodyState3D):
|
||||||
|
# Set the target to where the camera is currently looking
|
||||||
|
var target_forward = - pawn.camera_anchor.global_basis.z # Look where camera looks
|
||||||
|
var target_up = state.transform.basis.y
|
||||||
|
_auto_orient_target = Basis.looking_at(target_forward, target_up)
|
||||||
|
_is_auto_orienting = true # Start the orientation process
|
||||||
|
|
||||||
# --- Auto-Orientation Logic ---
|
# --- Auto-Orientation Logic ---
|
||||||
func _orient_pawn(delta: float):
|
func _process_auto_orientation(state: PhysicsDirectBodyState3D):
|
||||||
# 1. Determine Target Orientation Basis
|
# This function runs every physics frame
|
||||||
var initial_cam_basis = pawn.camera_anchor.global_basis
|
if not _is_auto_orienting:
|
||||||
var target_forward = -pawn.camera_anchor.global_basis.z # Look where camera looks
|
return # Not orienting, do nothing
|
||||||
var target_up = Vector3.UP # Default up initially
|
|
||||||
|
|
||||||
# --- THE FIX: Adjust how target_up is calculated ---
|
# 2. Calculate Torque using PD Controller
|
||||||
# Calculate velocity components relative to camera orientation
|
var torque = MotionUtils.calculate_pd_rotation_torque(
|
||||||
var _forward_velocity_component = pawn.velocity.dot(target_forward)
|
_auto_orient_target,
|
||||||
var _right_velocity_component = pawn.velocity.dot(pawn.camera_anchor.global_basis.x)
|
state.transform.basis,
|
||||||
|
state.angular_velocity, # Read from state
|
||||||
|
orientation_speed, # Kp
|
||||||
|
2 * sqrt(orientation_speed) # Kd (Critically Damped)
|
||||||
|
)
|
||||||
|
|
||||||
# Only apply strong "feet trailing" if significant forward/backward movement dominates
|
# 2. Apply the torque to the physics state
|
||||||
# and we are actually moving.
|
state.apply_torque(torque)
|
||||||
#if abs(forward_velocity_component) > abs(right_velocity_component) * 0.5 and velocity.length_squared() > 0.1:
|
|
||||||
#target_up = -velocity.normalized()
|
# 3. Check for stop condition
|
||||||
## Orthogonalize to prevent basis skew
|
var ang_vel_mag = state.angular_velocity.length()
|
||||||
#var target_right = target_up.cross(target_forward).normalized()
|
var axis = state.angular_velocity.normalized()
|
||||||
## If vectors are parallel, cross product is zero. Fallback needed.
|
|
||||||
#if target_right.is_zero_approx():
|
|
||||||
#target_up = transform.basis.y # Fallback to current up
|
|
||||||
#else:
|
|
||||||
#target_up = target_forward.cross(target_right).normalized()
|
|
||||||
#else:
|
|
||||||
## If primarily strafing or stationary relative to forward,
|
|
||||||
## maintain the current body's roll orientation (its local Y-axis).
|
|
||||||
target_up = pawn.transform.basis.y
|
|
||||||
|
|
||||||
# Create the target basis
|
# If we are close enough AND slow enough, stop.
|
||||||
var target_basis = Basis.looking_at(target_forward, target_up)
|
if ang_vel_mag < auto_orient_stop_velocity_threshold:
|
||||||
|
_is_auto_orienting = false
|
||||||
|
_auto_orient_target = pawn.global_basis # Set target to current for next time
|
||||||
|
|
||||||
|
if axis.is_normalized():
|
||||||
|
var physics_rotation = Basis().rotated(axis, ang_vel_mag * state.step)
|
||||||
|
|
||||||
|
pawn.camera_anchor.transform.basis = physics_rotation.inverse() * pawn.camera_anchor.transform.basis
|
||||||
|
|
||||||
# Optional Pitch Offset (Experimental):
|
|
||||||
# Apply the desired 70-degree pitch relative to the forward direction
|
|
||||||
# var target_pitch_rad = deg_to_rad(target_body_pitch_degrees)
|
|
||||||
# target_basis = target_basis.rotated(target_basis.x, target_pitch_rad) # Rotate around the target right vector
|
|
||||||
|
|
||||||
# 2. Smoothly Interpolate Towards Target Basis
|
|
||||||
var current_basis = pawn.global_basis
|
|
||||||
var new_basis = current_basis.slerp(target_basis, delta * orientation_speed).get_rotation_quaternion()
|
|
||||||
|
|
||||||
# Store the body's yaw *before* applying the new basis
|
|
||||||
var _old_body_yaw = current_basis.get_euler().y
|
|
||||||
var _old_body_pitch = current_basis.get_euler().x
|
|
||||||
|
|
||||||
# 3. Apply the new orientation
|
|
||||||
pawn.global_basis = new_basis
|
|
||||||
|
|
||||||
# 4. Reset camera pivot to rotation to what it was before we rotated the parent
|
|
||||||
pawn.camera_anchor.global_basis = initial_cam_basis
|
|
||||||
|
|
||||||
# --- Add new function placeholder ---
|
# --- Add new function placeholder ---
|
||||||
# TODO: Implement Rotation Stabilization Logic
|
# TODO: Implement Rotation Stabilization Logic
|
||||||
func _apply_stabilization_torques(_delta: float):
|
func _apply_stabilization_torques(_state: PhysicsDirectBodyState3D):
|
||||||
if not is_instance_valid(stabilization_target):
|
if not is_instance_valid(stabilization_target):
|
||||||
stabilization_enabled = false
|
stabilization_enabled = false
|
||||||
return
|
return
|
||||||
@ -176,7 +136,7 @@ func _apply_stabilization_torques(_delta: float):
|
|||||||
# - Proportional Term (based on orientation error): P = rotational_error * stabilization_kp
|
# - Proportional Term (based on orientation error): P = rotational_error * stabilization_kp
|
||||||
# - Derivative Term (based on relative spin): D = relative_angular_velocity * stabilization_kd
|
# - Derivative Term (based on relative spin): D = relative_angular_velocity * stabilization_kd
|
||||||
# - Required Torque = -(P + D) # Negative to counteract error/spin
|
# - Required Torque = -(P + D) # Negative to counteract error/spin
|
||||||
var required_torque = -(rotational_error * stabilization_kp + relative_angular_velocity * stabilization_kd)
|
var required_torque = - (rotational_error * stabilization_kp + relative_angular_velocity * stabilization_kd)
|
||||||
|
|
||||||
print("Applying stabilization torque: ", required_torque)
|
print("Applying stabilization torque: ", required_torque)
|
||||||
# 4. Convert Required Torque into Thruster Actions:
|
# 4. Convert Required Torque into Thruster Actions:
|
||||||
@ -186,7 +146,27 @@ func _apply_stabilization_torques(_delta: float):
|
|||||||
# - Apply the forces/torques (similar to how _apply_floating_movement applies roll torque).
|
# - Apply the forces/torques (similar to how _apply_floating_movement applies roll torque).
|
||||||
# Example (highly simplified, assumes direct torque application possible):
|
# Example (highly simplified, assumes direct torque application possible):
|
||||||
|
|
||||||
# angular_velocity += (required_torque / inertia) * delta
|
|
||||||
|
# --- Old logic for feet trailing (commented out) ---
|
||||||
|
# --- THE FIX: Adjust how target_up is calculated ---
|
||||||
|
# Calculate velocity components relative to camera orientation
|
||||||
|
# var _forward_velocity_component = pawn.velocity.dot(target_forward)
|
||||||
|
# var _right_velocity_component = pawn.velocity.dot(pawn.camera_anchor.global_basis.x)
|
||||||
|
|
||||||
|
# Only apply strong "feet trailing" if significant forward/backward movement dominates
|
||||||
|
# and we are actually moving.
|
||||||
|
#if abs(forward_velocity_component) > abs(right_velocity_component) * 0.5 and velocity.length_squared() > 0.1:
|
||||||
|
#target_up = -velocity.normalized()
|
||||||
|
## Orthogonalize to prevent basis skew
|
||||||
|
#var target_right = target_up.cross(target_forward).normalized()
|
||||||
|
## If vectors are parallel, cross product is zero. Fallback needed.
|
||||||
|
#if target_right.is_zero_approx():
|
||||||
|
#target_up = transform.basis.y # Fallback to current up
|
||||||
|
#else:
|
||||||
|
#target_up = target_forward.cross(target_right).normalized()
|
||||||
|
#else:
|
||||||
|
## If primarily strafing or stationary relative to forward,
|
||||||
|
## maintain the current body's roll orientation (its local Y-axis).
|
||||||
|
|
||||||
# --- Add methods for enabling/disabling stabilization, setting target etc. ---
|
# --- Add methods for enabling/disabling stabilization, setting target etc. ---
|
||||||
func set_stabilization_enabled(enable: bool):
|
func set_stabilization_enabled(enable: bool):
|
||||||
12
src/scenes/character/eva_suit_controller.tscn
Normal file
12
src/scenes/character/eva_suit_controller.tscn
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://bm1rbv4tuppbc"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://d4jka2etva22s" path="res://scenes/character/eva_movement_component.gd" id="1_mb22m"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_rlk1u"]
|
||||||
|
size = Vector3(1, 1, 0.4)
|
||||||
|
|
||||||
|
[node name="EVASuitController" type="Node3D" unique_id=241443807]
|
||||||
|
script = ExtResource("1_mb22m")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=1434211019]
|
||||||
|
mesh = SubResource("BoxMesh_rlk1u")
|
||||||
@ -8,6 +8,7 @@ class_name PlayerController3D
|
|||||||
@export var mouse_sensitivity: float = 0.002 # Radians per pixel motion
|
@export var mouse_sensitivity: float = 0.002 # Radians per pixel motion
|
||||||
var _mouse_motion_input: Vector2 = Vector2.ZERO
|
var _mouse_motion_input: Vector2 = Vector2.ZERO
|
||||||
|
|
||||||
|
|
||||||
class KeyInput:
|
class KeyInput:
|
||||||
var pressed: bool = false
|
var pressed: bool = false
|
||||||
var held: bool = false
|
var held: bool = false
|
||||||
@ -18,9 +19,26 @@ class KeyInput:
|
|||||||
held = _h
|
held = _h
|
||||||
released = _r
|
released = _r
|
||||||
|
|
||||||
|
func _to_dict():
|
||||||
|
return {
|
||||||
|
"pressed": pressed,
|
||||||
|
"held": held,
|
||||||
|
"released": released
|
||||||
|
}
|
||||||
|
|
||||||
|
static func from_dict(dict: Dictionary) -> KeyInput:
|
||||||
|
return KeyInput.new(dict.get("pressed", false), dict.get("held", false), dict.get("released", false))
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
# If we are spawned dynamically, the owner_id might be set by GameManager.
|
||||||
|
# Fallback: assume the pawn's name is the player ID (common pattern).
|
||||||
|
if get_parent().name.is_valid_int():
|
||||||
|
set_multiplayer_authority(int(get_parent().name))
|
||||||
|
|
||||||
func _unhandled_input(event: InputEvent):
|
func _unhandled_input(event: InputEvent):
|
||||||
|
|
||||||
|
# Check if THIS client is the owner of this controller
|
||||||
if not is_multiplayer_authority() or not is_instance_valid(possessed_pawn):
|
if not is_multiplayer_authority() or not is_instance_valid(possessed_pawn):
|
||||||
# print("Peer ID: %s, Node Authority: %s" % [multiplayer.get_unique_id(), get_multiplayer_authority()])
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Handle mouse motion input directly here
|
# Handle mouse motion input directly here
|
||||||
@ -28,6 +46,7 @@ func _unhandled_input(event: InputEvent):
|
|||||||
_mouse_motion_input += Vector2(event.relative.x, -event.relative.y)
|
_mouse_motion_input += Vector2(event.relative.x, -event.relative.y)
|
||||||
|
|
||||||
func _physics_process(_delta):
|
func _physics_process(_delta):
|
||||||
|
# Check if THIS client is the owner
|
||||||
if not is_multiplayer_authority() or not is_instance_valid(possessed_pawn):
|
if not is_multiplayer_authority() or not is_instance_valid(possessed_pawn):
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -36,7 +55,7 @@ func _physics_process(_delta):
|
|||||||
var sensitivity_modified_mouse_input = Vector2(_mouse_motion_input.x, _mouse_motion_input.y) * mouse_sensitivity
|
var sensitivity_modified_mouse_input = Vector2(_mouse_motion_input.x, _mouse_motion_input.y) * mouse_sensitivity
|
||||||
|
|
||||||
# Send rotation input via RPC immediately
|
# Send rotation input via RPC immediately
|
||||||
server_process_rotation_input.rpc_id(multiplayer.get_unique_id(), sensitivity_modified_mouse_input)
|
server_process_rotation_input.rpc_id(1, sensitivity_modified_mouse_input)
|
||||||
|
|
||||||
# Reset the buffer
|
# Reset the buffer
|
||||||
_mouse_motion_input = Vector2.ZERO
|
_mouse_motion_input = Vector2.ZERO
|
||||||
@ -50,29 +69,29 @@ func _physics_process(_delta):
|
|||||||
var l_input = KeyInput.new(Input.is_action_just_pressed("left_click"), Input.is_action_pressed("left_click"), Input.is_action_just_released("left_click"))
|
var l_input = KeyInput.new(Input.is_action_just_pressed("left_click"), Input.is_action_pressed("left_click"), Input.is_action_just_released("left_click"))
|
||||||
var r_input = KeyInput.new(Input.is_action_just_pressed("right_click"), Input.is_action_pressed("right_click"), Input.is_action_just_released("right_click"))
|
var r_input = KeyInput.new(Input.is_action_just_pressed("right_click"), Input.is_action_pressed("right_click"), Input.is_action_just_released("right_click"))
|
||||||
|
|
||||||
server_process_movement_input.rpc_id(multiplayer.get_unique_id(), move_vec, roll_input, vertical_input)
|
server_process_movement_input.rpc_id(1, move_vec, roll_input, vertical_input)
|
||||||
server_process_interaction_input.rpc_id(multiplayer.get_unique_id(), interact_input)
|
server_process_interaction_input.rpc_id(1, interact_input._to_dict())
|
||||||
server_process_clicks.rpc_id(multiplayer.get_unique_id(), l_input, r_input)
|
server_process_clicks.rpc_id(1, l_input._to_dict(), r_input._to_dict())
|
||||||
|
|
||||||
@rpc("authority", "call_local")
|
@rpc("any_peer", "call_local")
|
||||||
func server_process_movement_input(move: Vector2, roll: float, vertical: float):
|
func server_process_movement_input(move: Vector2, roll: float, vertical: float):
|
||||||
if is_instance_valid(possessed_pawn):
|
if is_instance_valid(possessed_pawn):
|
||||||
possessed_pawn.set_movement_input(move, roll, vertical)
|
possessed_pawn.set_movement_input(move, roll, vertical)
|
||||||
|
|
||||||
@rpc("authority", "call_local")
|
@rpc("any_peer", "call_local")
|
||||||
func server_process_interaction_input(interact_input: KeyInput):
|
func server_process_interaction_input(interact_input: Dictionary):
|
||||||
if is_instance_valid(possessed_pawn):
|
if is_instance_valid(possessed_pawn):
|
||||||
possessed_pawn.set_interaction_input(interact_input)
|
possessed_pawn.set_interaction_input(KeyInput.from_dict(interact_input))
|
||||||
|
|
||||||
@rpc("authority", "call_local")
|
@rpc("any_peer", "call_local")
|
||||||
func server_process_rotation_input(input: Vector2):
|
func server_process_rotation_input(input: Vector2):
|
||||||
if is_instance_valid(possessed_pawn):
|
if is_instance_valid(possessed_pawn):
|
||||||
possessed_pawn.set_rotation_input(input)
|
possessed_pawn.set_rotation_input(input)
|
||||||
|
|
||||||
@rpc("authority", "call_local")
|
@rpc("any_peer", "call_local")
|
||||||
func server_process_clicks(l_action: KeyInput, r_action: KeyInput):
|
func server_process_clicks(l_action: Dictionary, r_action: Dictionary):
|
||||||
if is_instance_valid(possessed_pawn):
|
if is_instance_valid(possessed_pawn):
|
||||||
possessed_pawn.set_click_input(l_action, r_action)
|
possessed_pawn.set_click_input(KeyInput.from_dict(l_action), KeyInput.from_dict(r_action))
|
||||||
|
|
||||||
func possess(pawn_to_control: CharacterPawn3D):
|
func possess(pawn_to_control: CharacterPawn3D):
|
||||||
possessed_pawn = pawn_to_control
|
possessed_pawn = pawn_to_control
|
||||||
@ -87,7 +106,7 @@ func _notification(what):
|
|||||||
NOTIFICATION_WM_WINDOW_FOCUS_IN:
|
NOTIFICATION_WM_WINDOW_FOCUS_IN:
|
||||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||||
NOTIFICATION_EXIT_TREE:
|
NOTIFICATION_EXIT_TREE:
|
||||||
print("PlayerController %s exited tree" % multiplayer.get_unique_id())
|
print("PlayerController exited tree")
|
||||||
NOTIFICATION_ENTER_TREE:
|
NOTIFICATION_ENTER_TREE:
|
||||||
print("PlayerController %s entered tree" % multiplayer.get_unique_id())
|
print("PlayerController %s entered tree" % multiplayer.get_unique_id())
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user