Planet setup map editor #48

Closed
opened 2026-08-15 11:16:22 +00:00 by metaheavens · 1 comment
Owner

Part of #40. Depends on the planet-setups ticket (data format) and the main-menu ticket (entry point).

map editor in the main menu, which will let me create various setups for each planet type [...] all setups created should be saved within the game itself, as a dedicated scene, not just in a game save

Scope

  1. PlanetSetupEditor.tscn + PlanetSetupEditor.gd, reachable from the main menu, 720x1280 touch UI in the existing idiom.
  2. Profile picker - choose which surface profile the setup is authored for; drive the background from PlanetSurfaceProfiles.get_profile(id) so the canvas shows the real surface appearance rather than a blank sheet.
  3. Palette - capture point, plus one entry per EnemyDefinitions entry. Generated from the registry, never hardcoded, so a new enemy definition shows up automatically. Draw each entry with its definition's hull and colour.
  4. Interaction - tap a palette entry to select it, tap the canvas to place, drag a placed item to move it, tap to select and a delete button to remove. Pan and pinch-zoom the canvas using the camera idiom already in Main.tscn/TouchJoystick.gd. Show a grid or origin marker so positions are judgeable - the fleet lands at Vector2.ZERO.
  5. Load / new / name - open any existing setup from PlanetSetups for editing, or start a new one and name it.
  6. Save - ResourceSaver.save() to res://PlanetSetups/<setup_id>.tres, producing exactly the PlanetSetup + PlanetSetupSpawn structure the game already loads.
    • Known constraint: res:// is writable only when running from the project (the Godot editor, or the Godot Android app this project is opened with) - never from an exported build. Guard the save and show a clear message ("setups can only be saved when running from the project") instead of failing silently. Do not add a user:// fallback: #40 requires setups to live in the game as committed resources.
    • The registry scans res://PlanetSetups/ with DirAccess, so a newly saved file is picked up without touching any code; a Godot reimport may be needed before it appears.
  7. The editor must not touch GameState gameplay state.

Acceptance criteria

  • Place 3 capture points and 2 enemies for the rocky profile, save, return to the menu, Play, land on a planet that resolves to that setup, and find exactly those points and enemies at those positions.
  • Reopening the saved setup in the editor shows the same items and lets them be moved and deleted.
  • A new enemy definition added to EnemyDefinitions appears in the palette with no editor code change.
  • In a build where res:// is not writable, saving reports the reason instead of appearing to succeed.

Tests

tests/test_setup_editor.gd - drive the editor's model directly (place / move / delete / save / reload) and assert the saved resource round-trips; the touch layer itself can stay out of the headless test. bash tests/run_tests.sh editor, plus a 720x1280 screenshot of the editor with items placed.

Repo notes (read before starting)

  • Godot 4.7.1, portrait 720x1280, touch UI. Project dir: /storage/emulated/0/GodotProjects/SpaceshipTest.
  • After editing any project file, run touch on it. Android FUSE does not bump mtime under ~/storage/shared, and Godot's import cache will silently keep serving the old version, making a correct fix look like it did nothing.
  • Headless tests: bash tests/run_tests.sh <substring>; full suite with no argument. Tests are SceneTree scripts printing TEST_NAME: PASS / TEST_NAME: FAIL (reason) and calling quit(0|1) - copy the shape of tests/test_gas_bomber_cooldowns.gd.
  • Real screenshots: bash tests/screenshot.sh <res://Scene.tscn> <out.png> <frames> 720x1280. Use few frames (~10-20); the software rasterizer is slow. --headless renders nothing at all, so it cannot validate visuals.
  • Drawing goes through NeonDraw / NeonPiece; do not introduce a different visual idiom.
  • The repo deliberately has no type switches left (tickets #31-#35): behaviour comes from *Definition resources plus capability component scenes. Do not add if type == "..." branches.
  • There is no persistence layer (no FileAccess, no user:// anywhere outside this ticket's explicit scope). GameState is an in-memory autoload. Do not invent a save system.
  • Commit each ticket separately and run the full suite before pushing.
Part of #40. Depends on the planet-setups ticket (data format) and the main-menu ticket (entry point). > map editor in the main menu, which will let me create various setups for each planet type [...] all setups created should be saved within the game itself, as a dedicated scene, not just in a game save ### Scope 1. `PlanetSetupEditor.tscn` + `PlanetSetupEditor.gd`, reachable from the main menu, 720x1280 touch UI in the existing idiom. 2. **Profile picker** - choose which surface profile the setup is authored for; drive the background from `PlanetSurfaceProfiles.get_profile(id)` so the canvas shows the real surface appearance rather than a blank sheet. 3. **Palette** - capture point, plus one entry per `EnemyDefinitions` entry. Generated from the registry, never hardcoded, so a new enemy definition shows up automatically. Draw each entry with its definition's hull and colour. 4. **Interaction** - tap a palette entry to select it, tap the canvas to place, drag a placed item to move it, tap to select and a delete button to remove. Pan and pinch-zoom the canvas using the camera idiom already in `Main.tscn`/`TouchJoystick.gd`. Show a grid or origin marker so positions are judgeable - the fleet lands at `Vector2.ZERO`. 5. **Load / new / name** - open any existing setup from `PlanetSetups` for editing, or start a new one and name it. 6. **Save** - `ResourceSaver.save()` to `res://PlanetSetups/<setup_id>.tres`, producing exactly the `PlanetSetup` + `PlanetSetupSpawn` structure the game already loads. - **Known constraint:** `res://` is writable only when running from the project (the Godot editor, or the Godot Android app this project is opened with) - never from an exported build. Guard the save and show a clear message ("setups can only be saved when running from the project") instead of failing silently. Do **not** add a `user://` fallback: #40 requires setups to live in the game as committed resources. - The registry scans `res://PlanetSetups/` with `DirAccess`, so a newly saved file is picked up without touching any code; a Godot reimport may be needed before it appears. 7. The editor must not touch `GameState` gameplay state. ### Acceptance criteria - Place 3 capture points and 2 enemies for the rocky profile, save, return to the menu, Play, land on a planet that resolves to that setup, and find exactly those points and enemies at those positions. - Reopening the saved setup in the editor shows the same items and lets them be moved and deleted. - A new enemy definition added to `EnemyDefinitions` appears in the palette with no editor code change. - In a build where `res://` is not writable, saving reports the reason instead of appearing to succeed. ### Tests `tests/test_setup_editor.gd` - drive the editor's model directly (place / move / delete / save / reload) and assert the saved resource round-trips; the touch layer itself can stay out of the headless test. `bash tests/run_tests.sh editor`, plus a 720x1280 screenshot of the editor with items placed. ### Repo notes (read before starting) - Godot 4.7.1, portrait 720x1280, touch UI. Project dir: `/storage/emulated/0/GodotProjects/SpaceshipTest`. - **After editing any project file, run `touch` on it.** Android FUSE does not bump mtime under `~/storage/shared`, and Godot's import cache will silently keep serving the old version, making a correct fix look like it did nothing. - Headless tests: `bash tests/run_tests.sh <substring>`; full suite with no argument. Tests are `SceneTree` scripts printing `TEST_NAME: PASS` / `TEST_NAME: FAIL (reason)` and calling `quit(0|1)` - copy the shape of `tests/test_gas_bomber_cooldowns.gd`. - Real screenshots: `bash tests/screenshot.sh <res://Scene.tscn> <out.png> <frames> 720x1280`. Use few frames (~10-20); the software rasterizer is slow. `--headless` renders nothing at all, so it cannot validate visuals. - Drawing goes through `NeonDraw` / `NeonPiece`; do not introduce a different visual idiom. - The repo deliberately has **no type switches** left (tickets #31-#35): behaviour comes from `*Definition` resources plus capability component scenes. Do not add `if type == "..."` branches. - There is **no persistence layer** (no `FileAccess`, no `user://` anywhere outside this ticket's explicit scope). `GameState` is an in-memory autoload. Do not invent a save system. - Commit each ticket separately and run the full suite before pushing.
Author
Owner

Implemented and pushed as df2f252.

  • PlanetSetupEditor authors PlanetSetup resources: pick a surface profile (drives the real lunar_surface background, not a blank sheet), place/move/delete capture points and enemies from a palette generated straight off EnemyDefinitions.all() (a new enemy definition shows up with no editor change), pan/pinch-zoom the canvas with the same touch idiom as GameController, then save to res://PlanetSetups/<id>.tres via ResourceSaver.
  • Reachable now from the main menu's Map Editor button (enabled - #47 shipped it disabled/"coming soon" pending this ticket).
  • The mutation methods (new_setup/load_setup/add_*/move_*/remove_*/save_setup) are the whole model and work standalone, which is what let tests/test_setup_editor.gd drive placement/move/delete/save/reload directly without simulating touch input, per the ticket's own guidance.

Verified: placed 3 capture points + 2 enemies, saved, reopened in a fresh editor instance, confirmed exact round-trip, moved/deleted after reopening. Palette entry count is asserted against EnemyDefinitions.all().size() + 1 rather than a hardcoded number, so it stays correct as more enemy types land. Verified visually at 720x1280 with items placed, selection highlighting, and the dynamic palette all visible.

Every cross-file reference in this file is a preloaded script const rather than a bare global class name, matching #42/#44's load-order notes.

This closes out the #40 breakdown: #41-#48 are now all implemented, tested, and merged.

Implemented and pushed as `df2f252`. - `PlanetSetupEditor` authors `PlanetSetup` resources: pick a surface profile (drives the real lunar_surface background, not a blank sheet), place/move/delete capture points and enemies from a palette generated straight off `EnemyDefinitions.all()` (a new enemy definition shows up with no editor change), pan/pinch-zoom the canvas with the same touch idiom as `GameController`, then save to `res://PlanetSetups/<id>.tres` via `ResourceSaver`. - Reachable now from the main menu's Map Editor button (enabled - #47 shipped it disabled/"coming soon" pending this ticket). - The mutation methods (`new_setup`/`load_setup`/`add_*`/`move_*`/`remove_*`/`save_setup`) are the whole model and work standalone, which is what let `tests/test_setup_editor.gd` drive placement/move/delete/save/reload directly without simulating touch input, per the ticket's own guidance. Verified: placed 3 capture points + 2 enemies, saved, reopened in a fresh editor instance, confirmed exact round-trip, moved/deleted after reopening. Palette entry count is asserted against `EnemyDefinitions.all().size() + 1` rather than a hardcoded number, so it stays correct as more enemy types land. Verified visually at 720x1280 with items placed, selection highlighting, and the dynamic palette all visible. Every cross-file reference in this file is a preloaded script const rather than a bare global class name, matching #42/#44's load-order notes. This closes out the #40 breakdown: #41-#48 are now all implemented, tested, and merged.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
metaheavens/spaceship#48
No description provided.