Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 75fb76ef03 |
@@ -5,11 +5,6 @@ on:
|
||||
branches: [release]
|
||||
pull_request:
|
||||
branches: [release]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dummy:
|
||||
description: "Dry Run — tests the build process without creating a release"
|
||||
required: false
|
||||
|
||||
env:
|
||||
GODOT_VERSION: 4.6.1
|
||||
@@ -18,32 +13,16 @@ env:
|
||||
BLENDER_VERSION: 5.0.0
|
||||
|
||||
jobs:
|
||||
export:
|
||||
name: ${{ matrix.name }} Export
|
||||
runs-on: ubuntu-24.04
|
||||
export-windows:
|
||||
name: Windows Export
|
||||
runs-on: ubuntu-24.04 # Use 24.04 with godot 4
|
||||
container: barichello/godot-ci:4.6
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- name: Windows
|
||||
godot_preset: "Windows"
|
||||
artifact_name: windows
|
||||
output_ext: ".exe"
|
||||
install_blender: true
|
||||
- name: Linux
|
||||
godot_preset: "Linux/X11"
|
||||
artifact_name: linux
|
||||
output_ext: ".x86_64"
|
||||
install_blender: true
|
||||
|
||||
steps:
|
||||
- name: Update and install dependencies
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y curl gnupg
|
||||
if [ "${{ matrix.install_blender }}" = "true" ]; then
|
||||
apt-get install -y blender
|
||||
fi
|
||||
apt-get install -y blender
|
||||
|
||||
- name: Install Node.js
|
||||
run: |
|
||||
@@ -69,36 +48,96 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set the Blender path
|
||||
if [ -n "${BLENDER_PATH:-}" ]; then
|
||||
if grep -q '^filesystem/import/blender/blender_path' "$GODOT_CFG"; then
|
||||
# Replace existing path
|
||||
sed -i "s|^filesystem/import/blender/blender_path = .*|filesystem/import/blender/blender_path = \"$BLENDER_PATH\"|" "$GODOT_CFG"
|
||||
else
|
||||
# Append new path
|
||||
echo "filesystem/import/blender/blender_path = \"$BLENDER_PATH\"" >> "$GODOT_CFG"
|
||||
fi
|
||||
fi
|
||||
echo "Blender path configured in $GODOT_CFG"
|
||||
|
||||
- name: Build
|
||||
- name: Windows Build
|
||||
shell: bash
|
||||
run: |
|
||||
set -Eeuo pipefail
|
||||
mkdir -v -p build/${{ matrix.artifact_name }}
|
||||
mkdir -v -p build/windows
|
||||
EXPORT_DIR="$(readlink -f build)"
|
||||
cd $PROJECT_PATH
|
||||
godot --headless --export-release "${{ matrix.godot_preset }}" \
|
||||
"$EXPORT_DIR/${{ matrix.artifact_name }}/$EXPORT_NAME${{ matrix.output_ext }}"
|
||||
godot --headless --export-release "Windows" "$EXPORT_DIR/windows/$EXPORT_NAME.exe"
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows
|
||||
path: build/windows
|
||||
|
||||
export-linux:
|
||||
name: Linux Export
|
||||
runs-on: ubuntu-24.04 # Use 24.04 with godot 4
|
||||
container: barichello/godot-ci:4.6
|
||||
steps:
|
||||
- name: Update and install dependencies
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y curl gnupg
|
||||
|
||||
- name: Install Node.js
|
||||
run: |
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
||||
apt-get install -y nodejs
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
lfs: true
|
||||
- name: Setup
|
||||
shell: bash
|
||||
run: |
|
||||
set -Eeuo pipefail
|
||||
BLENDER_PATH="/usr/bin/blender"
|
||||
mkdir -pv ~/.config/godot
|
||||
mkdir -pv ~/.local/share/godot/export_templates/
|
||||
GODOT_CFG="$(find ~/.config/godot -name "editor_settings-*.tres" | head -n 1 || true)"
|
||||
|
||||
if [ -z "$GODOT_CFG" ]; then
|
||||
echo "# Missing Godot editor settings" > "$GODOT_CFG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set the Blender path
|
||||
if [ -n "${BLENDER_PATH:-}" ]; then
|
||||
if grep -q '^filesystem/import/blender/blender_path' "$GODOT_CFG"; then
|
||||
# Replace existing path
|
||||
sed -i "s|^filesystem/import/blender/blender_path = .*|filesystem/import/blender/blender_path = \"$BLENDER_PATH\"|" "$GODOT_CFG"
|
||||
else
|
||||
# Append new path
|
||||
echo "filesystem/import/blender/blender_path = \"$BLENDER_PATH\"" >> "$GODOT_CFG"
|
||||
fi
|
||||
fi
|
||||
echo "Blender path configured in $GODOT_CFG"
|
||||
|
||||
- name: Linux Build
|
||||
shell: bash
|
||||
run: |
|
||||
set -Eeuo pipefail
|
||||
mkdir -v -p build/linux
|
||||
EXPORT_DIR="$(readlink -f build)"
|
||||
cd $PROJECT_PATH
|
||||
godot --headless --export-release "Linux/X11" "$EXPORT_DIR/linux/$EXPORT_NAME.x86_64"
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.artifact_name }}
|
||||
path: build/${{ matrix.artifact_name }}
|
||||
name: linux
|
||||
path: build/linux
|
||||
|
||||
create-release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: [export]
|
||||
if: github.event_name == 'push'
|
||||
needs: [export-linux, export-windows]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -118,6 +157,7 @@ jobs:
|
||||
- name: Extract version and body from CHANGELOG
|
||||
id: changelog
|
||||
run: |
|
||||
# Extract the latest released version (skip Unreleased)
|
||||
LATEST=$(grep -E '^## \[[0-9]+\.[0-9]+\.[0-9]+\]' CHANGELOG.md | head -n1 | sed -E 's/^## \[([0-9]+\.[0-9]+\.[0-9]+)\].*/\1/')
|
||||
|
||||
if [ -z "$LATEST" ]; then
|
||||
@@ -128,14 +168,17 @@ jobs:
|
||||
echo "Released version found: $LATEST"
|
||||
echo "version=$LATEST" >> $GITHUB_OUTPUT
|
||||
|
||||
# Extract the body: lines until the next ## header
|
||||
BODY=$(awk -v ver="$LATEST" '
|
||||
$0 ~ "^## \\[" ver "\\]" {found=1; next}
|
||||
found && $0 ~ "^## \\[" {exit}
|
||||
found {print}
|
||||
' CHANGELOG.md)
|
||||
|
||||
# Trim leading/trailing empty lines
|
||||
BODY=$(echo "$BODY" | sed '/^\s*$/d')
|
||||
|
||||
# Output body safely for GitHub Actions
|
||||
echo "body<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "$BODY" >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Godot 4+ specific ignores
|
||||
.idea/
|
||||
.godot/
|
||||
/android/
|
||||
/dist/
|
||||
|
||||
@@ -1,496 +0,0 @@
|
||||
# Aurora 4X — Godot 4.6.2 Remake
|
||||
## Game Design Document & Developer Preparation
|
||||
|
||||
> **Status:** Pre-production / Architecture phase
|
||||
> **Engine:** Godot 4.6.2
|
||||
> **Genre:** Real-time 4X Space Strategy with time scaling
|
||||
> **Reference:** [Aurora 4X](https://aurora4x.com) by AuroraSteve
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Game Vision](#1-game-vision)
|
||||
2. [Core Gameplay Loop](#2-core-gameplay-loop)
|
||||
3. [Time System Design](#3-time-system-design)
|
||||
4. [Resource System Design](#4-resource-system-design)
|
||||
5. [Planet & Body Design](#5-planet--body-design)
|
||||
6. [Mining System Design](#6-mining-system-design)
|
||||
7. [Architecture Overview](#7-architecture-overview)
|
||||
8. [Threading Model](#8-threading-model)
|
||||
9. [Class Reference](#9-class-reference)
|
||||
10. [Developer Checklist](#10-developer-checklist)
|
||||
11. [Open Questions](#11-open-questions)
|
||||
|
||||
---
|
||||
|
||||
## 1. Game Vision
|
||||
|
||||
A faithful real-time reimagining of Aurora 4X in Godot 4. The goal is to preserve Aurora's depth — procedural star systems, mineral economics, ship design, exploration, and diplomacy — while modernizing the experience with a proper real-time engine, time scaling, and a cleaner UI.
|
||||
|
||||
**Design pillars:**
|
||||
- **Depth over accessibility** — Aurora's complexity is a feature, not a flaw
|
||||
- **Simulation integrity** — the numbers must hold up at any time scale
|
||||
- **Modular systems** — each simulation domain (economy, combat, diplomacy) is isolated and independently tickable
|
||||
- **Performance budget awareness** — late-game with dozens of colonies and hundreds of ships must remain playable
|
||||
|
||||
---
|
||||
|
||||
## 2. Core Gameplay Loop
|
||||
|
||||
```
|
||||
Explore star systems
|
||||
→ Survey planets and bodies for minerals
|
||||
→ Colonize and deploy mines
|
||||
→ Extract minerals → Build ships & installations
|
||||
→ Expand to new systems
|
||||
→ Encounter alien races → Diplomacy or War
|
||||
→ Repeat at larger scale
|
||||
```
|
||||
|
||||
**Key differences from the original Aurora:**
|
||||
- Real-time instead of turn-based increments
|
||||
- Time scaling (1x → 64x+) replaces "advance X days" buttons
|
||||
- Visual star map and orbit rendering instead of text tables
|
||||
- Event-driven pause system (game pauses automatically on important events)
|
||||
|
||||
---
|
||||
|
||||
## 3. Time System Design
|
||||
|
||||
### Philosophy
|
||||
|
||||
All simulation math is **rate-based**, not tick-based. This means:
|
||||
- Mining produces X tons **per second** rather than X tons **per turn**
|
||||
- Any system consuming time receives a `scaled_delta` (real delta × time scale)
|
||||
- At 64x, `scaled_delta` is simply 64× larger — no special casing anywhere
|
||||
|
||||
### Time Scale Ladder
|
||||
|
||||
| Level | Scale | Use Case |
|
||||
|-------|-------|----------|
|
||||
| 1 | 1× | Combat, diplomacy, precision decisions |
|
||||
| 2 | 2× | Routine fleet movement |
|
||||
| 3 | 4× | Short transit legs |
|
||||
| 4 | 8× | Long transit legs |
|
||||
| 5 | 16× | Waiting for construction |
|
||||
| 6 | 32× | Long colonization phases |
|
||||
| 7 | 64× | Early game exploration stretches |
|
||||
| 8+ | 128×+ | Optional / player settings |
|
||||
|
||||
### Auto-Pause Events
|
||||
|
||||
The game automatically drops to paused when:
|
||||
- A mineral deposit is fully depleted
|
||||
- An unknown contact appears on sensors
|
||||
- A construction order completes
|
||||
- A ship takes damage
|
||||
- A diplomatic message is received
|
||||
- A colony falls below minimum supply threshold
|
||||
|
||||
### `GameClock` — Autoload
|
||||
|
||||
Single source of truth for all time in the game. Nothing reads `delta` directly — everything calls `GameClock.get_scaled_delta(delta)`.
|
||||
|
||||
```gdscript
|
||||
# Autoload: GameClock
|
||||
const SCALES: Array[float] = [1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0]
|
||||
|
||||
var time_scale: float = 1.0
|
||||
var paused: bool = false
|
||||
var elapsed_game_time: float = 0.0 # total in-game seconds
|
||||
|
||||
func get_scaled_delta(delta: float) -> float
|
||||
func set_scale(scale: float) -> void
|
||||
func toggle_pause() -> void
|
||||
func faster() -> void
|
||||
func slower() -> void
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Resource System Design
|
||||
|
||||
### The 11 Minerals
|
||||
|
||||
Directly ported from Aurora 4X. Each has a distinct role in construction and technology.
|
||||
|
||||
| # | Mineral | Primary Use |
|
||||
|---|---------|-------------|
|
||||
| 0 | Duranium | Hull plating, construction |
|
||||
| 1 | Neutronium | Armour, advanced hulls |
|
||||
| 2 | Corbomite | Electronic components |
|
||||
| 3 | Tritanium | Engines |
|
||||
| 4 | Boronide | Power plants |
|
||||
| 5 | Mercassium | Sensors |
|
||||
| 6 | Vendarite | Weapons |
|
||||
| 7 | Sorium | Fuel (found mainly on gas giants) |
|
||||
| 8 | Uridium | Shields |
|
||||
| 9 | Corundium | Ground forces equipment |
|
||||
| 10 | Gallicite | Missile components |
|
||||
|
||||
### Deposit Properties
|
||||
|
||||
Each deposit on a body has exactly two values:
|
||||
|
||||
| Property | Range | Effect |
|
||||
|----------|-------|--------|
|
||||
| `amount` | 0 – 999,999 tons | Total remaining; depletes over time |
|
||||
| `accessibility` | 0.1 – 1.0 | Multiplier on mine output rate |
|
||||
|
||||
**Mining rate formula:**
|
||||
```
|
||||
tons_per_second = mines_assigned × accessibility
|
||||
```
|
||||
|
||||
At accessibility 1.0, one mine extracts 1 ton/sec of in-game time. At 0.1, ten mines are needed for the same throughput. These base values are tuned during balancing.
|
||||
|
||||
### Deposit Distribution by Body Type
|
||||
|
||||
Not every mineral appears on every body. Spawn probability during procedural generation:
|
||||
|
||||
| Body Type | Spawn Chance per Mineral |
|
||||
|-----------|-------------------------|
|
||||
| Rocky planet | 60% |
|
||||
| Moon | 45% |
|
||||
| Asteroid | 80% (low amount, high accessibility) |
|
||||
| Gas giant | 10% (Sorium-weighted) |
|
||||
| Comet | 25% |
|
||||
|
||||
### Survey Mechanic
|
||||
|
||||
Deposits are **hidden until surveyed**. A geological survey ship must complete a survey mission on the body before deposits appear. This preserves Aurora's exploration tension.
|
||||
|
||||
- `deposit.surveyed = false` by default
|
||||
- `get_active_deposits()` filters out unsurveyed deposits
|
||||
- Survey progress is a time-based operation (affected by time scale)
|
||||
|
||||
---
|
||||
|
||||
## 5. Planet & Body Design
|
||||
|
||||
### `PlanetBody` — Plain Class (not Node or Resource)
|
||||
|
||||
> **Critical:** `PlanetBody` must NOT extend `Resource` or `Node`. It is mutated from the economy worker thread. Plain GDScript classes are thread-safe to read/write; Godot's built-in base classes are not.
|
||||
|
||||
**Properties:**
|
||||
```
|
||||
body_name: String
|
||||
body_type: String # "Rocky", "Moon", "Gas Giant", "Asteroid", "Comet"
|
||||
gravity: float # relative to Earth (1.0)
|
||||
temperature: float # Kelvin
|
||||
deposits: Dictionary # MineralDeposit.Type (int) → MineralDeposit
|
||||
```
|
||||
|
||||
**Save/Load:** Serialized manually to JSON or a custom binary format. Do not rely on `ResourceSaver`.
|
||||
|
||||
### Body Types and Gameplay Role
|
||||
|
||||
| Type | Mining | Colonization | Notes |
|
||||
|------|--------|--------------|-------|
|
||||
| Rocky planet | Yes | Yes | Main colony targets |
|
||||
| Moon | Yes | Limited | Good early mining |
|
||||
| Asteroid | Yes | No | High accessibility, low total |
|
||||
| Gas giant | Sorium only | No | Fuel source |
|
||||
| Comet | Rare minerals | No | Worth hunting |
|
||||
|
||||
---
|
||||
|
||||
## 6. Mining System Design
|
||||
|
||||
### `MiningOperation` — One Per Colony
|
||||
|
||||
Each colonized body that has mines deployed has exactly one `MiningOperation`. It references the body and tracks the deployed mine count and local stockpile.
|
||||
|
||||
**Tick behavior:**
|
||||
1. Get all active (surveyed, non-depleted) deposits
|
||||
2. Divide `mines_deployed` evenly across active deposits
|
||||
3. Call `deposit.extract(scaled_delta, mines_share)` on each
|
||||
4. Accumulate extracted amounts into `stockpile`
|
||||
5. Collect and return any depletion events
|
||||
|
||||
**Mine allocation** (v1 — simple):
|
||||
Mines split evenly across all active deposits. Future versions can allow player-directed allocation per mineral type.
|
||||
|
||||
### Stockpile Flow
|
||||
|
||||
```
|
||||
PlanetBody deposits
|
||||
→ MiningOperation.stockpile (local buffer)
|
||||
→ Colony inventory (global pool per empire)
|
||||
→ Construction queues consume from colony inventory
|
||||
→ Freighters transport between colonies
|
||||
```
|
||||
|
||||
The local stockpile buffer means mining output doesn't instantly teleport to construction — freighters must move it, preserving Aurora's logistics gameplay.
|
||||
|
||||
---
|
||||
|
||||
## 7. Architecture Overview
|
||||
|
||||
### Node Tree (Main Scene)
|
||||
|
||||
```
|
||||
Main
|
||||
├── GameClock (Autoload)
|
||||
├── EconomyManager (Node — _process every frame)
|
||||
├── StarSystemManager (Node — owns all PlanetBody instances)
|
||||
├── FleetManager (Node)
|
||||
├── UILayer (CanvasLayer)
|
||||
│ ├── StarMap
|
||||
│ ├── ColonyPanel
|
||||
│ ├── EventLog
|
||||
│ └── TimeControls
|
||||
└── EventBus (Autoload — for cross-system signals)
|
||||
```
|
||||
|
||||
### System Boundaries
|
||||
|
||||
| System | Owns | Communicates via |
|
||||
|--------|------|-----------------|
|
||||
| EconomyManager | MiningOperations, EconomyWorker | EventBus signals |
|
||||
| StarSystemManager | PlanetBody, star layout | Direct reference |
|
||||
| FleetManager | Ship instances, movement | EventBus signals |
|
||||
| UI | Display only | Reads snapshots, listens to EventBus |
|
||||
|
||||
**Rule:** UI never writes to simulation data. It reads snapshots and sends player commands through a command queue.
|
||||
|
||||
---
|
||||
|
||||
## 8. Threading Model
|
||||
|
||||
### Why a Thread
|
||||
|
||||
At 16x–64x time scale, the economy tick can process significant simulation work per real frame. Moving it off the main thread keeps rendering and input at full frame rate regardless of simulation load.
|
||||
|
||||
### Thread Safety Rules
|
||||
|
||||
1. Only plain GDScript classes (`class_name Foo`, no `extends`) are mutated from the worker thread
|
||||
2. Never call `emit_signal()` from the worker thread — use an event queue instead
|
||||
3. Never instantiate Nodes from the worker thread
|
||||
4. Always lock the mutex before reading OR writing shared data from either thread
|
||||
5. The main thread owns the UI — the worker thread never touches display state
|
||||
|
||||
### Architecture
|
||||
|
||||
```
|
||||
Main Thread Worker Thread
|
||||
───────────────────────────────── ──────────────────────────────────
|
||||
GameClock._process(delta)
|
||||
→ EconomyManager._process(delta)
|
||||
→ worker.push_delta() ──────→ Semaphore wakes _run()
|
||||
→ worker.poll_events() ←────── _process_tick(scaled_delta)
|
||||
→ emit via EventBus for each MiningOperation:
|
||||
→ maybe pause clock deposit.extract()
|
||||
accumulate stockpile
|
||||
collect events → queue
|
||||
```
|
||||
|
||||
### `EconomyWorker` Internals
|
||||
|
||||
```
|
||||
_thread: Thread
|
||||
_semaphore: Semaphore # main posts, worker waits
|
||||
_mutex: Mutex # guards all shared state
|
||||
|
||||
_operations: Array # MiningOperation list
|
||||
_pending_delta: float # accumulated scaled delta
|
||||
_pending_events: Array # event queue (drained by main thread)
|
||||
```
|
||||
|
||||
**Delta accumulation:** If the main thread posts faster than the worker can process (unlikely but possible at extreme time scales), `_pending_delta` accumulates rather than dropping ticks. The worker drains the full accumulated delta on its next wake.
|
||||
|
||||
### Reading Data from UI
|
||||
|
||||
The UI must never read `stockpile` or deposit amounts directly without a mutex-guarded snapshot:
|
||||
|
||||
```gdscript
|
||||
# EconomyWorker — safe snapshot for UI
|
||||
func get_stockpile_snapshot(op: MiningOperation) -> Dictionary:
|
||||
_mutex.lock()
|
||||
var snapshot := op.stockpile.duplicate()
|
||||
_mutex.unlock()
|
||||
return snapshot
|
||||
```
|
||||
|
||||
UI refresh timer: every **0.5 real seconds** — not every frame.
|
||||
|
||||
---
|
||||
|
||||
## 9. Class Reference
|
||||
|
||||
### `MineralDeposit`
|
||||
| | |
|
||||
|--|--|
|
||||
| Base | None (plain class) |
|
||||
| Thread-safe | ✅ |
|
||||
| File | `mineral_deposit.gd` |
|
||||
|
||||
| Member | Type | Notes |
|
||||
|--------|------|-------|
|
||||
| `type` | `Type` (enum) | One of 11 mineral types |
|
||||
| `amount` | `float` | Tons remaining |
|
||||
| `accessibility` | `float` | 0.1 – 1.0 |
|
||||
| `surveyed` | `bool` | Hidden until geological survey |
|
||||
| `get_rate(mines)` | `float` | Tons/sec at given mine count |
|
||||
| `extract(scaled_delta, mines)` | `float` | Mutates amount, returns extracted |
|
||||
| `is_depleted()` | `bool` | True when amount ≤ 0 |
|
||||
|
||||
---
|
||||
|
||||
### `PlanetBody`
|
||||
| | |
|
||||
|--|--|
|
||||
| Base | None (plain class) |
|
||||
| Thread-safe | ✅ |
|
||||
| File | `planet_body.gd` |
|
||||
|
||||
| Member | Type | Notes |
|
||||
|--------|------|-------|
|
||||
| `body_name` | `String` | |
|
||||
| `body_type` | `String` | Rocky / Moon / Gas Giant / etc. |
|
||||
| `gravity` | `float` | Earth = 1.0 |
|
||||
| `temperature` | `float` | Kelvin |
|
||||
| `deposits` | `Dictionary` | int → MineralDeposit |
|
||||
| `add_deposit(d)` | `void` | |
|
||||
| `get_deposit(type)` | `MineralDeposit` | |
|
||||
| `get_active_deposits()` | `Array` | Surveyed + non-depleted only |
|
||||
|
||||
---
|
||||
|
||||
### `MiningOperation`
|
||||
| | |
|
||||
|--|--|
|
||||
| Base | None (plain class) |
|
||||
| Thread-safe | ✅ |
|
||||
| File | `mining_operation.gd` |
|
||||
|
||||
| Member | Type | Notes |
|
||||
|--------|------|-------|
|
||||
| `body` | `PlanetBody` | |
|
||||
| `mines_deployed` | `int` | |
|
||||
| `stockpile` | `Dictionary` | Type → float (tons) |
|
||||
| `tick(scaled_delta)` | `Array` | Returns events (depletions) |
|
||||
| `get_total_rate()` | `Dictionary` | Type → tons/sec, for UI |
|
||||
|
||||
---
|
||||
|
||||
### `EconomyWorker`
|
||||
| | |
|
||||
|--|--|
|
||||
| Base | None (plain class) |
|
||||
| Thread-safe | ✅ (internally managed) |
|
||||
| File | `economy_worker.gd` |
|
||||
|
||||
| Member | Type | Notes |
|
||||
|--------|------|-------|
|
||||
| `start()` | `void` | Launches thread |
|
||||
| `stop()` | `void` | Graceful shutdown, waits for thread |
|
||||
| `push_delta(scaled_delta)` | `void` | Called from main thread each frame |
|
||||
| `add_operation(op)` | `void` | Register a colony |
|
||||
| `remove_operation(op)` | `void` | Deregister a colony |
|
||||
| `poll_events()` | `Array` | Drain event queue (main thread) |
|
||||
| `get_stockpile_snapshot(op)` | `Dictionary` | Safe UI read |
|
||||
|
||||
---
|
||||
|
||||
### `EconomyManager`
|
||||
| | |
|
||||
|--|--|
|
||||
| Base | `Node` |
|
||||
| Thread-safe | Main thread only |
|
||||
| File | `economy_manager.gd` |
|
||||
|
||||
Thin coordinator. Drives `EconomyWorker` each frame, handles events from the worker, emits signals on `EventBus`.
|
||||
|
||||
---
|
||||
|
||||
### `GameClock`
|
||||
| | |
|
||||
|--|--|
|
||||
| Base | `Node` (Autoload) |
|
||||
| Thread-safe | Main thread only |
|
||||
| File | `game_clock.gd` |
|
||||
|
||||
All time scaling lives here. Never read `delta` directly anywhere else in the project.
|
||||
|
||||
---
|
||||
|
||||
### `ResourceGenerator`
|
||||
| | |
|
||||
|--|--|
|
||||
| Base | None (static methods) |
|
||||
| Thread-safe | ✅ (no state) |
|
||||
| File | `resource_generator.gd` |
|
||||
|
||||
| Member | Notes |
|
||||
|--------|-------|
|
||||
| `generate_deposits(body, rng)` | Procedurally populates a PlanetBody |
|
||||
| `_spawn_chance(body_type)` | Per-type probability table |
|
||||
|
||||
---
|
||||
|
||||
## 10. Developer Checklist
|
||||
|
||||
### Phase 0 — Foundation
|
||||
- [ ] Set up Godot 4.6.2 project structure (`Core/`, `Systems/`, `UI/`, `Data/`)
|
||||
- [ ] Implement `GameClock` autoload
|
||||
- [ ] Implement `EventBus` autoload (for cross-system signals)
|
||||
- [ ] Write unit tests for `MineralDeposit.extract()` — verify math at 1x, 16x, 64x scale
|
||||
- [ ] Write unit tests for delta accumulation in `EconomyWorker`
|
||||
|
||||
### Phase 1 — Resource System
|
||||
- [ ] `MineralDeposit` — full implementation + tests
|
||||
- [ ] `PlanetBody` — full implementation
|
||||
- [ ] `ResourceGenerator` — procedural deposit generation
|
||||
- [ ] `MiningOperation` — tick logic + event return
|
||||
- [ ] `EconomyWorker` — thread, mutex, semaphore
|
||||
- [ ] `EconomyManager` — main thread coordinator
|
||||
- [ ] Verify thread shutdown is clean on scene change and game exit
|
||||
|
||||
### Phase 2 — Star System
|
||||
- [ ] Procedural star system generation (stars, planets, moons, asteroid belts)
|
||||
- [ ] Orbital mechanics (visual only — positions, not physics sim)
|
||||
- [ ] `StarSystemManager` node
|
||||
- [ ] Survey mission system (time-based, uses `GameClock`)
|
||||
|
||||
### Phase 3 — Colony & UI
|
||||
- [ ] Colony creation flow (ship delivers colony module)
|
||||
- [ ] Mine deployment UI
|
||||
- [ ] Stockpile display (snapshot-based, 0.5s refresh)
|
||||
- [ ] Event log panel (depletion notices, auto-pause triggers)
|
||||
- [ ] Time controls UI (pause, scale ladder, keyboard shortcuts)
|
||||
|
||||
### Phase 4 — Construction
|
||||
- [ ] Construction queue system
|
||||
- [ ] Mineral consumption from colony stockpile
|
||||
- [ ] Freighter / logistics system (move stockpile between colonies)
|
||||
|
||||
### Phase 5 — Ships & Fleets
|
||||
- [ ] Ship component / design system
|
||||
- [ ] Fleet movement (real-time, scaled)
|
||||
- [ ] Basic sensor / detection system
|
||||
|
||||
### Phase 6 — Expansion
|
||||
- [ ] Jump point discovery and inter-system travel
|
||||
- [ ] Non-Player Race (NPR) basic AI
|
||||
- [ ] Diplomacy framework
|
||||
|
||||
---
|
||||
|
||||
## 11. Open Questions
|
||||
|
||||
| # | Question | Priority |
|
||||
|---|----------|----------|
|
||||
| 1 | What is the base mining rate (tons/sec per mine at 1x)? Needs balancing pass. | High |
|
||||
| 2 | Should mine allocation be automatic (even split) or player-directed per mineral? | High |
|
||||
| 3 | At what time scales should auto-pause be suppressible by the player? | Medium |
|
||||
| 4 | Save file format — JSON (human-readable) or custom binary (performance)? | Medium |
|
||||
| 5 | Is Sorium (fuel) part of the same mining pipeline or a separate extraction type? | Medium |
|
||||
| 6 | Should asteroid belts be individual bodies or a single aggregate body? | Low |
|
||||
| 7 | How many colonies realistically before the thread model needs profiling? | Low |
|
||||
|
||||
---
|
||||
|
||||
*Document version 0.1 — Initial architecture session*
|
||||
*Last updated: May 2026*
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"conventionalCommits.scopes": [
|
||||
"ci/cd"
|
||||
]
|
||||
}
|
||||
@@ -4,12 +4,12 @@ importer="scene"
|
||||
importer_version=1
|
||||
type="PackedScene"
|
||||
uid="uid://b8yyluxikhlr0"
|
||||
path="res://.godot/imported/PID_Spinning_Stuff.glb-aa3b93bf47083b9724865d3bff0f5f1e.scn"
|
||||
path="res://.godot/imported/PID_Spinning_Stuff.glb-977aece4b561e834c064e6c1c7e53471.scn"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Experiments/PidTest/Assets/PID_Spinning_Stuff.glb"
|
||||
dest_files=["res://.godot/imported/PID_Spinning_Stuff.glb-aa3b93bf47083b9724865d3bff0f5f1e.scn"]
|
||||
source_file="res://Assets/PID_Spinning_Stuff.glb"
|
||||
dest_files=["res://.godot/imported/PID_Spinning_Stuff.glb-977aece4b561e834c064e6c1c7e53471.scn"]
|
||||
|
||||
[params]
|
||||
|
||||
@@ -4,12 +4,12 @@ importer="scene"
|
||||
importer_version=1
|
||||
type="PackedScene"
|
||||
uid="uid://cin3pgpeydkpe"
|
||||
path="res://.godot/imported/PID_Spinning_Target.glb-b494bd392644136f4ee2f4a9ca10e7bc.scn"
|
||||
path="res://.godot/imported/PID_Spinning_Target.glb-739e3becae2412e2332407d1fc9f1fc7.scn"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Experiments/PidTest/Assets/PID_Spinning_Target.glb"
|
||||
dest_files=["res://.godot/imported/PID_Spinning_Target.glb-b494bd392644136f4ee2f4a9ca10e7bc.scn"]
|
||||
source_file="res://Assets/PID_Spinning_Target.glb"
|
||||
dest_files=["res://.godot/imported/PID_Spinning_Target.glb-739e3becae2412e2332407d1fc9f1fc7.scn"]
|
||||
|
||||
[params]
|
||||
|
||||
@@ -4,12 +4,12 @@ importer="scene"
|
||||
importer_version=1
|
||||
type="PackedScene"
|
||||
uid="uid://c8ywajojvb7pw"
|
||||
path="res://.godot/imported/PID_Test_Obj.blend-49d06dd6be02191c02959431b2d686bf.scn"
|
||||
path="res://.godot/imported/PID_Test_Obj.blend-06d5e64216d0d8667c2f9c3cb6d12c34.scn"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Experiments/PidTest/Assets/PID_Test_Obj.blend"
|
||||
dest_files=["res://.godot/imported/PID_Test_Obj.blend-49d06dd6be02191c02959431b2d686bf.scn"]
|
||||
source_file="res://Assets/PID_Test_Obj.blend"
|
||||
dest_files=["res://.godot/imported/PID_Test_Obj.blend-06d5e64216d0d8667c2f9c3cb6d12c34.scn"]
|
||||
|
||||
[params]
|
||||
|
||||
|
Before Width: | Height: | Size: 533 B After Width: | Height: | Size: 533 B |
@@ -3,15 +3,15 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dng410xo7qqfv"
|
||||
path="res://.godot/imported/a-moon.png-54f8d7810db3be4679f0fc14b17f0770.ctex"
|
||||
path="res://.godot/imported/a-moon.png-bce2eccded710c90add850f3ca7cb2e1.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Core/Assets/PixelPlanets/a-moon.png"
|
||||
dest_files=["res://.godot/imported/a-moon.png-54f8d7810db3be4679f0fc14b17f0770.ctex"]
|
||||
source_file="res://Assets/PixelPlanets/a-moon.png"
|
||||
dest_files=["res://.godot/imported/a-moon.png-bce2eccded710c90add850f3ca7cb2e1.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
@@ -4,22 +4,20 @@ importer="scene"
|
||||
importer_version=1
|
||||
type="PackedScene"
|
||||
uid="uid://crfjfbhjuderh"
|
||||
path="res://.godot/imported/Thruster Cube Collision.glb-e4567795df54acdcaed8b44a3b1cdf8a.scn"
|
||||
path="res://.godot/imported/Thruster Cube Collision.glb-e95615f3a01fd673f0dafc758072d75c.scn"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Experiments/ThrusterCube/Assets/Thruster Cube Collision.glb"
|
||||
dest_files=["res://.godot/imported/Thruster Cube Collision.glb-e4567795df54acdcaed8b44a3b1cdf8a.scn"]
|
||||
source_file="res://Assets/Thruster Cube Collision.glb"
|
||||
dest_files=["res://.godot/imported/Thruster Cube Collision.glb-e95615f3a01fd673f0dafc758072d75c.scn"]
|
||||
|
||||
[params]
|
||||
|
||||
nodes/root_type="CollisionShape3D"
|
||||
nodes/root_name=""
|
||||
nodes/root_script=null
|
||||
nodes/apply_root_scale=true
|
||||
nodes/root_scale=1.0
|
||||
nodes/import_as_skeleton_bones=false
|
||||
nodes/use_name_suffixes=true
|
||||
nodes/use_node_type_suffixes=true
|
||||
meshes/ensure_tangents=true
|
||||
meshes/generate_lods=true
|
||||
@@ -34,9 +32,6 @@ animation/trimming=false
|
||||
animation/remove_immutable_tracks=true
|
||||
animation/import_rest_as_RESET=false
|
||||
import_script/path=""
|
||||
materials/extract=0
|
||||
materials/extract_format=0
|
||||
materials/extract_path=""
|
||||
_subresources={}
|
||||
gltf/naming_version=1
|
||||
gltf/embedded_image_handling=0
|
||||
@@ -0,0 +1,25 @@
|
||||
[remap]
|
||||
|
||||
importer="wavefront_obj"
|
||||
importer_version=1
|
||||
type="Mesh"
|
||||
uid="uid://c7f1y6fhexbhm"
|
||||
path="res://.godot/imported/Thruster Cube Collision.obj-b25b556e6c42aebde4547600bcacd901.mesh"
|
||||
|
||||
[deps]
|
||||
|
||||
files=["res://.godot/imported/Thruster Cube Collision.obj-b25b556e6c42aebde4547600bcacd901.mesh"]
|
||||
|
||||
source_file="res://Assets/Thruster Cube Collision.obj"
|
||||
dest_files=["res://.godot/imported/Thruster Cube Collision.obj-b25b556e6c42aebde4547600bcacd901.mesh", "res://.godot/imported/Thruster Cube Collision.obj-b25b556e6c42aebde4547600bcacd901.mesh"]
|
||||
|
||||
[params]
|
||||
|
||||
generate_tangents=true
|
||||
generate_lods=true
|
||||
generate_shadow_mesh=true
|
||||
generate_lightmap_uv2=false
|
||||
generate_lightmap_uv2_texel_size=0.2
|
||||
scale_mesh=Vector3(1, 1, 1)
|
||||
offset_mesh=Vector3(0, 0, 0)
|
||||
force_disable_mesh_compression=false
|
||||
@@ -4,22 +4,20 @@ importer="scene"
|
||||
importer_version=1
|
||||
type="PackedScene"
|
||||
uid="uid://cmiwlha25agl4"
|
||||
path="res://.godot/imported/Thruster Cube.glb-591643872d53aaa419a7d06c5a20d845.scn"
|
||||
path="res://.godot/imported/Thruster Cube.glb-02382f7bdc8ae9a0011d286e98d4c123.scn"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Experiments/ThrusterCube/Assets/Thruster Cube.glb"
|
||||
dest_files=["res://.godot/imported/Thruster Cube.glb-591643872d53aaa419a7d06c5a20d845.scn"]
|
||||
source_file="res://Assets/Thruster Cube.glb"
|
||||
dest_files=["res://.godot/imported/Thruster Cube.glb-02382f7bdc8ae9a0011d286e98d4c123.scn"]
|
||||
|
||||
[params]
|
||||
|
||||
nodes/root_type="RigidBody3D"
|
||||
nodes/root_name=""
|
||||
nodes/root_script=null
|
||||
nodes/apply_root_scale=true
|
||||
nodes/root_scale=1.0
|
||||
nodes/import_as_skeleton_bones=false
|
||||
nodes/use_name_suffixes=true
|
||||
nodes/use_node_type_suffixes=true
|
||||
meshes/ensure_tangents=true
|
||||
meshes/generate_lods=true
|
||||
@@ -34,9 +32,6 @@ animation/trimming=false
|
||||
animation/remove_immutable_tracks=true
|
||||
animation/import_rest_as_RESET=false
|
||||
import_script/path=""
|
||||
materials/extract=0
|
||||
materials/extract_format=0
|
||||
materials/extract_path=""
|
||||
_subresources={}
|
||||
gltf/naming_version=1
|
||||
gltf/embedded_image_handling=1
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene format=3 uid="uid://cc7e4loxpb1x6"]
|
||||
[gd_scene load_steps=3 format=3 uid="uid://cc7e4loxpb1x6"]
|
||||
|
||||
[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_lapuk"]
|
||||
points = PackedVector3Array(-0.5, -1, 0, -0.497651, -1, -0.0490407, -0.497651, -1, 0.0489429, -0.5, 1, 0, -0.490407, -1, -0.097592, -0.497651, 1, -0.0490407, -0.490407, -1, 0.0974941, -0.497651, 1, 0.0489429, -0.478563, -1, -0.145164, -0.490407, 1, -0.097592, -0.478563, -1, 0.145067, -0.490407, 1, 0.0974941, -0.46202, -1, -0.191366, -0.478563, 1, -0.145164, -0.46202, -1, 0.191269, -0.478563, 1, 0.145067, -0.440975, -1, -0.235709, -0.46202, 1, -0.191366, -0.440975, -1, 0.235611, -0.46202, 1, 0.191269, -0.415818, -1, -0.2778, -0.440975, 1, -0.235709, -0.415818, -1, 0.277702, -0.440975, 1, 0.235611, -0.386551, -1, -0.317247, -0.415818, 1, -0.2778, -0.386551, -1, 0.31715, -0.415818, 1, 0.277702, -0.353563, -1, -0.353563, -0.386551, 1, -0.317247, -0.353563, -1, 0.353465, -0.386551, 1, 0.31715, -0.317247, -1, -0.386551, -0.353563, 1, -0.353563, -0.317247, -1, 0.386453, -0.353563, 1, 0.353465, -0.2778, -1, -0.415818, -0.317247, 1, -0.386551, -0.2778, -1, 0.41572, -0.317247, 1, 0.386453, -0.235709, -1, -0.440975, -0.2778, 1, -0.415818, -0.235709, -1, 0.440877, -0.2778, 1, 0.41572, -0.191366, -1, -0.46202, -0.235709, 1, -0.440975, -0.191366, -1, 0.461922, -0.235709, 1, 0.440877, -0.145164, -1, -0.478563, -0.191366, 1, -0.46202, -0.145164, -1, 0.478465, -0.191366, 1, 0.461922, -0.097592, -1, -0.490407, -0.145164, 1, -0.478563, -0.097592, -1, 0.490309, -0.145164, 1, 0.478465, -0.0490407, -1, -0.497651, -0.097592, 1, -0.490407, -0.0490407, -1, 0.497553, -0.097592, 1, 0.490309, 0, -1, -0.5, -0.0490407, 1, -0.497651, 0, -1, 0.5, -0.0490407, 1, 0.497553, 0.0489429, -1, -0.497651, 0, 1, -0.5, 0.0489429, -1, 0.497553, 0, 1, 0.5, 0.0974941, -1, -0.490407, 0.0489429, 1, -0.497651, 0.0974941, -1, 0.490309, 0.0489429, 1, 0.497553, 0.145067, -1, -0.478563, 0.0974941, 1, -0.490407, 0.145067, -1, 0.478465, 0.0974941, 1, 0.490309, 0.191269, -1, -0.46202, 0.145067, 1, -0.478563, 0.191269, -1, 0.461922, 0.145067, 1, 0.478465, 0.235611, -1, -0.440975, 0.191269, 1, -0.46202, 0.235611, -1, 0.440877, 0.191269, 1, 0.461922, 0.277702, -1, -0.415818, 0.235611, 1, -0.440975, 0.277702, -1, 0.41572, 0.235611, 1, 0.440877, 0.31715, -1, -0.386551, 0.277702, 1, -0.415818, 0.31715, -1, 0.386453, 0.277702, 1, 0.41572, 0.353465, -1, -0.353563, 0.31715, 1, -0.386551, 0.353465, -1, 0.353465, 0.31715, 1, 0.386453, 0.386453, -1, -0.317247, 0.353465, 1, -0.353563, 0.386453, -1, 0.31715, 0.353465, 1, 0.353465, 0.41572, -1, -0.2778, 0.386453, 1, -0.317247, 0.41572, -1, 0.277702, 0.386453, 1, 0.31715, 0.440877, -1, -0.235709, 0.41572, 1, -0.2778, 0.440877, -1, 0.235611, 0.41572, 1, 0.277702, 0.461922, -1, -0.191366, 0.440877, 1, -0.235709, 0.461922, -1, 0.191269, 0.440877, 1, 0.235611, 0.478465, -1, -0.145164, 0.461922, 1, -0.191366, 0.478465, -1, 0.145067, 0.461922, 1, 0.191269, 0.490309, -1, -0.097592, 0.478465, 1, -0.145164, 0.490309, -1, 0.0974941, 0.478465, 1, 0.145067, 0.497553, -1, -0.0490407, 0.490309, 1, -0.097592, 0.497553, -1, 0.0489429, 0.490309, 1, 0.0974941, 0.5, -1, 0, 0.497553, 1, -0.0490407, 0.497553, 1, 0.0489429, 0.5, 1, 0)
|
||||
@@ -1,7 +1,7 @@
|
||||
[gd_scene format=3 uid="uid://c8tm1q2cp567o"]
|
||||
[gd_scene load_steps=6 format=3 uid="uid://c8tm1q2cp567o"]
|
||||
|
||||
[ext_resource type="Script" path="res://Experiments/SpaceMove/Scripts/player_ship.gd" id="1_3yydb"]
|
||||
[ext_resource type="Script" path="res://Experiments/SpaceMove/Scripts/shipAiComponent.gd" id="2_vr0dq"]
|
||||
[ext_resource type="Script" uid="uid://ccnbhjxglgw12" path="res://Assets/player_ship.gd" id="1_3yydb"]
|
||||
[ext_resource type="Script" uid="uid://ci33hs6nbuhqr" path="res://Assets/shipAiComponent.gd" id="2_vr0dq"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_tjnu1"]
|
||||
radius = 1.48237
|
||||
@@ -1,7 +1,7 @@
|
||||
[gd_scene format=3 uid="uid://1al1ysn5q5yk"]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://1al1ysn5q5yk"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://cmiwlha25agl4" path="res://Experiments/ThrusterCube/Assets/Thruster Cube.glb" id="1_48yjx"]
|
||||
[ext_resource type="Script" path="res://Experiments/PidTest/Scripts/pid_test.gd" id="2_j3sme"]
|
||||
[ext_resource type="PackedScene" uid="uid://cmiwlha25agl4" path="res://Assets/Thruster Cube.glb" id="1_48yjx"]
|
||||
[ext_resource type="Script" uid="uid://dd3ns5mckarbj" path="res://Assets/thruster_cube.gd" id="2_j3sme"]
|
||||
|
||||
[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_48yjx"]
|
||||
points = PackedVector3Array(5.05799, 3.09144, 8.02469, 5.05799, -3.09243, 8.02469, 5.05799, 3.72121, 7.41253, 4.99561, 3.99253, 9.40488, 5.05799, -3.7222, 7.41253, 4.99561, -3.99352, 9.40488, 5.05799, 3.72121, -8.54888, 4.99561, 4.98769, 8.4087, 4.99165, 4.00936, 9.40714, 4.98769, 3.99253, 9.41165, 4.99165, 4.99165, 8.42677, 4.99561, -4.98868, 8.4087, 5.05799, -3.7222, -8.54888, 4.98769, -3.99352, 9.41165, 4.99165, -4.01035, 9.40714, 4.99165, -4.99264, 8.42677, 5.05799, 3.09144, -9.15878, 4.99561, 3.99253, -10.539, 4.99561, 4.98769, -9.54505, 1.20608, 0.951591, 11.8535, 4.00936, 4.99165, 9.40714, 4.98769, 4.99561, 8.4087, 3.99253, 4.99561, 9.40488, 4.99561, -4.98868, -9.54505, 4.99561, -3.99352, -10.539, 5.05799, -3.09243, -9.15878, 1.20608, -0.952582, 11.8535, 4.00936, -4.99264, 9.40714, 4.98769, -4.9966, 8.4087, 3.99253, -4.9966, 9.40488, 4.99165, 4.00936, -10.5435, 4.99165, 4.99165, -9.56086, 0.951591, 1.20608, 11.8535, 3.99253, 4.98769, 9.41165, 3.72121, 5.05799, 7.41253, 4.98769, 4.99561, -9.54505, -3.99352, 4.99561, 9.40488, 3.09144, 5.05799, 8.02469, 4.99165, -4.99264, -9.56086, 4.99165, -4.01035, -10.5435, 0.951591, -1.20707, 11.8535, 3.99253, -4.98868, 9.41165, 3.72121, -5.05799, 7.41253, 4.98769, -4.9966, -9.54505, -3.99352, -4.9966, 9.40488, 3.09144, -5.05799, 8.02469, 4.98769, 3.99253, -10.548, 3.08153, 3.08153, -11.2234, 4.00936, 4.99165, -10.5435, -0.952582, 1.20608, 11.8535, -3.99352, 4.98769, 9.41165, 3.72121, 5.05799, -8.54888, 3.99253, 4.99561, -10.539, -4.01035, 4.99165, 9.40714, -3.09243, 5.05799, 8.02469, -3.7222, 5.05799, 7.41253, -4.98868, 4.99561, 8.4087, -4.99264, 4.99165, 8.42677, 4.00936, -4.99264, -10.5435, 3.08153, -3.08252, -11.2234, 4.98769, -3.99352, -10.548, -0.952582, -1.20707, 11.8535, -3.99352, -4.98868, 9.41165, 3.72121, -5.05799, -8.54888, 3.99253, -4.9966, -10.539, -4.01035, -4.99264, 9.40714, -4.99264, -4.99264, 8.42677, -4.98868, -4.9966, 8.4087, -3.7222, -5.05799, 7.41253, -3.09243, -5.05799, 8.02469, 3.1152, 2.99935, -11.2234, 2.99935, 3.1152, -11.2234, 3.99253, 4.98769, -10.548, -1.20707, 0.951591, 11.8535, 3.09144, 5.05799, -9.15878, -3.99352, 4.99561, -10.539, -4.99264, 4.00936, 9.40714, -3.7222, 5.05799, -8.54888, -4.98868, 4.99561, -9.54505, -4.9966, 4.98769, 8.4087, -4.9966, 3.99253, 9.40488, 3.99253, -4.98868, -10.548, 2.99935, -3.11619, -11.2234, 3.1152, -3.00034, -11.2234, -1.20707, -0.952582, 11.8535, 3.09144, -5.05799, -9.15878, -3.99352, -4.9966, -10.539, -4.99264, -4.01035, 9.40714, -4.9966, -3.99352, 9.40488, -4.9966, -4.98868, 8.4087, -4.98868, -4.9966, -9.54505, -3.7222, -5.05799, -8.54888, -3.00034, 3.1152, -11.2234, -3.99352, 4.98769, -10.548, -4.98868, 3.99253, 9.41165, -3.09243, 5.05799, -9.15878, -4.01035, 4.99165, -10.5435, -4.99264, 4.99165, -9.56086, -5.05799, 3.72121, 7.41253, -4.9966, 4.98769, -9.54505, -5.05799, 3.09144, 8.02469, -3.99352, -4.98868, -10.548, -3.00034, -3.11619, -11.2234, -4.98868, -3.99352, 9.41165, -3.09243, -5.05799, -9.15878, -4.01035, -4.99264, -10.5435, -5.05799, -3.09243, 8.02469, -5.05799, -3.7222, 7.41253, -4.9966, -4.98868, -9.54505, -4.99264, -4.99264, -9.56086, -3.08252, 3.08153, -11.2234, -4.99264, 4.00936, -10.5435, -5.05799, 3.72121, -8.54888, -4.9966, 3.99253, -10.539, -3.08252, -3.08252, -11.2234, -4.99264, -4.01035, -10.5435, -5.05799, -3.7222, -8.54888, -4.9966, -3.99352, -10.539, -3.11619, 2.99935, -11.2234, -4.98868, 3.99253, -10.548, -5.05799, 3.09144, -9.15878, -3.11619, -3.00034, -11.2234, -4.98868, -3.99352, -10.548, -5.05799, -3.09243, -9.15878)
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene format=3 uid="uid://bp7um84bpvhmx"]
|
||||
[gd_scene load_steps=2 format=3 uid="uid://bp7um84bpvhmx"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://crfjfbhjuderh" path="res://Assets/Thruster Cube Collision.glb" id="1_v5i77"]
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
extends Node2D
|
||||
@@ -1 +0,0 @@
|
||||
uid://1c5nfdg2aud4
|
||||
@@ -1,37 +0,0 @@
|
||||
[gd_scene format=3 uid="uid://o2egm85y3wul"]
|
||||
|
||||
[ext_resource type="Script" path="res://Experiments/Recuration/Assets/TheMoon/TheMoon.gd" id="1_sr6fy"]
|
||||
[ext_resource type="Texture2D" uid="uid://dng410xo7qqfv" path="res://Core/Assets/PixelPlanets/a-moon.png" id="2_oy8k5"]
|
||||
|
||||
[node name="TheMoon" type="Node2D" unique_id=1994078602]
|
||||
script = ExtResource("1_sr6fy")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=1777467462]
|
||||
texture_filter = 1
|
||||
texture_repeat = 1
|
||||
texture = ExtResource("2_oy8k5")
|
||||
|
||||
[node name="Control" type="Control" parent="." unique_id=1752474701]
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
offset_left = 20.0
|
||||
offset_top = 20.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 20.0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Control" unique_id=61689214]
|
||||
layout_mode = 0
|
||||
offset_right = 110.0
|
||||
offset_bottom = 77.0
|
||||
|
||||
[node name="Label" type="Label" parent="Control/VBoxContainer" unique_id=1786036540]
|
||||
layout_mode = 2
|
||||
text = "Iron"
|
||||
|
||||
[node name="Label2" type="Label" parent="Control/VBoxContainer" unique_id=374559952]
|
||||
layout_mode = 2
|
||||
text = "Copper"
|
||||
|
||||
[node name="Label3" type="Label" parent="Control/VBoxContainer" unique_id=1739358724]
|
||||
layout_mode = 2
|
||||
text = "Copper"
|
||||
@@ -1,17 +0,0 @@
|
||||
[gd_scene format=3 uid="uid://cycayd4l7k7s4"]
|
||||
|
||||
[ext_resource type="Script" path="res://Experiments/Recuration/Scripts/RecurionCamera.gd" id="1_002bs"]
|
||||
[ext_resource type="PackedScene" uid="uid://cbqapc1frbhtv" path="res://Experiments/Recuration/UI/UI.tscn" id="2_qgdyp"]
|
||||
[ext_resource type="PackedScene" uid="uid://o2egm85y3wul" path="res://Experiments/Recuration/Assets/TheMoon/TheMoon.tscn" id="3_yu4li"]
|
||||
|
||||
[node name="Recuration" type="Node2D" unique_id=1741828961]
|
||||
|
||||
[node name="RecurionCamera" type="Camera2D" parent="." unique_id=997983592]
|
||||
script = ExtResource("1_002bs")
|
||||
movement_speed = 10.0
|
||||
metadata/_custom_type_script = "uid://bqslv86lm78ci"
|
||||
|
||||
[node name="Ui" parent="RecurionCamera" unique_id=1649292342 instance=ExtResource("2_qgdyp")]
|
||||
|
||||
[node name="TheMoon" parent="." unique_id=1994078602 instance=ExtResource("3_yu4li")]
|
||||
position = Vector2(-181, -79)
|
||||
@@ -1,12 +0,0 @@
|
||||
[gd_scene format=3 uid="uid://cbqapc1frbhtv"]
|
||||
|
||||
[ext_resource type="Script" path="res://Experiments/Recuration/UI/ui.gd" id="1_0oc4u"]
|
||||
|
||||
[node name="Ui" type="Control" unique_id=1649292342]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_0oc4u")
|
||||
@@ -1 +0,0 @@
|
||||
extends Control
|
||||
@@ -1 +0,0 @@
|
||||
uid://dslwh6krdrhb
|
||||
@@ -1,25 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="wavefront_obj"
|
||||
importer_version=1
|
||||
type="Mesh"
|
||||
uid="uid://c7f1y6fhexbhm"
|
||||
path="res://.godot/imported/Thruster Cube Collision.obj-c54c1e160e870d82560d1c443ddeae58.mesh"
|
||||
|
||||
[deps]
|
||||
|
||||
files=["res://.godot/imported/Thruster Cube Collision.obj-c54c1e160e870d82560d1c443ddeae58.mesh"]
|
||||
|
||||
source_file="res://Experiments/ThrusterCube/Assets/Thruster Cube Collision.obj"
|
||||
dest_files=["res://.godot/imported/Thruster Cube Collision.obj-c54c1e160e870d82560d1c443ddeae58.mesh", "res://.godot/imported/Thruster Cube Collision.obj-c54c1e160e870d82560d1c443ddeae58.mesh"]
|
||||
|
||||
[params]
|
||||
|
||||
generate_tangents=true
|
||||
generate_lods=true
|
||||
generate_shadow_mesh=true
|
||||
generate_lightmap_uv2=false
|
||||
generate_lightmap_uv2_texel_size=0.2
|
||||
scale_mesh=Vector3(1, 1, 1)
|
||||
offset_mesh=Vector3(0, 0, 0)
|
||||
force_disable_mesh_compression=false
|
||||
@@ -0,0 +1,40 @@
|
||||
<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/28.0.6 Chrome/138.0.7204.100 Electron/37.2.3 Safari/537.36" version="28.0.6">
|
||||
<diagram name="Seite-1" id="8VUDw9VsU7XZE8zAJI22">
|
||||
<mxGraphModel dx="575" dy="518" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="U4xH48hkQDtbZK23ePJW-3" value="2D Movement Drag Conept" style="shape=cube;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;darkOpacity=0.05;darkOpacity2=0.1;" vertex="1" parent="1">
|
||||
<mxGeometry x="10" y="10" width="120" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="U4xH48hkQDtbZK23ePJW-4" value="When<br>Left Click + Hold" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="120" width="80" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="U4xH48hkQDtbZK23ePJW-5" value="Save Mouse Pos" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="160" y="130" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="U4xH48hkQDtbZK23ePJW-6" value="Movement of mouse" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="250" width="80" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="U4xH48hkQDtbZK23ePJW-7" value="New Mouse pos - old pos = move postions" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="160" y="260" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="U4xH48hkQDtbZK23ePJW-8" value="" style="endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="440" y="210" as="sourcePoint" />
|
||||
<mxPoint x="600" y="330" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="U4xH48hkQDtbZK23ePJW-10" value="Click<br>PosA" style="shape=callout;whiteSpace=wrap;html=1;perimeter=calloutPerimeter;" vertex="1" parent="1">
|
||||
<mxGeometry x="380" y="130" width="120" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="U4xH48hkQDtbZK23ePJW-11" value="Click Move<br>PosB" style="shape=callout;whiteSpace=wrap;html=1;perimeter=calloutPerimeter;" vertex="1" parent="1">
|
||||
<mxGeometry x="540" y="250" width="120" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="U4xH48hkQDtbZK23ePJW-12" value="Vector: 10x, -5y" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="540" y="130" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -3,15 +3,11 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://pyvdyr3pes5o"
|
||||
path="res://.godot/imported/Movement 2D.svg-4fa99617f74c694e4d2141eda40271bc.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
valid=false
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Experiments/Recuration/Planning/Movement 2D.svg"
|
||||
dest_files=["res://.godot/imported/Movement 2D.svg-4fa99617f74c694e4d2141eda40271bc.ctex"]
|
||||
source_file="res://Games/SpaceResources/Planing/Movement 2D.svg"
|
||||
|
||||
[params]
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,16 @@
|
||||
[gd_scene format=3 uid="uid://cycayd4l7k7s4"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bqslv86lm78ci" path="res://Games/SpaceResources/Scripts/RecurionCamera.gd" id="1_002bs"]
|
||||
[ext_resource type="Texture2D" uid="uid://dng410xo7qqfv" path="res://Assets/PixelPlanets/a-moon.png" id="2_qgdyp"]
|
||||
|
||||
[node name="Recuration" type="Node2D" unique_id=1741828961]
|
||||
|
||||
[node name="RecurionCamera" type="Camera2D" parent="." unique_id=997983592]
|
||||
script = ExtResource("1_002bs")
|
||||
movement_speed = 10.0
|
||||
metadata/_custom_type_script = "uid://bqslv86lm78ci"
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=45756830]
|
||||
texture_filter = 1
|
||||
texture_repeat = 1
|
||||
texture = ExtResource("2_qgdyp")
|
||||
@@ -1,34 +1,33 @@
|
||||
extends Node3D
|
||||
|
||||
var p: float = 0.4
|
||||
var i: float = 0.0
|
||||
var d: float = 1
|
||||
var p:float = 0.4
|
||||
var i:float = 0.0
|
||||
var d:float = 1
|
||||
|
||||
var force: float = 200.0
|
||||
var error: float = 0.0
|
||||
var force:float = 200.0
|
||||
var error:float = 0.0
|
||||
var last_error = 0.0
|
||||
var error_derivative: float = 0.0
|
||||
var integral: float = 0.0
|
||||
var target: float = 0.0 #0.0 -> 359.99
|
||||
var error_derivative:float = 0.0
|
||||
var integral:float = 0.0
|
||||
var target:float = 0.0 #0.0 -> 359.99
|
||||
|
||||
var p_input: SpinBox
|
||||
var i_input: SpinBox
|
||||
var d_input: SpinBox
|
||||
var force_input: SpinBox
|
||||
var target_input: SpinBox
|
||||
var p_input:SpinBox
|
||||
var i_input:SpinBox
|
||||
var d_input:SpinBox
|
||||
var force_input:SpinBox
|
||||
var target_input:SpinBox
|
||||
|
||||
var spinner_node: Node3D
|
||||
var target_node: Node3D
|
||||
var error_lable: Label
|
||||
var speed_lable: Label
|
||||
var acceleration_label: Label
|
||||
var error_derivative_lable: Label
|
||||
var integral_lable: Label
|
||||
|
||||
var spinner_speed: float = 0.0
|
||||
var max_speed: float = 120 # deg/m -> 1/360/60s = 1rpm
|
||||
var acceleration: float
|
||||
var spinner_node:Node3D
|
||||
var target_node:Node3D
|
||||
var error_lable:Label
|
||||
var speed_lable:Label
|
||||
var acceleration_label:Label
|
||||
var error_derivative_lable:Label
|
||||
var integral_lable:Label
|
||||
|
||||
var spinner_speed:float = 0.0
|
||||
var max_speed:float = 120 # deg/m -> 1/360/60s = 1rpm
|
||||
var acceleration:float
|
||||
|
||||
func _ready() -> void:
|
||||
spinner_node = get_node("Spinner")
|
||||
@@ -46,7 +45,7 @@ func _ready() -> void:
|
||||
force_input = get_node("PID Menue/PanelContainer/VBoxContainer/Force/Input")
|
||||
force_input.value_changed.connect(_update_force_value)
|
||||
|
||||
target_input = get_node("PID Menue/PanelContainer/VBoxContainer/Target Rotation/Input")
|
||||
target_input =get_node("PID Menue/PanelContainer/VBoxContainer/Target Rotation/Input")
|
||||
target_input.value_changed.connect(_update_target_rot)
|
||||
|
||||
error_lable = get_node("PID Menue/PanelContainer/VBoxContainer/Error/Output")
|
||||
@@ -61,34 +60,29 @@ func _ready() -> void:
|
||||
d_input.value = d
|
||||
force_input.value = force
|
||||
|
||||
|
||||
func _update_target_rot(value: float) -> void:
|
||||
func _update_target_rot(value:float) -> void:
|
||||
target_node.rotation.x = deg_to_rad(value)
|
||||
|
||||
|
||||
func _update_p_value(value: float) -> void:
|
||||
func _update_p_value(value:float) -> void:
|
||||
p = value
|
||||
|
||||
|
||||
func _update_i_value(value: float) -> void:
|
||||
func _update_i_value(value:float) -> void:
|
||||
i = value
|
||||
|
||||
|
||||
func _update_d_value(value: float) -> void:
|
||||
func _update_d_value(value:float) -> void:
|
||||
d = value
|
||||
|
||||
|
||||
func _update_force_value(value: float) -> void:
|
||||
func _update_force_value(value:float) -> void:
|
||||
force = value
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
# PID Stuff
|
||||
target = rad_to_deg(target_node.rotation.x)
|
||||
error = target - rad_to_deg(spinner_node.rotation.x)
|
||||
error_derivative = (error - last_error) / delta
|
||||
error_derivative = (error - last_error) /delta
|
||||
integral += error * delta
|
||||
|
||||
|
||||
# Clamp acceleration between min and max force
|
||||
var pid_output := (p * error) + (i * integral) + (d * error_derivative)
|
||||
acceleration = clampf(pid_output, -force, force)
|
||||
@@ -105,11 +99,10 @@ func _process(delta: float) -> void:
|
||||
|
||||
last_error = error
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
#UI Updats
|
||||
error_lable.text = str(error).pad_decimals(2).pad_zeros(3) + " deg"
|
||||
error_derivative_lable.text = str(error_derivative).pad_decimals(2).pad_zeros(3)
|
||||
integral_lable.text = str(integral).pad_decimals(2).pad_zeros(3)
|
||||
speed_lable.text = str(spinner_speed).pad_decimals(2).pad_zeros(3) + " deg/m"
|
||||
acceleration_label.text = str(acceleration / force * 100).pad_decimals(2).pad_zeros(3) + " %"
|
||||
acceleration_label.text = str(acceleration/force*100).pad_decimals(2).pad_zeros(3) + " %"
|
||||
@@ -1,8 +1,8 @@
|
||||
[gd_scene format=3 uid="uid://caj5t8q1fii5m"]
|
||||
[gd_scene load_steps=8 format=3 uid="uid://caj5t8q1fii5m"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://cin3pgpeydkpe" path="res://Experiments/PidTest/Assets/PID_Spinning_Target.glb" id="1_0c8sw"]
|
||||
[ext_resource type="Script" uid="uid://b63aqs33qyp0g" path="res://Experiments/PidTest/Scripts/pid_test.gd" id="1_sxbsa"]
|
||||
[ext_resource type="PackedScene" uid="uid://b8yyluxikhlr0" path="res://Experiments/PidTest/Assets/PID_Spinning_Stuff.glb" id="2_sxbsa"]
|
||||
[ext_resource type="PackedScene" uid="uid://cin3pgpeydkpe" path="res://Assets/PID_Spinning_Target.glb" id="1_0c8sw"]
|
||||
[ext_resource type="Script" uid="uid://b63aqs33qyp0g" path="res://Levels/pid_test.gd" id="1_sxbsa"]
|
||||
[ext_resource type="PackedScene" uid="uid://b8yyluxikhlr0" path="res://Assets/PID_Spinning_Stuff.glb" id="2_sxbsa"]
|
||||
|
||||
[sub_resource type="Environment" id="Environment_d03hh"]
|
||||
background_mode = 2
|
||||
@@ -16,31 +16,31 @@ ambient_light_source = 2
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_sxbsa"]
|
||||
font_size = 24
|
||||
|
||||
[node name="PidTest" type="Node3D" unique_id=409732338]
|
||||
[node name="PidTest" type="Node3D"]
|
||||
script = ExtResource("1_sxbsa")
|
||||
|
||||
[node name="Target" type="Node3D" parent="." unique_id=1892694980]
|
||||
[node name="Target" type="Node3D" parent="."]
|
||||
|
||||
[node name="PID_Spinning_Target" parent="Target" unique_id=290681639 instance=ExtResource("1_0c8sw")]
|
||||
[node name="PID_Spinning_Target" parent="Target" instance=ExtResource("1_0c8sw")]
|
||||
|
||||
[node name="Spinner" type="Node3D" parent="." unique_id=247778584]
|
||||
[node name="Spinner" type="Node3D" parent="."]
|
||||
|
||||
[node name="PID_Spinning_Stuff" parent="Spinner" unique_id=1201678253 instance=ExtResource("2_sxbsa")]
|
||||
[node name="PID_Spinning_Stuff" parent="Spinner" instance=ExtResource("2_sxbsa")]
|
||||
|
||||
[node name="OmniLight3D" type="OmniLight3D" parent="Spinner/PID_Spinning_Stuff" unique_id=2090020750]
|
||||
[node name="OmniLight3D" type="OmniLight3D" parent="Spinner/PID_Spinning_Stuff"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.40560818, 0.6382216, 0)
|
||||
light_color = Color(0.99999994, 0.20727095, 0.32746297, 1)
|
||||
light_energy = 0.2
|
||||
shadow_enabled = true
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=1282499222]
|
||||
[node name="Camera3D" type="Camera3D" parent="."]
|
||||
transform = Transform3D(-4.3597606e-08, -0.072106734, 0.99739695, -3.1518854e-09, 0.99739695, 0.072106734, -1, 0, -4.371139e-08, 4.3431935, 0.43207824, 0)
|
||||
environment = SubResource("Environment_d03hh")
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1522897878]
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||
transform = Transform3D(0.25000006, 0.9659258, 0.06698735, -0.2588191, -1.9081726e-08, 0.9659258, 0.93301266, -0.25881913, 0.25000003, 0, 3.3288543, 0)
|
||||
|
||||
[node name="PID Menue" type="Control" parent="." unique_id=1859056208]
|
||||
[node name="PID Menue" type="Control" parent="."]
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
offset_left = 20.0
|
||||
@@ -49,172 +49,172 @@ offset_right = 20.0
|
||||
offset_bottom = 20.0
|
||||
theme = SubResource("Theme_sxbsa")
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="PID Menue" unique_id=1246871103]
|
||||
[node name="PanelContainer" type="PanelContainer" parent="PID Menue"]
|
||||
layout_mode = 0
|
||||
offset_right = 40.0
|
||||
offset_bottom = 40.0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="PID Menue/PanelContainer" unique_id=954080507]
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="PID Menue/PanelContainer"]
|
||||
layout_mode = 2
|
||||
theme = SubResource("Theme_d03hh")
|
||||
|
||||
[node name="Spinner Header" type="Label" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=1483799622]
|
||||
[node name="Spinner Header" type="Label" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Spinner Controll"
|
||||
label_settings = SubResource("LabelSettings_sxbsa")
|
||||
|
||||
[node name="Proportinal Term (P)" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=1794698833]
|
||||
[node name="Proportinal Term (P)" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Proportinal Term (P)" unique_id=1317903797]
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Proportinal Term (P)"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Proportinal Term (P)"
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="PID Menue/PanelContainer/VBoxContainer/Proportinal Term (P)" unique_id=1758759405]
|
||||
[node name="MarginContainer" type="MarginContainer" parent="PID Menue/PanelContainer/VBoxContainer/Proportinal Term (P)"]
|
||||
custom_minimum_size = Vector2(20, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Input" type="SpinBox" parent="PID Menue/PanelContainer/VBoxContainer/Proportinal Term (P)" unique_id=1823143898]
|
||||
[node name="Input" type="SpinBox" parent="PID Menue/PanelContainer/VBoxContainer/Proportinal Term (P)"]
|
||||
layout_mode = 2
|
||||
max_value = 1.0
|
||||
step = 0.01
|
||||
value = 0.5
|
||||
|
||||
[node name="Integral (I)" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=64519878]
|
||||
[node name="Integral (I)" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Integral (I)" unique_id=1114350133]
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Integral (I)"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Integral (I)"
|
||||
|
||||
[node name="Input" type="SpinBox" parent="PID Menue/PanelContainer/VBoxContainer/Integral (I)" unique_id=24991717]
|
||||
[node name="Input" type="SpinBox" parent="PID Menue/PanelContainer/VBoxContainer/Integral (I)"]
|
||||
layout_mode = 2
|
||||
max_value = 1.0
|
||||
step = 0.01
|
||||
|
||||
[node name="Derivative (D)" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=373567523]
|
||||
[node name="Derivative (D)" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Derivative (D)" unique_id=1005009217]
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Derivative (D)"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Derivative (D)"
|
||||
|
||||
[node name="Input" type="SpinBox" parent="PID Menue/PanelContainer/VBoxContainer/Derivative (D)" unique_id=2125630530]
|
||||
[node name="Input" type="SpinBox" parent="PID Menue/PanelContainer/VBoxContainer/Derivative (D)"]
|
||||
layout_mode = 2
|
||||
max_value = 1.0
|
||||
step = 0.01
|
||||
|
||||
[node name="Force" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=372036544]
|
||||
[node name="Force" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Force" unique_id=730787559]
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Force"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Force"
|
||||
|
||||
[node name="Input" type="SpinBox" parent="PID Menue/PanelContainer/VBoxContainer/Force" unique_id=664419913]
|
||||
[node name="Input" type="SpinBox" parent="PID Menue/PanelContainer/VBoxContainer/Force"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=1594734591]
|
||||
[node name="MarginContainer" type="MarginContainer" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 20)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Target Header" type="Label" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=840305492]
|
||||
[node name="Target Header" type="Label" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Target"
|
||||
label_settings = SubResource("LabelSettings_sxbsa")
|
||||
|
||||
[node name="Target Rotation" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=1817766875]
|
||||
[node name="Target Rotation" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Target Rotation" unique_id=434163315]
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Target Rotation"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Target Rotation"
|
||||
|
||||
[node name="Input" type="SpinBox" parent="PID Menue/PanelContainer/VBoxContainer/Target Rotation" unique_id=702580921]
|
||||
[node name="Input" type="SpinBox" parent="PID Menue/PanelContainer/VBoxContainer/Target Rotation"]
|
||||
layout_mode = 2
|
||||
max_value = 1439.96
|
||||
step = 0.01
|
||||
custom_arrow_step = 10.0
|
||||
|
||||
[node name="MarginContainer2" type="MarginContainer" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=1993364980]
|
||||
[node name="MarginContainer2" type="MarginContainer" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 20)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Solution" type="Label" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=1363644963]
|
||||
[node name="Solution" type="Label" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Solution"
|
||||
label_settings = SubResource("LabelSettings_sxbsa")
|
||||
|
||||
[node name="Error" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=1710432059]
|
||||
[node name="Error" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Error" unique_id=20360049]
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Error"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Error"
|
||||
|
||||
[node name="Output" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Error" unique_id=220452512]
|
||||
[node name="Output" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Error"]
|
||||
layout_mode = 2
|
||||
text = "000.00"
|
||||
horizontal_alignment = 1
|
||||
uppercase = true
|
||||
|
||||
[node name="Error Derivative" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=257500719]
|
||||
[node name="Error Derivative" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Error Derivative" unique_id=520180909]
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Error Derivative"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Error Derivative"
|
||||
|
||||
[node name="Output" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Error Derivative" unique_id=376634574]
|
||||
[node name="Output" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Error Derivative"]
|
||||
layout_mode = 2
|
||||
text = "000.00"
|
||||
horizontal_alignment = 1
|
||||
uppercase = true
|
||||
|
||||
[node name="Integral" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=1906698794]
|
||||
[node name="Integral" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Integral" unique_id=1621802829]
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Integral"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Integral"
|
||||
|
||||
[node name="Output" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Integral" unique_id=1321401490]
|
||||
[node name="Output" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Integral"]
|
||||
layout_mode = 2
|
||||
text = "000.00"
|
||||
horizontal_alignment = 1
|
||||
uppercase = true
|
||||
|
||||
[node name="Speed" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=1485477014]
|
||||
[node name="Speed" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Speed" unique_id=363468111]
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Speed"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Speed"
|
||||
|
||||
[node name="Output" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Speed" unique_id=1947341639]
|
||||
[node name="Output" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Speed"]
|
||||
layout_mode = 2
|
||||
text = "000.00"
|
||||
horizontal_alignment = 1
|
||||
uppercase = true
|
||||
|
||||
[node name="Acceleration" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer" unique_id=1814146417]
|
||||
[node name="Acceleration" type="HBoxContainer" parent="PID Menue/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Acceleration" unique_id=1879879740]
|
||||
[node name="Label" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Acceleration"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Acceleration"
|
||||
|
||||
[node name="Output" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Acceleration" unique_id=1647345306]
|
||||
[node name="Output" type="Label" parent="PID Menue/PanelContainer/VBoxContainer/Acceleration"]
|
||||
layout_mode = 2
|
||||
text = "000.00"
|
||||
horizontal_alignment = 1
|
||||
@@ -0,0 +1,3 @@
|
||||
[gd_scene format=3 uid="uid://jynlgkm41y8d"]
|
||||
|
||||
[node name="SpaceMove" type="Node3D"]
|
||||
@@ -1,9 +1,8 @@
|
||||
[gd_scene format=3 uid="uid://dgst4apmowe53"]
|
||||
[gd_scene load_steps=10 format=3 uid="uid://dgst4apmowe53"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://cc7e4loxpb1x6" path="res://Experiments/ThrusterCube/Scenes/obstacle.tscn" id="1_ig7tw"]
|
||||
[ext_resource type="PackedScene" uid="uid://c8tm1q2cp567o" path="res://Experiments/SpaceMove/Assets/player_ship.tscn" id="2_0xm2m"]
|
||||
[ext_resource type="PackedScene" uid="uid://1al1ysn5q5yk" path="res://Experiments/ThrusterCube/Scenes/thruster_cube.tscn" id="3_h2yge"]
|
||||
[ext_resource type="Script" path="res://Experiments/SpaceMove/Scripts/player_ship.gd" id="4_10w3i"]
|
||||
[ext_resource type="PackedScene" uid="uid://cc7e4loxpb1x6" path="res://Assets/obstacle.tscn" id="1_ig7tw"]
|
||||
[ext_resource type="PackedScene" uid="uid://c8tm1q2cp567o" path="res://Assets/player_ship.tscn" id="2_0xm2m"]
|
||||
[ext_resource type="PackedScene" uid="uid://1al1ysn5q5yk" path="res://Assets/thruster_cube.tscn" id="3_h2yge"]
|
||||
|
||||
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_hsoxx"]
|
||||
|
||||
@@ -23,49 +22,46 @@ ambient_light_color = Color(1, 1, 1, 1)
|
||||
|
||||
[sub_resource type="PlaneMesh" id="PlaneMesh_h2yge"]
|
||||
|
||||
[node name="TestLevel" type="Node3D" unique_id=652844344]
|
||||
[node name="TestLevel" type="Node3D"]
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=150721961]
|
||||
[node name="Camera3D" type="Camera3D" parent="."]
|
||||
transform = Transform3D(0.998445, -0.0179374, 0.0527875, -9.30799e-10, 0.946829, 0.321737, -0.0557519, -0.321236, 0.945357, 0.181835, 5.6324, 24.1051)
|
||||
fov = 50.4
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=972963566]
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource("Environment_hsoxx")
|
||||
camera_attributes = SubResource("CameraAttributesPractical_1c2mv")
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=419392911]
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||
transform = Transform3D(0.933305, -0.340159, 0.115038, 0, 0.320365, 0.947294, -0.359085, -0.884114, 0.298998, 0, 1.65681, 0)
|
||||
|
||||
[node name="Node" type="Node3D" parent="." unique_id=1060338205]
|
||||
[node name="Node" type="Node3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.112919, -16.6481, 0.0137749)
|
||||
|
||||
[node name="Obstacle" parent="Node" unique_id=1151336365 instance=ExtResource("1_ig7tw")]
|
||||
[node name="Obstacle" parent="Node" instance=ExtResource("1_ig7tw")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.528058, 1.09307, -4.11262)
|
||||
|
||||
[node name="PlayerShip" parent="Node" unique_id=1169721436 instance=ExtResource("2_0xm2m")]
|
||||
[node name="PlayerShip" parent="Node" instance=ExtResource("2_0xm2m")]
|
||||
transform = Transform3D(-0.0337657, 0, -0.99943, 0, 1, 0, 0.99943, 0, -0.0337657, -20.7388, 9.76772, -1.42542)
|
||||
_start_direction = Vector3(1, 0.5, 0)
|
||||
_start_speed = 100.0
|
||||
|
||||
[node name="Marker3D" type="Marker3D" parent="Node" unique_id=1294508738]
|
||||
[node name="Marker3D" type="Marker3D" parent="Node"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.147182, -10.5201)
|
||||
gizmo_extents = 5.03
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Node/Marker3D" unique_id=545308513]
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Node/Marker3D"]
|
||||
transform = Transform3D(0.189904, 0, 0, 0, 0.189904, 0, 0, 0, 0.189904, 0, 0, 0)
|
||||
mesh = SubResource("SphereMesh_0xm2m")
|
||||
|
||||
[node name="Obstacle2" parent="Node" unique_id=579337740 instance=ExtResource("1_ig7tw")]
|
||||
[node name="Obstacle2" parent="Node" instance=ExtResource("1_ig7tw")]
|
||||
transform = Transform3D(0.635485, -0.772113, 0, 0.772113, 0.635485, 0, 0, 0, 1, -6.93043, 24.3938, -1.34355)
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Node" unique_id=257615271]
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Node"]
|
||||
transform = Transform3D(11.7541, 0, 0, 0, 1, 0, 0, 0, 11.7541, 0, -7, 0)
|
||||
mesh = SubResource("PlaneMesh_h2yge")
|
||||
skeleton = NodePath("../..")
|
||||
|
||||
[node name="Thruster Cube" parent="." unique_id=580986924 instance=ExtResource("3_h2yge")]
|
||||
[node name="Thruster Cube" parent="." instance=ExtResource("3_h2yge")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -11.2033)
|
||||
mass = 200.0
|
||||
script = ExtResource("4_10w3i")
|
||||
_start_direction = Vector3(0, 0, 0)
|
||||
_start_speed = 0.0
|
||||
@@ -1,134 +0,0 @@
|
||||
# Godot Experiments - Project Structure
|
||||
|
||||
## Overview
|
||||
|
||||
One Godot project containing multiple self-contained experiments.
|
||||
Each experiment lives in its own folder under `Experiments/` with its own scenes, scripts, assets and UI.
|
||||
Shared code and assets used across experiments live in `Core/`.
|
||||
|
||||
---
|
||||
|
||||
## Folder Tree
|
||||
|
||||
```
|
||||
res://
|
||||
│
|
||||
├── main.tscn # Project entry point / experiment selector
|
||||
├── project.godot
|
||||
│
|
||||
├── Core/ # Shared across ALL experiments
|
||||
│ ├── Components/
|
||||
│ │ ├── back_to_main.gd # Navigation: return to main menu
|
||||
│ │ ├── open_level_component.gd # Navigation: open a level
|
||||
│ │ └── quit_game_component.gd # Navigation: quit game
|
||||
│ └── Assets/
|
||||
│ └── PixelPlanets/ # Shared planet sprites/textures
|
||||
│
|
||||
├── Experiments/
|
||||
│ │
|
||||
│ ├── Recuration/ # Top-down space game with solar system generation
|
||||
│ │ ├── Scenes/
|
||||
│ │ │ ├── Recuration.tscn # Main scene
|
||||
│ │ │ ├── SolarSystem.tscn # Solar system root node
|
||||
│ │ │ ├── Planet.tscn # Reusable planet scene
|
||||
│ │ │ └── Star.tscn # Star scene
|
||||
│ │ ├── Scripts/
|
||||
│ │ │ ├── recuration_camera.gd # Top-down pan + zoom camera
|
||||
│ │ │ ├── resource_component.gd # Planet resource data
|
||||
│ │ │ └── solar_system_generator.gd # Procedural system generation
|
||||
│ │ ├── UI/
|
||||
│ │ │ ├── UI.tscn # HUD root
|
||||
│ │ │ ├── ui.gd # HUD logic
|
||||
│ │ │ └── planet_info_panel.tscn # Click-to-inspect planet panel
|
||||
│ │ ├── Assets/
|
||||
│ │ │ └── TheMoon/
|
||||
│ │ │ ├── TheMoon.tscn
|
||||
│ │ │ └── TheMoon.gd
|
||||
│ │ └── Planning/
|
||||
│ │ └── Movement 2D.svg # Design / planning diagrams
|
||||
│ │
|
||||
│ ├── SpaceMove/ # 2D space movement experiment
|
||||
│ │ ├── Scenes/
|
||||
│ │ │ ├── space_move.tscn
|
||||
│ │ │ └── space_test.tscn
|
||||
│ │ ├── Scripts/
|
||||
│ │ │ ├── player_ship.gd
|
||||
│ │ │ └── ship_ai_component.gd
|
||||
│ │ └── Assets/
|
||||
│ │ └── player_ship.tscn
|
||||
│ │
|
||||
│ ├── ThrusterCube/ # Physics thruster experiment
|
||||
│ │ ├── Scenes/
|
||||
│ │ │ ├── thruster_cube.tscn
|
||||
│ │ │ ├── thruster_cube_collision.tscn
|
||||
│ │ │ └── obstacle.tscn
|
||||
│ │ ├── Scripts/
|
||||
│ │ │ └── thruster_cube.gd
|
||||
│ │ └── Assets/
|
||||
│ │ ├── Thruster Cube.glb
|
||||
│ │ └── Thruster Cube Collision.glb
|
||||
│ │
|
||||
│ └── PidTest/ # PID controller experiment
|
||||
│ ├── Scenes/
|
||||
│ │ └── pid_test.tscn
|
||||
│ ├── Scripts/
|
||||
│ │ └── pid_test.gd
|
||||
│ └── Assets/
|
||||
│ ├── PID_Spinning_Stuff.glb
|
||||
│ ├── PID_Spinning_Target.glb
|
||||
│ └── PID_Test_Obj.blend
|
||||
│
|
||||
└── dist/ # Web export output (auto-generated, do not edit)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rules
|
||||
|
||||
### 1. Each experiment is self-contained
|
||||
|
||||
All scenes, scripts, assets and UI for an experiment live inside its own folder.
|
||||
Deleting an experiment folder should not break anything else.
|
||||
|
||||
### 2. Core is for shared things only
|
||||
|
||||
Only put something in `Core/` if **two or more** experiments use it.
|
||||
When in doubt, keep it inside the experiment.
|
||||
|
||||
### 3. Move files inside Godot, not in Explorer
|
||||
|
||||
Always use Godot's **FileSystem panel** to move files.
|
||||
This keeps UID references intact and prevents broken scene paths.
|
||||
|
||||
### 4. Naming conventions
|
||||
|
||||
| Type | Convention | Example |
|
||||
| --------- | ---------------------- | --------------------------------------- |
|
||||
| Folders | `PascalCase` | `Recuration/`, `ThrusterCube/` |
|
||||
| Scenes | `snake_case.tscn` | `solar_system.tscn` |
|
||||
| Scripts | `snake_case.gd` | `recuration_camera.gd` |
|
||||
| Classes | `PascalCase` | `class_name RecurationCamera` |
|
||||
| Variables | `snake_case` | `var orbit_radius: float` |
|
||||
| Constants | `SCREAMING_SNAKE_CASE` | `const AU_TO_PIXELS := 100.0` |
|
||||
| Signals | `snake_case` | `signal planet_clicked(planet: Planet)` |
|
||||
|
||||
---
|
||||
|
||||
## Adding a New Experiment
|
||||
|
||||
1. Create a new folder under `Experiments/YourExperimentName/`
|
||||
2. Add the standard subfolders: `Scenes/`, `Scripts/`, `Assets/`
|
||||
3. Add a `UI/` folder if the experiment needs one
|
||||
4. Add an entry in `main.tscn` to open it
|
||||
5. Only move shared code to `Core/` once a second experiment needs it
|
||||
|
||||
---
|
||||
|
||||
## Gitea CI
|
||||
|
||||
CI workflows live in `.gitea/workflows/`:
|
||||
|
||||
- `release.yml` — builds and publishes a release
|
||||
- `sonar.yml` — code quality analysis
|
||||
|
||||
Web export output is in `dist/` and should be in `.gitignore` if you do not want to commit build artifacts.
|
||||
@@ -1,95 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 400 400">
|
||||
|
||||
<!-- Outer badge — square 1:1 -->
|
||||
<rect width="396" height="396" x="2" y="2" fill="#2b3148" stroke="#181d2e" stroke-width="4"
|
||||
rx="20"
|
||||
style="fill:rgb(43, 49, 72);stroke:rgb(24, 29, 46);color:rgb(255, 255, 255);stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
|
||||
<!-- Subtle inner glow border -->
|
||||
<rect width="372" height="372" x="14" y="14" fill="none" stroke="#3a4460" stroke-width="1" rx="14"
|
||||
style="fill:none;stroke:rgb(58, 68, 96);color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
|
||||
<!-- Top label: CATTLE GAMES -->
|
||||
<text x="200" y="46" font-family="sans-serif" font-size="13" font-weight="700" fill="#7a8eb0"
|
||||
letter-spacing="4" text-anchor="middle"
|
||||
style="fill:rgb(122, 142, 176);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:sans-serif;font-size:13px;font-weight:700;text-anchor:middle;dominant-baseline:auto">CATTLE
|
||||
GAMES</text>
|
||||
|
||||
<!-- Godot robot — centered, large -->
|
||||
<g transform="translate(200,195) scale(0.155)"
|
||||
style="fill:rgb(0, 0, 0);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto">
|
||||
<g transform="translate(-512,-512)"
|
||||
style="fill:rgb(0, 0, 0);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto">
|
||||
<g fill="#fff"
|
||||
style="fill:rgb(255, 255, 255);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto">
|
||||
<path d="M105 673v33q407 354 814 0v-33z"
|
||||
style="fill:rgb(255, 255, 255);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
<path fill="#478cbf"
|
||||
d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"
|
||||
style="fill:rgb(71, 140, 191);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
<path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"
|
||||
style="fill:rgb(255, 255, 255);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
<circle cx="725" cy="526" r="90"
|
||||
style="fill:rgb(255, 255, 255);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
<circle cx="299" cy="526" r="90"
|
||||
style="fill:rgb(255, 255, 255);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
</g>
|
||||
<g fill="#2b2d3a"
|
||||
style="fill:rgb(43, 45, 58);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto">
|
||||
<circle cx="307" cy="532" r="60"
|
||||
style="fill:rgb(43, 45, 58);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
<circle cx="717" cy="532" r="60"
|
||||
style="fill:rgb(43, 45, 58);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- Horizontal divider above bottom section -->
|
||||
<line x1="30" y1="300" x2="370" y2="300" stroke="#3a4460" stroke-width="1"
|
||||
style="fill:rgb(0, 0, 0);stroke:rgb(58, 68, 96);color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
|
||||
<!-- Bottom section: two columns -->
|
||||
|
||||
<!-- Left: Powered by Godot -->
|
||||
<text x="40" y="325" font-family="sans-serif" font-size="9" fill="#5a6a8a" letter-spacing="1.5"
|
||||
style="fill:rgb(90, 106, 138);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:sans-serif;font-size:9px;font-weight:400;text-anchor:start;dominant-baseline:auto">POWERED
|
||||
BY</text>
|
||||
<text x="40" y="346" font-family="sans-serif" font-size="17" font-weight="700" fill="#478cbf"
|
||||
style="fill:rgb(71, 140, 191);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:sans-serif;font-size:17px;font-weight:700;text-anchor:start;dominant-baseline:auto">Godot
|
||||
Engine</text>
|
||||
|
||||
<!-- Vertical divider -->
|
||||
<line x1="215" y1="308" x2="215" y2="372" stroke="#3a4460" stroke-width="1"
|
||||
style="fill:rgb(0, 0, 0);stroke:rgb(58, 68, 96);color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
|
||||
<!-- Right: Experimental Port badge -->
|
||||
<text x="232" y="325" font-family="sans-serif" font-size="9" fill="#5a6a8a" letter-spacing="1.5"
|
||||
style="fill:rgb(90, 106, 138);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:sans-serif;font-size:9px;font-weight:400;text-anchor:start;dominant-baseline:auto">RELEASE
|
||||
TYPE</text>
|
||||
|
||||
<!-- Warning triangle -->
|
||||
<polygon points="232,355 240,341 248,355" fill="#e8922a"
|
||||
style="fill:rgb(232, 146, 42);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
<text x="240" y="353" font-family="sans-serif" font-size="7.5" font-weight="700" fill="#2b3148"
|
||||
text-anchor="middle" dominant-baseline="central"
|
||||
style="fill:rgb(43, 49, 72);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:sans-serif;font-size:7.5px;font-weight:700;text-anchor:middle;dominant-baseline:central">
|
||||
!</text>
|
||||
|
||||
<text x="253" y="350" font-family="sans-serif" font-size="13" font-weight="700" fill="#e8922a"
|
||||
style="fill:rgb(232, 146, 42);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:sans-serif;font-size:13px;font-weight:700;text-anchor:start;dominant-baseline:auto">
|
||||
Experimental</text>
|
||||
<text x="253" y="366" font-family="sans-serif" font-size="11" fill="#8a9ab8"
|
||||
style="fill:rgb(138, 154, 184);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:sans-serif;font-size:11px;font-weight:400;text-anchor:start;dominant-baseline:auto">
|
||||
Port</text>
|
||||
|
||||
<!-- Corner accent dots -->
|
||||
<circle cx="30" cy="30" r="3" fill="#3a4460"
|
||||
style="fill:rgb(58, 68, 96);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
<circle cx="370" cy="30" r="3" fill="#3a4460"
|
||||
style="fill:rgb(58, 68, 96);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
<circle cx="30" cy="370" r="3" fill="#3a4460"
|
||||
style="fill:rgb(58, 68, 96);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
<circle cx="370" cy="370" r="3" fill="#3a4460"
|
||||
style="fill:rgb(58, 68, 96);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto" />
|
||||
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 994 B |
@@ -1,25 +1,11 @@
|
||||
[gd_scene format=3 uid="uid://djelupqdj4wgd"]
|
||||
|
||||
[ext_resource type="Script" path="res://Core/Components/open_level_component.gd" id="1_ig7tw"]
|
||||
[ext_resource type="PackedScene" uid="uid://dgst4apmowe53" path="res://Experiments/SpaceMove/Scenes/space_test.tscn" id="2_1bvp3"]
|
||||
[ext_resource type="PackedScene" uid="uid://caj5t8q1fii5m" path="res://Experiments/PidTest/Scenes/pid_test.tscn" id="4_7mycd"]
|
||||
[ext_resource type="PackedScene" uid="uid://cycayd4l7k7s4" path="res://Experiments/Recuration/Scenes/Recuration.tscn" id="5_lquwl"]
|
||||
[ext_resource type="Script" path="res://Core/Components/quit_game_component.gd" id="6_7mycd"]
|
||||
|
||||
[sub_resource type="PackedScene" id="PackedScene_lquwl"]
|
||||
_bundled = {
|
||||
"conn_count": 0,
|
||||
"conns": PackedInt32Array(),
|
||||
"editable_instances": [],
|
||||
"id_paths": [],
|
||||
"names": PackedStringArray("SpaceMove", "Node3D"),
|
||||
"node_count": 1,
|
||||
"node_ids": PackedInt32Array(0),
|
||||
"node_paths": [],
|
||||
"nodes": PackedInt32Array(-1, -1, 1, 0, -1, 0, 0),
|
||||
"variants": [],
|
||||
"version": 3
|
||||
}
|
||||
[ext_resource type="Script" uid="uid://bel5yfuiqithe" path="res://open_level_component.gd" id="1_ig7tw"]
|
||||
[ext_resource type="PackedScene" uid="uid://dgst4apmowe53" path="res://Levels/space_test.tscn" id="2_1bvp3"]
|
||||
[ext_resource type="PackedScene" uid="uid://jynlgkm41y8d" path="res://Levels/space_move.tscn" id="3_lquwl"]
|
||||
[ext_resource type="PackedScene" uid="uid://caj5t8q1fii5m" path="res://Levels/pid_test.tscn" id="4_7mycd"]
|
||||
[ext_resource type="PackedScene" uid="uid://cycayd4l7k7s4" path="res://Levels/Recuration.tscn" id="5_lquwl"]
|
||||
[ext_resource type="Script" uid="uid://lh1hhx4q8nlu" path="res://quit_game_component.gd" id="6_7mycd"]
|
||||
|
||||
[node name="Main" type="Control" unique_id=834120395]
|
||||
layout_mode = 3
|
||||
@@ -48,6 +34,7 @@ text = "space_test"
|
||||
[node name="OpenLevelComponent" type="Node" parent="VBoxContainer/Button" unique_id=1834050455]
|
||||
script = ExtResource("1_ig7tw")
|
||||
level = ExtResource("2_1bvp3")
|
||||
metadata/_custom_type_script = "uid://bel5yfuiqithe"
|
||||
|
||||
[node name="Button2" type="Button" parent="VBoxContainer" unique_id=93954602]
|
||||
layout_mode = 2
|
||||
@@ -56,7 +43,8 @@ text = "space_move
|
||||
|
||||
[node name="OpenLevelComponent" type="Node" parent="VBoxContainer/Button2" unique_id=1732413263]
|
||||
script = ExtResource("1_ig7tw")
|
||||
level = SubResource("PackedScene_lquwl")
|
||||
level = ExtResource("3_lquwl")
|
||||
metadata/_custom_type_script = "uid://bel5yfuiqithe"
|
||||
|
||||
[node name="Button3" type="Button" parent="VBoxContainer" unique_id=1480596145]
|
||||
layout_mode = 2
|
||||
@@ -65,6 +53,7 @@ text = "pid_test"
|
||||
[node name="OpenLevelComponent" type="Node" parent="VBoxContainer/Button3" unique_id=1820153918]
|
||||
script = ExtResource("1_ig7tw")
|
||||
level = ExtResource("4_7mycd")
|
||||
metadata/_custom_type_script = "uid://bel5yfuiqithe"
|
||||
|
||||
[node name="Button4" type="Button" parent="VBoxContainer" unique_id=955421861]
|
||||
layout_mode = 2
|
||||
@@ -73,6 +62,7 @@ text = "Recuration"
|
||||
[node name="OpenLevelComponent" type="Node" parent="VBoxContainer/Button4" unique_id=292657034]
|
||||
script = ExtResource("1_ig7tw")
|
||||
level = ExtResource("5_lquwl")
|
||||
metadata/_custom_type_script = "uid://bel5yfuiqithe"
|
||||
|
||||
[node name="Button5" type="Button" parent="VBoxContainer" unique_id=630288499]
|
||||
layout_mode = 2
|
||||
@@ -80,3 +70,4 @@ text = "Exit Experements"
|
||||
|
||||
[node name="QuitGame" type="Node" parent="VBoxContainer/Button5" unique_id=1111277542]
|
||||
script = ExtResource("6_7mycd")
|
||||
metadata/_custom_type_script = "uid://lh1hhx4q8nlu"
|
||||
|
||||
@@ -20,6 +20,10 @@ config/features=PackedStringArray("4.6", "Forward Plus")
|
||||
boot_splash/bg_color=Color(0, 0, 0, 1)
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[autoload]
|
||||
|
||||
BackToMain="*res://back_to_main.gd"
|
||||
|
||||
[filesystem]
|
||||
|
||||
import/blender/enabled.android=true
|
||||
|
||||