Dev Log โ 14 April 2026
I picked up directly from where the 13 April session ended. I’d written all 7 menu GDScript files but hadn’t created any of the .tscn scene files yet. This session I covered:
- Creating all 7 menu scene files (.tscn)
- Updating GameManager, GameScene, HUD with new settings fields and wiring
- A series of bug fixes after first in-editor test
- UI polish and layout improvements based on user feedback
- Level Select redesign (5ร5 grid, game-kit level icon images)
- Main Menu container freedom (removed VBoxContainer constraint)
| Scene | Type | Notes |
|---|---|---|
| scenes/menus/Splash.tscn | Node2D | Starfield + planet decorations + logo + “TAP TO PLAY” |
| scenes/menus/MainMenu.tscn | Node2D + CanvasLayer | Background, planets, play/endless/settings/shop buttons |
| scenes/menus/LevelSelect.tscn | Node2D + CanvasLayer | Panel frame, grid, prev/next pagination |
| scenes/menus/CharacterShop.tscn | Node2D + CanvasLayer | 3ร3 ship grid, coins row, play button |
| scenes/menus/Settings.tscn | CanvasLayer (overlay) | Music/SFX/Fullscreen toggles, close button |
| scenes/menus/PauseMenu.tscn | CanvasLayer (overlay) | Resume/Settings/Main Menu, layer=10, process_mode=Always |
| scenes/menus/LevelComplete.tscn | CanvasLayer (overlay) | Stars display, score, retry/next buttons, layer=10 |
GameManager.gd: Settings persistence
NEW Added three fields to persistent save data:
Saved under a [settings] section in user://save.cfg alongside existing player data.
GameScene.gd: Pause input + Level Complete handoff
NEW Added _unhandled_input() to handle the action_pause action (Escape / P). Instantiates PauseMenu as a CanvasLayer overlay on the current scene.
CHANGED_level_complete() no longer calls hud.show_level_complete(). Instead, instantiates LevelComplete.tscn and calls setup(stars, score) on it.
HUD.gd: Rank badge, pause button, simplified
NEW Rank badge display: loads Sci Fi Ranks/Sliver Ranks/Rank Silver N.png based on current_rank. Falls back to Rank Silver 12 if rank 13 (missing from assets) is requested.
NEW Pause button wired: PauseButton.pressed โ instantiates PauseMenu and adds it to get_tree().current_scene.
CHANGED Removed show_level_complete() method; responsibility moved to GameScene. Kept show_game_over() in HUD.
CHANGED Node hierarchy: LeftWidget Control houses points_powerup_lifes.png background, RankBadge TextureRect (70ร70 on the circle), ScoreLabel, and HealthDisplay.
MainMenu.gd: Live coin count
NEWBtnCoins text is populated in _ready() from gm.coins and updates via coins_changed signal.
LevelSelect.gd: 5ร5 grid, level icon images
CHANGEDLEVELS_PER_PAGE changed from 12 to 25. All 24 levels now fit on a single page, so the pagination buttons hide automatically.
CHANGED Level tile now uses Game Assests/UI/Levels/Level N.png as the tile frame image, with the level number as a Neuropol label overlaid in the centre. Locked tiles use Game Assests/UI/Level Locked.png.
CHANGED Tile styling: transparent Button StyleBox, with all visual style coming from the icon image.
| Bug | Root Cause | Fix |
|---|---|---|
| BUG Pause button invisible in HUD | TextureButton used anchor-based layout (anchor_left=1.0) as a direct CanvasLayer child. CanvasLayer children don’t resolve anchors against viewport size reliably. | Switched to layout_mode = 0 with absolute pixel coords: offset_left=1836, offset_right=1908 (72px button, 12px from right edge of 1920px canvas). |
| BUG Settings menu unresponsive when opened from Pause | get_tree().paused = true is set by PauseMenu. Settings.tscn root node had no process_mode, so it defaulted to Inherit โ paused state โ no input processed. | Added process_mode = 3 (PROCESS_MODE_ALWAYS) to the Settings CanvasLayer root. Also confirmed PauseMenu already has this set. |
| BUG Splash showed wrong background | Scene used a solid ColorRect. Needed the game’s starfield background matching all other screens. | Replaced ColorRect with Game Assests/Backgrounds/Background/background_01_parallax_01.png TextureRect + PTModelSprite_ID61659.png planet decorations top-left and bottom-right. |
| BUG Menu backgrounds not filling screen | TextureRect stretch_mode = 5 (KEEP_ASPECT_CENTERED) letterboxes the image. expand_mode was set but stretch mode was wrong. | Changed to stretch_mode = 0 (SCALE) on all menu background TextureRects. Image is 1920ร1080 so distortion is not an issue. |
| BUG Rank badge too large / overflowing circle | RankBadge TextureRect was sized at ~80ร80 but positioned incorrectly relative to the circular portion of points_powerup_lifes.png. | Resized to 70ร70, positioned at offset (6, 6) โ (76, 76) within the LeftWidget. Final fine-tuning done in editor. |
Consistent background system across all screens
Every menu screen now uses the same background stack:
- background_01_parallax_01.png (starfield, stretch_mode=SCALE, full 1920ร1080)
- PTModelSprite_ID9256.png or PTModelSprite_ID61669.png: planet top-left and bottom-right
- CanvasLayer UI above
Panel frame asset wired in
Assests/GUI/PNG/window_whole_alpha.png (teal border frame with transparent centre) is included as a PanelFrame TextureRect in all panel-style screens. Size and position are tunable in the Godot editor.
VBoxContainer removed from Main Menu
The Buttons node was a VBoxContainer, which forced child Controls to a fixed layout, preventing free movement in the editor. Changed to a plain Control node. BtnPlay and BtnEndless switched from layout_mode = 2 (container-driven) to layout_mode = 0 (absolute). Both buttons can now be freely moved and resized in the 2D editor.
Level Select: 5ร5 grid
Changed from 6-column 2-page layout to a 5-column single-page layout. All 24 levels displayed at once (25th slot is empty). Tile spacing increased to h=16 / v=20. Pagination buttons hidden when total pages = 1.
Button background colour
Inspector โ Theme Overrides โ Styles โ Normal โ New StyleBoxFlat โ Bg Color. Repeat for Hover and Pressed states.
Button icons
Two options:
- Button with icon: set the Icon property in Inspector. Tick Expand Icon to fill. Clear text for icon-only.
- TextureButton: right-click node โ Change Type โ TextureButton. Assign texture_normal / texture_hover / texture_pressed. Assets available: Game Assests/UI/Settings Button.png, Shop Button.png, Restart.png.
Panel frame sizing
The PanelFrame TextureRect in each scene is wired with the teal frame image. Drag edges in the 2D canvas to match the content area. No code change required.
Planet decoration positions
Each menu scene has PlanetTopLeft and PlanetBottomRight TextureRects as Node2D children (behind CanvasLayer). Select and move in the 2D editor to taste.
Complete
- All 7 menu scenes created and wired to their scripts
- Game flow: Splash โ MainMenu โ LevelSelect โ GameScene โ PauseMenu / LevelComplete
- Settings overlay works from both MainMenu and PauseMenu (with process_mode=Always)
- HUD: rank badge (with missing-rank-13 fallback), score, health, pause button
- GameManager persists music_enabled, sfx_enabled, fullscreen across sessions
- project.godot main scene set to Splash.tscn
- Level tiles use game-kit icon images + Neuropol number overlay
- CharacterShop buy/select logic complete
Carried into afternoon session
- Pause menu missing restart button
- Asteroid spawn system: all spawning on-screen simultaneously, no edge drift-in
- Level Select grid overflowing panel frame (5 rows too tall)
- Level tile hover detection unreliable (child Controls intercepting mouse events)
- Button hover box visible; I wanted scale-only feedback with no box
- MainMenu PlayButton spin animation not yet added
The previous context window ended just as the asteroid spawn rewrite was beginning. This continuation session picked up directly from that point, completing all outstanding requests from the prior message in sequence.
NEW Replaced the old simultaneous-spawn system with a staggered queue driven from 8 fixed edge points.
8 Fixed edge spawn points
Positions sit 200px outside the screen boundary, one at each midpoint and one at each corner:
Velocity toward screen center
Each edge-spawned asteroid is given a velocity aimed at the screen centre with a ยฑ25ยฐ spread so they drift in naturally rather than heading straight to the middle:
Initial on-screen burst (~25%)
At wave start, ~25% of the wave’s asteroids spawn immediately at the four screen quadrant positions (with ยฑ80px random offset). The rest are queued for staggered edge entry.
Level-scaled spawn interval
The queue drains at an interval that shrinks with each level, making higher levels feel increasingly hectic:
Wave completion
CHANGED Wave complete now requires bothasteroids_alive <= 0and_spawn_queue.is_empty(). Previously the wave could complete while asteroids were still waiting to spawn.
Off-screen cleanup
NEW Every 3 seconds, any asteroid that has drifted more than 500px beyond the screen boundary is silently removed. This prevents accumulation of off-screen RigidBody2D nodes over long play sessions.
Bug fixed: double-count
FIX The old _start_wave() pre-set asteroids_alive to the total count AND spawn_asteroid() also incremented it, effectively doubling the count. The new system resets asteroids_alive = 0 at wave start and lets spawn_asteroid() be the sole incrementor.
NEW Added a RESTART button between Settings and Main Menu in the pause VBox.
The handler unpauses the tree first, then reloads the current scene. The ordering is critical to avoid Godot’s paused-scene reload edge case:
Grid overflow fixed: 6ร4 layout
FIX The 5-column layout produced 5 rows of tiles. The grid’s available height was only 677px; 5 rows needed 955px, causing the last two rows to overflow the panel frame.
Fix: switched to 6 columns ร 4 rows. 24 รท 6 = exactly 4 rows with no orphan tiles. Tile size reduced to 148ร152 and separations tightened to h=12 / v=14 so everything fits cleanly:
| Before (5 col) | After (6 col) | |
|---|---|---|
| Rows needed | 5 rows โ 955px (overflows) | 4 rows โ 650px (fits) |
| Orphan tiles | 4th row incomplete | None (24 รท 6 = exact) |
| Tile size | 160 ร 175 | 148 ร 152 |
Hover detection fixed
FIX Mouse hover was unreliable because child Control nodes inside the Button tile were consuming mouse events before they reached the Button. The default mouse_filter for Control is MOUSE_FILTER_STOP.
Fix: set mouse_filter = MOUSE_FILTER_PASS on all non-interactive children inside each tile: vbox, icon_holder, icon, num_lbl, star_row, and each star Label.
Star row spacing tightened
CHANGED VBox separation reduced from 6 โ 2. Stars now sit immediately below the icon rather than floating away from it.
Hover box removed, scale tween added
CHANGED All button states (normal, hover, pressed, focus, disabled) now use StyleBoxEmpty. No box appears on hover. Instead, mouse_entered and mouse_exited run a 0.1s Tween that scales the tile 1.0 โ 1.1 and back, pivoted from the tile centre.
PlayButton 360ยฐ spin
NEW The MainButton1/Playbutton Sprite2D spins a full 360ยฐ when the cursor enters the Play button area (desktop) or the button is pressed (mobile/touch). A guard flag _spin_active prevents re-triggering mid-spin.
TAU = 2ฯ = one full rotation. Duration is 0.5 seconds with sine ease-in-out for a snappy but smooth feel.
How to add scale-on-hover to any other button
Here’s the pattern to apply it to Endless or any other menu button:
- Set btn.pivot_offset = btn.size / 2 in _ready() so the button scales from its centre, not its top-left corner.
- Connect mouse_entered โ scale to Vector2(1.1, 1.1) over 0.1s
- Connect mouse_exited โ scale back to Vector2(1.0, 1.0) over 0.1s
- Connect button_down โ same as mouse_entered (covers mobile touch)
How to remove the hover box on any button
Godot buttons draw a box on hover from the theme’s hover StyleBox. To remove it:
In the editor: Select the button โ Inspector โ Theme Overrides โ Styles โ set Normal, Hover, Pressed, and Focus each to New StyleBoxEmpty.
In code:
Complete
- All 7 menu scenes wired and functional
- Asteroid spawn system: staggered queue, 8 edge points, 25% on-screen burst, level-scaled interval, off-screen cleanup
- Asteroids no longer bounce off screen edges; they drift freely and collide only with each other
- Pause menu: Resume / Settings / Restart / Main Menu
- Level Select: 6ร4 grid (24 tiles exact), correct hover detection, scale tween, no hover box
- MainMenu PlayButton 360ยฐ spin on hover and touch
- Button hover/animation pattern documented for self-service application to remaining buttons
Still outstanding
- Apply hover scale + StyleBoxEmpty to Endless Mode button and any remaining menu buttons
- Panel frame sizing: visual adjustment in editor per screen
- HUD final pixel alignment
- Mobile joystick input not yet wired
- Audio bus muting on session start (respect saved music_enabled / sfx_enabled)
- Coin shop / IAP not implemented