Dev Log โ 15 May 2026
Session Overview
This session was driven entirely by playtesting. Two critical runtime bugs were discovered in the ship system: ships were rendering at the wrong size and the first ship was always visible regardless of which ship was selected. These were diagnosed and fixed correctly. The session also overhauled the BGS-1 and BGS-2 ships with a unique thruster and gun mechanic, tuned crystal/power-up drop rates, and added a debug coin button to the Character Shop.
- Fixed: Double-scaling bug: ships rendering at wrong size at runtime
- Fixed: Placeholder sprite always visible at game start
- Improved: Editor collision polygon workflow: active polygon now highlighted
- New: BGS-1 and BGS-2 unique thruster animation and side-firing gun mechanic
- Tuned: Coin drop rates reduced, power-up drop rates increased
- Added: Debug +1000 coins button in Character Shop
- Fixed: Viper thruster: now uses BGS-style 10-frame animation, single centre exhaust
- Rearchitected: All 18 ship scenes restructured so thruster position and scale can be set visually in the Godot editor without any code overrides
Ship Double-Scaling and an Always-Visible Placeholder Sprite
Bug 1: Ships at Wrong Size (Double-Scaling)
Ships were appearing at the wrong size at runtime. The SHIP_DISPLAY_SIZE dynamic scaling calculation appeared correct but the rendered result did not match the target 80 px.
Root cause:_ship_body was being added as a child of ShipBody (the placeholder Node2D), which still had an editor-saved scale baked into the .tscn file from previous tuning sessions (e.g. scale = Vector2(0.131, 0.131) for CP2). The dynamic scaling code then set a scale on _ship_body relative to that already-scaled parent, multiplying the two values together and producing a ship far smaller than intended.
Fix:_ship_body is now added directly to self (the CharacterBody2D) instead of inside ShipBody. Scale is set on _ship_body in world space, independent of any editor-saved parent scale. The dynamic calculation now produces the exact target size every time.
# Before (wrong โ inherits ShipBody's editor-saved scale):
placeholder.add_child(_ship_body)
# After (correct โ added directly to CharacterBody2D):
add_child(_ship_body)
Bug 2: Placeholder Sprite Always Visible
The first ship sprite (whichever was last previewed in the editor) was always visible at game start, overlaid on top of the actual equipped ship’s sprite. This was the ShipBody/Sprite2D placeholder node with a baked texture from the last @tool editor preview session.
Fix: In _ready(), ShipBody.visible = false is called immediately (when Engine.is_editor_hint() is false). The placeholder is editor-only; it must be invisible at runtime. The actual ship body is instantiated separately and added to self.
func _ready() -> void:
if Engine.is_editor_hint():
return
# Hide the editor placeholder โ it serves no runtime purpose
var sb: Node2D = $ShipBody
if sb:
sb.visible = false
_gm = get_node("/root/GameManager")
...
_apply_ship_setup()
ShipBody is an editor-only node. It is always hidden at runtime. The real ship body (_ship_body) is a dynamically instantiated scene added directly to the CharacterBody2D root, so it inherits no editor-saved scale from ShipBody. Editor Improvement: Active Collision Polygon Highlighted
When editing collision polygons in Player.tscn, it was unclear which of the 18 Col_* nodes corresponded to the ship currently being previewed via the editor sliders. All 18 nodes were visible simultaneously, making it hard to select and trace the right one.
Option C: Active Polygon Made Visible
The _editor_update_preview() function now iterates all Col_* nodes and hides them all, then makes only the active one visible. The visible property on CollisionPolygon2D has no effect on physics; it only controls whether the gizmo outline is drawn in the editor viewport. This means the correct polygon is always highlighted in orange when the preview sliders are set.
func _editor_update_preview() -> void:
# ... load sprite texture + apply scale ...
# Show only the active collision polygon in the editor
for child in get_children():
if child is CollisionPolygon2D:
child.visible = false
var active_col_name: String = COLLISION_NODE_NAMES[series][level]
var col: CollisionPolygon2D = get_node_or_null(active_col_name)
if col:
col.visible = true
editor_active_collision = active_col_name
else:
editor_active_collision = "(none)"
An @export var editor_active_collision: String = "(none)" is also shown in the Inspector so you can confirm at a glance which node is active before editing it.
BGS-1 and BGS-2: Unique Thruster System
Neither BGS ship has a centre thruster. Both use a dedicated 10-frame thruster animation loaded from Game Assests/Thrusters/BGS Thrusters/. The standard thruster loading path in _apply_ship_setup() was extended to detect BGS ships and load these frames instead of the standard set.
const BGS_THRUSTER_PATHS: Array[String] = [
"res://Game Assests/Thrusters/BGS Thrusters/thruster_1.png",
"res://Game Assests/Thrusters/BGS Thrusters/thruster_2.png",
# ... 10 frames total
]
When a BGS ship is detected: _use_center = false, _use_sides = true. BGS thruster frames are loaded into _thruster_frames. The ThrusterLeft and ThrusterRight nodes both have visible = false set in their .tscn files and are controlled at runtime by the existing thruster animation loop.
BGS-1 and BGS-2: Gun Barrel Layout and Side-Firing Mechanic
15 Gun Barrel Marker2D Nodes
The BGS ships have a unique gun layout: 3 front barrels and 6 per side (12 side barrels total). All 15 are placed as Marker2D nodes in the ship .tscn files so positions can be tuned visually in the editor without touching code.
- GunBarrelFront1/2/3: Front-facing, fire forward (same direction as ship heading)
- GunBarrelSideLeft1โ6: Left hull edge, fire perpendicular (left of heading)
- GunBarrelSideRight1โ6: Right hull edge, fire perpendicular (right of heading)
Level-Gated Side Firing
The upgrade mechanic for BGS ships is the side guns, not speed or size. Front guns always fire. Side guns unlock progressively by level:
| Level | Front Guns | Side Guns (per side) | Total Barrels |
|---|---|---|---|
| X1 (Level 0) | 3 | 0 | 3 |
| X2 (Level 1) | 3 | 3 each side | 9 |
| X3 (Level 2) | 3 | 6 each side | 15 |
func _handle_fire_bgs(level: int) -> void:
for barrel in _bgs_gun_front:
bullet_fired.emit(barrel.global_position, rotation)
if level < 1:
return
var side_count: int = 3 if level == 1 else 6
var rot_left: float = rotation - (PI * 0.5)
var rot_right: float = rotation + (PI * 0.5)
for i in side_count:
if i < _bgs_gun_side_left.size():
bullet_fired.emit(_bgs_gun_side_left[i].global_position, rot_left)
if i < _bgs_gun_side_right.size():
bullet_fired.emit(_bgs_gun_side_right[i].global_position, rot_right)
Side guns fire at exactly 90ยฐ to the ship heading (rotation ยฑ PI/2). The _is_bgs: bool flag is set in _apply_ship_setup() and routes _handle_fire() to the BGS-specific handler when true.
Player.gd BGS References
Three new BGS-specific arrays are populated in _apply_ship_setup() when a BGS ship is loaded:
var _bgs_gun_front: Array[Marker2D] = []
var _bgs_gun_side_left: Array[Marker2D] = []
var _bgs_gun_side_right: Array[Marker2D] = []
var _is_bgs: bool = false
These are cleared in _clear_ship_refs() each time a new ship loads, preventing stale references when switching ships.
Drop Rate Tuning: Fewer Coins, More Power-ups
Playtesting showed coin drops from asteroids were too frequent (screen clutter, economy unbalanced) and power-up drops were too rare (players rarely received buffs). Both adjusted in GameScene.gd.
| Item | Change | Old Value | New Value |
|---|---|---|---|
| Coin drop: LARGE asteroid | CHANGE | 100% chance | 70% chance |
| Coin drop: MEDIUM asteroid (2nd coin) | CHANGE | 40% chance | 20% chance |
| Coin drop: SMALL asteroid | CHANGE | 15% chance | 8% chance |
| Power-up: LARGE asteroid spawn chance | CHANGE | 25% | 35% |
| Power-up: MEDIUM asteroid spawn chance | CHANGE | 12% | 20% |
Files changed: scripts/game/GameScene.gd ยท _spawn_crystals() and _try_spawn_powerup().
Debug +1000 Coins Button in the Character Shop
A debug button was added to the Character Shop to allow rapid coin testing without playing through levels. Positioned on the right-hand side of the screen, mid-height, outside the main panel area. Yellow text to make it visually distinct as a debug element. Remove before shipping.
- Scene:
DEBUG_AddCoinsButton node added toUICanvasLayer inCharacterShop.tscn - Position: offset_left=1545, offset_top=510, offset_right=1905, offset_bottom=580
- Style: Yellow font (
Color(1, 0.9, 0, 1)), font_size=22, text="DEBUG +1000 Coins" - Wiring:
_gm.add_coins(1000), which uses the canonical GameManager method, triggerscoins_changedsignal and updates the live coin display
Viper Using Wrong Thruster Frames
The Viper (series 5) was loading the standard 7-frame THRUSTER_PATHS animation set, which includes a small diamond-style exhaust graphic that looks wrong on the Viper hull. The Viper should use a single centre exhaust using the BGS-style 10-frame animation, scaled down proportionally.
Root Cause
The Viper is a standalone ship (no X1/X2/X3 levels) and falls into the else branch of _apply_ship_setup(), the same branch as all standard multi-level ships. That branch unconditionally loaded THRUSTER_PATHS. There was no Viper-specific check.
Fix
Added a series == 5 check inside the standard else-branch that overrides the thruster layout and frame source for the Viper specifically:
# Viper (series 5) โ single centre exhaust, BGS-style thruster frames scaled down
if series == 5:
_use_center = true
_use_sides = false
# Load thruster frames โ Viper shares BGS animation frames (scaled down)
_thruster_textures.clear()
if series == 5:
for p in BGS_THRUSTER_PATHS:
_thruster_textures.append(load(p) as Texture2D)
else:
for p in THRUSTER_PATHS:
_thruster_textures.append(load(p) as Texture2D)
The Viper now plays the same 10-frame BGS exhaust animation on its centre thruster. The visual size is controlled by the scale value set on ThrusterCenter in Ship_Viper.tscn, starting at (3.6, 3.6), which can be tuned visually in the editor.
Thruster Visual Editing via Scene Restructure
Problem
Thrusters on all ships were sized and positioned entirely in code, via a block of ratio constants (TC_Y_R, TS_X_R, etc.) computed world-space values and forced them onto the nodes every time a ship loaded. Any values placed on thruster nodes in the .tscn editor were silently overwritten at runtime. Visual editing was impossible.
The deeper issue was structural: thruster Sprite2D nodes were direct children of the ship scene root. The ship root itself got scaled at runtime (e.g. BGS scale = 0.151), so the thrusters inherited that scale, and world-space size collapsed to near-zero on large-texture ships. The code override was a workaround for this inheritance.
The Body Sub-Node
All 18 ship .tscn files were restructured to introduce a Body Node2D child. The ship sprite and all gun barrel Marker2D nodes moved under Body. The thruster nodes stayed at the scene root.
| Before | After |
|---|---|
Ship_XXX (Node2D root) โ scaled at runtime โโ Sprite2D โ correct โ โโ GunBarrel โ correct โ โโ ThrusterCenter โ inherits scale โ โโ ThrusterLeft โ inherits scale โ โโ ThrusterRight โ inherits scale โ |
Ship_XXX (Node2D root) โ NOT scaled โโ Body (Node2D) โ only this scaled โ โโ Sprite2D โ correct โ โ โโ GunBarrel โ correct โ โโ ThrusterCenter โ world-space โ โโ ThrusterLeft โ world-space โ โโ ThrusterRight โ world-space โ |
At runtime, _apply_ship_setup() now scales Body only. Thrusters remain at their scene-defined positions and scales, which are now direct world-space values: what you set in the editor is exactly what appears in-game.
Player.gd Changes
- Sprite lookup changed from
"Sprite2D"โ"Body/Sprite2D" - Standard gun barrel lookups:
"GunBarrel"โ"Body/GunBarrel","Body/GunBarrelLeft","Body/GunBarrelRight" - BGS gun barrel lookups:
"GunBarrelFront%d"โ"Body/GunBarrelFront%d", etc. - Scale applied to
body_art(theBodysub-node) instead of_ship_body - Entire thruster position/scale override block removed, with no more ratio constants in code
# Before โ scales entire scene root (thrusters inherit it):
_ship_body.scale = Vector2(s, s)
# After โ scales only the art sub-node:
var body_art: Node2D = _ship_body.get_node_or_null("Body") as Node2D
if body_art and longest > 0.0:
body_art.scale = Vector2(disp / longest, disp / longest)
Starting Thruster Values
All thruster nodes were given pre-computed world-space starting positions so they appear in approximately the right place immediately. These are derived from the same proportional ratios that were previously computed in code, now baked into the .tscn as editable values.
| Ship Group | Display Size | ThrusterCenter | ThrusterLeft / Right |
|---|---|---|---|
| CX16, DKO, WO84, CP2, PTM (all variants) | 80 px | (0, 36) scale (2.2, 2.2) | (ยฑ24, 32) scale (1.8, 1.8) |
| Viper | 130 px | (0, 59) scale (3.6, 3.6) | (ยฑ39, 52), unused, no sides |
| BGS-1, BGS-2 | 160 px | n/a (no centre) | (ยฑ48, 64) scale (3.5, 3.5) |
BGS Thruster Visibility Bug Fixed
Both BGS ship .tscn files had visible = false set on ThrusterLeft and ThrusterRight. Since _update_thrust_effects() controls thruster visibility at runtime based on is_thrusting and _use_sides, the static visible = false in the scene permanently suppressed the BGS thrusters even when thrusting. These flags have been removed; the code handles all visibility toggling.
How to Tune Thruster Positions Going Forward
- Open a ship scene (e.g.
scenes/entities/ships/Ship_CX16_X1.tscn) - Select
ThrusterCenter,ThrusterLeft, orThrusterRightin the scene tree - Drag to reposition or use the Inspector to set scale; both update the
.tscn - Save the scene. No code changes needed, changes are live immediately
Files Changed on 15 May 2026
| File | Change |
|---|---|
| scripts/entities/Player.gd | FIX _ship_body added to self (not ShipBody), eliminating double-scaling. FIX ShipBody.visible=false in _ready(). CHANGE BGS_THRUSTER_PATHS const; _bgs_gun_* arrays; _is_bgs flag; _apply_ship_setup() BGS branch; _handle_fire() routes to _handle_fire_bgs(); _clear_ship_refs() clears BGS arrays. CHANGE _editor_update_preview() hides all Col_* then shows active one. NEW SHIP_DISPLAY_SIZES 2D array; editor_active_collision export. |
| scenes/entities/Player.tscn | FIX Removed any editor-saved scale from ShipBody node; scale is now set exclusively in code. |
| scenes/entities/ships/Ship_BGS1.tscn | CHANGE Removed ThrusterCenter; added 15 gun barrel Marker2D nodes (GunBarrelFront1โ3, GunBarrelSideLeft1โ6, GunBarrelSideRight1โ6); all thrusters visible=false. |
| scenes/entities/ships/Ship_BGS2.tscn | CHANGE Same structure as BGS1; gun barrel positions tuned independently for BGS-2 hull shape. |
| scripts/game/GameScene.gd | CHANGE _spawn_crystals(): LARGE 100%โ70%, MEDIUM 2nd coin 40%โ20%, SMALL 15%โ8%. _try_spawn_powerup(): LARGE 25%โ35%, MEDIUM 12%โ20%. |
| scenes/menus/CharacterShop.tscn | NEW DEBUG_AddCoins Button node under UI CanvasLayer; yellow text; positioned right-side mid-height. |
| scripts/menus/CharacterShop.gd | NEW @onready var _debug_add_coins; connected in _ready() to add_coins(1000). |
| scripts/entities/Player.gd | FIX Viper (series 5) now loads BGS_THRUSTER_PATHS with _use_center=true, _use_sides=false. CHANGE Sprite lookup โ "Body/Sprite2D". Scale now applied to Body sub-node only. Gun barrel paths prefixed "Body/". FIX Entire thruster position/scale override block removed, with no more ratio constants in code. |
| scenes/entities/ships/Ship_CX16_X1.tscn Ship_CX16_X2.tscn Ship_CX16_X3.tscn Ship_DKO_X1โX3.tscn Ship_WO84_X1โX3.tscn Ship_CP2_X1โX3.tscn Ship_PTM_X1โX3.tscn Ship_Viper.tscn Ship_BGS1.tscn Ship_BGS2.tscn |
CHANGE All 18 scenes restructured: Body Node2D sub-node added; Sprite2D and GunBarrel* nodes moved under Body (parent="Body"); ThrusterCenter/Left/Right stay at scene root with pre-computed world-space positions and scales. FIX BGS1 and BGS2: removed visible=false from thruster nodes. |
Open Items
| Item | Priority | Notes |
|---|---|---|
| Remove DEBUG_AddCoins button before shipping | Pre-ship | In CharacterShop.tscn and CharacterShop.gd |
| Add all 12 sound effects | High | SOUND NEEDED comments mark every trigger point in the codebase |
| Tune player ship collision polygons (ร18) | High | Use Editor Preview sliders in Player.tscn; the active polygon is now highlighted |
| Tune thruster positions per ship variant | High | Open each ship .tscn, select ThrusterCenter/Left/Right and drag. Fully visual now, no code changes needed. Starting positions pre-set. |
| Tune gun barrel positions per ship variant | High | Open each ship .tscn, drag GunBarrel Marker2D nodes under Body. BGS ships have 15 barrels each, tuned by level. |
| Tune asteroid collision polygons (ร12) | Medium | A1 traced. A3โA13 use default octagon. |
| Enemy movement โ _physics_process | Medium | EnemyUnit + EnemyMothership position logic is in _process |
| Throttle asteroid dodge loop | Medium | EnemyUnit._get_asteroid_dodge() scans all asteroids every frame |
| Wire real achievement data | Medium | 12 slots are placeholder (unlocked = false) |
| Standalone ship level-up (BGS rocket mechanic) | Medium | BGS side guns now level-gated. Viper and additional standalone ships still need a level-up benefit. |
| Level Complete visual polish | Medium | SHIP_DISPLAY_CONFIG offsets/scales need tuning per ship |
| Mobile joystick wiring | Medium | MobileControls visible=false; input not connected |
| Audio buses | Medium | Create Master โ Music and SFX buses once sounds are added |
| Wave warning text | Low | Still says "Asteroids Incoming" on enemy-only waves |
| Planet positions BG_02โBG_13 | Low | Editor adjustment needed per background scene |
| Coin shop / IAP | Low | Not started |
| AdMob, Vungle, AppLovin | Low | SDK integration pending |
| GDPR consent | Low | Required before store submission |
| Google Play Games leaderboards | Low | Not started |
| Android / iOS export signing | Low | Export templates not configured |