Space-time distorder vessel and the fleet speed fader #59
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A researchable vessel that lets the whole fleet travel faster than its default cruise speed, controlled by a fader that appears on the right of the screen while such a vessel is in the fleet.
Scope
VesselDistorderComponent.tscn+.gd,capability_id = "distorder". It carries no per-shot behaviour; its presence is what matters, plus (later ticket) energy drain.GameState.fleet_speed_multiplier: float = 1.0(1.0 = today's behaviour), clamped to[1.0, MAX_MULTIPLIER](suggest 3.0).Ship.apply_vessel_stats()readsGameState.vessel_stat(...), andFleet.cruise_speeddrives the formation anchor. Multiply at the point of use rather than baking it into the stored stats, or researching a speed upgrade while boosted will corrupt the base value.Fleet.gd's header comment first: the anchor advances atcruise_speedwhile individual ships are allowed to exceed it to hold formation. Both need scaling, or the formation visibly stretches under boost.SpeedFader.gd+ a node on the right edge of theUIlayer in bothMain.tscnandPlanetSurface.tscn: a vertical drag control in the existing touch idiom (seeTouchJoystick.gdfor raw-touch handling and why these controls do not go through_gui_input), drawn withNeonDraw. Visible only whenfleet.has_capability("distorder").DistorderVesselDefinition.tres+ ship-lab unlock, registered inVesselDefinitions, with crafter/hangar nodes per #57's note.fleet_speed_multiplierto 1.0 and hides the fader - a fleet must never be left permanently boosted by a vessel it no longer has.Out of scope
Energy consumption while boosting - that is #62.
Acceptance criteria
Tests
tests/test_space_time_distorder.gd(bash tests/run_tests.sh distorder) measuring actual distance travelled per second at 1.0 vs a boosted multiplier, plus a 720x1280 screenshot of the fader.Repo notes (read before starting)
/storage/emulated/0/GodotProjects/SpaceshipTest.touchon 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.bash tests/run_tests.sh <substring>; full suite with no argument. Tests areSceneTreescripts printingTEST_NAME: PASS/TEST_NAME: FAIL (reason)and callingquit(0|1)- copy the shape oftests/test_capture_points.gd.bash tests/screenshot.sh <res://Scene.tscn> <out.png> <frames> 720x1280. Use few frames (~15); the software rasterizer is slow.--headlessrenders nothing at all, so it cannot validate visuals.NeonDraw/NeonPiece; do not introduce a different visual idiom.*Definitionresources plus capability component scenes. Do not addif type == "..."branches.FileAccess, nouser://).GameStateis an in-memory autoload. Do not invent a save system.Traps that have already cost hours on this codebase
const X = preload(...)in a test file that is itself the-sentry point. It evaluates during that file's own early compilation, which can run before autoloads are registered; any script it pulls in that referencesGameStateinside a function body then fails to compile withIdentifier not found: GameState. Usevar X: Scriptplusload()inside_initialize()instead. See the header comment intests/test_capture_points.gd.[]to a typedArray[Resource]export from another script fails at runtime - the compiler only sees the target asResourceand cannot confirm the element type. Leave the declared default alone, or build the typed array inside the owning script.Fleet.spawn_ships(0, ...)does not empty the fleet - it falls back to one default interceptor by design. Clearfleet.shipsexplicitly if a test or preview needs genuinely zero ships.ship.positionwithout also settingship.move_targetletsShip._physics_processsteer it straight back toward the stale target within a few frames.SceneTreetest's own_process()clock under device load, even with--fixed-fps 60. Gate waits on the system's own state (a component's timer or flag), not onelapsed >= duration.queue_free()s itself (projectiles, shells) must not be re-read inside a per-frame wait condition - cache the scalar you need before the wait._screenshot_tool.gd's_initialize(), so their_ready()races the game scene's own_ready(). Do setup on the first_process()tick, andget_tree().paused = trueonce everything is placed if the scene must hold still.Implemented and pushed in
116e0f9.GameState.fleet_speed_multiplier(1.0-3.0,MAX_FLEET_SPEED_MULTIPLIER) is applied at the point of use -Fleet's cruise anchor andShip's ownmax_speed/acceleration- rather than baked into stored stats, so a stat upgrade researched mid-boost can't corrupt the base value.Ship.arrive_radiusis also scaled by the multiplier: at higher speeds each physics tick covers a proportionally larger step, and once that step outgrows a fixedarrive_radiusthe ship can overshoot its snap-to-target zone every tick while chasing a target that's also now receding faster - visible as the fleet stretching apart under boost. Scaling it preserves the same tightness 1.0x already has.SpeedFader.gd: a self-contained vertical drag control (TouchJoystick's raw-touch idiom, not_gui_input) that writes straight to the autoload. Resets the multiplier to 1.0 the instantfleet.has_capability("distorder")goes false, so a fleet can never be left permanently boosted by a vessel it no longer has.VesselDistorderComponentcarries no per-shot behaviour (energy drain while boosted is #62) - its presence is what matters. Registered inVesselDefinitions, wired into the crafter/hangar/ship-lab menus.Tests:
tests/test_space_time_distorder.gd(bash tests/run_tests.sh distorder) - fader absent/visible with fleet composition, boosted vs baseline travel distance, formation holds together under sustained boost, losing the vessel resets the multiplier and hides the fader, and the multiplier/fader both survive a space -> surface scene swap. Full suite passed at the time.