Releases: ikostan/SkyLockAssault
Milestone 16: Implement Parallax Scrolling Background linked to Player Speed, Part #2
This PR implements a comprehensive architectural overhaul of the player movement and parallax systems to improve maintainability, stability, and type safety. Key changes focus on decoupling systems through the Observer pattern and resolving long-term float-precision risks.
Summary of Changes
Architectural Improvements
- Observer Pattern & Decoupling: Transitioned the
ParallaxManagerand UI systems away from polling global singletons. They now react dynamically to signals (e.g.,speed_changed,fuel_depleted) emitted by the player. - Dependency Injection: Refined
main_scene.gdto inject theGameSettingsResourceinto subordinates at initialization, reducing coupling to theGlobalsautoload and improving testability. - Encapsulation: Moved complex internal logic, such as parallax wrap period calculations, into the
ParallaxManager, hiding implementation details from theMainScene.
Technical Safeguards
- Float Precision Safeguard: Implemented a
wrapfmechanism in the parallax loop to prevent "stuttering" during long-duration play sessions by resetting the scroll offset at a calculated period. - LCM Sync Math: Developed a Least Common Multiple (LCM) algorithm to synchronize disparate parallax layer periods, ensuring that layers with different
motion_scalevalues wrap seamlessly without visual jumping. - Type Safety: Refactored the player's speed data structure from a loosely typed dictionary (
speed["speed"]) to a strictly typed float (current_speed), eliminating silent runtime errors.
UI & Input
- Unbound Controls Warning: Implemented a dynamic notification system that alerts players if critical actions are not bound to their current device (Keyboard vs. Gamepad).
- Web Compatibility: Added JavaScript callbacks and user-gesture detection for background music to ensure a smooth experience on web/itch.io exports.
Testing & Quality Assurance
- Test Suite Synchronization: Updated the entire GUT and GdUnit4 test suites to match the new typed properties and decoupled signal architecture.
- Static Analysis Compliance: Resolved multiple "code smells" and "anti-patterns" identified by @deepsource-bot, @coderabbitai, and @sourcery-ai.
Summary by @sourcery & @coderabbitai
Introduce a dedicated ParallaxManager to drive background scrolling from the player’s speed signal, decoupling parallax logic from the main scene and player while preserving fuel-based behavior and precision safeguards.
New Features:
- Add a ParallaxManager node that controls parallax background scroll speed based on the player’s current forward velocity and game difficulty.
- Automatically calculate an optimal wrap period for parallax layers to avoid float precision issues during long sessions.
- Added a dedicated parallax manager that accepts injected settings, can be primed with an initial speed, and can auto-calculate optional vertical wrap to avoid float drift.
Enhancements:
- Refactor player speed handling to use a strongly-typed current_speed property instead of a dictionary, simplifying signal emissions and fuel consumption logic.
- Wire the main scene to inject game settings into the parallax manager and connect player speed signals using a safer, dependency-injected architecture.
Tests:
- Add comprehensive GUT tests for ParallaxManager covering signal integration, scroll math, flameout behavior, recovery, null global safety, and default-initialization behavior.
- Update existing player, fuel, difficulty, and UI tests to use the new current_speed property and validate the updated fuel depletion calculations.
- New tests cover manager behavior, scroll math, flameout/recovery, and safety when settings are missing; player tests updated to use the new speed property.
Refactor:
- Parallax behavior moved out of the main scene into the manager; player speed state simplified to a scalar property.
Bug Fixes:
- Background scrolling reliably stops and snaps to zero on fuel depletion.
Contributors
- @ikostan: Lead architectural design, core implementation, and test suite refactoring.
- @coderabbitai: Detailed code review and architectural feedback.
- @deepsource-bot: Automated static analysis and code quality monitoring.
- @sourcery-ai: Automated logic refactoring and code simplification suggestions.
@ikostan Contributions Summary
- Architectural Refactoring: Spearheaded the transition from a tightly coupled, singleton-dependent system to a decoupled, signal-based Observer Pattern.
- Precision Engineering: Implemented a sophisticated Least Common Multiple (LCM) calculation for the Parallax Manager to synchronize non-commensurate layer periods and prevent visual "jumps".
- Type-Safety Migration: Eliminated stringly-typed dictionary access for player speed, replacing it with a strongly-typed float property (
current_speed) to ensure compile-time safety across the game engine. - Stability & Safeguards: Developed a Float Degradation Safeguard using the
wrapfmethod, protecting the game's visual integrity during extended play sessions. - UI/UX Logic: Integrated a dynamic Unbound Controls warning system that detects and alerts players to missing critical keybindings based on their active device (Keyboard vs. Gamepad).
- Test Suite Maintenance: Successfully updated and maintained both GUT and GdUnit4 test suites, ensuring that all architectural refactors remained verified by automated unit and integration tests.
- Dependency Injection: Refined the
main_scene.gdinitialization logic to use safe Dependency Injection, protecting the scene from crashes during isolated testing or scene transitions.
This Pull Request (PR) #574 has benefited from significant contributions and automated reviews from several AI-driven tools and bots. Below is a summary of their contributions and their correctly formatted GitHub handles for inclusion in the contributors list.
Bots & AI Contribution Summary
- @coderabbitai: Acted as the primary AI reviewer for this PR. It provided deep architectural feedback, identified magic numbers, suggested the transition to the Observer pattern for the parallax system, and caught critical edge cases like float-precision degradation and signal redundancy. It also verified the fix for "unbound controls" and assisted in refactoring the speed data structure from a dictionary to a strongly-typed float.
- @deepsource-bot: Performed automated static analysis and code quality reviews. It flagged potential "anti-patterns" and ensured the GDScript followed consistent style guidelines and best practices.
- @sourcery-ai: Contributed automated refactoring suggestions to improve code readability and efficiency. It focused on simplifying complex logic and ensuring the new decoupled architecture remained clean and maintainable.
Contributor List (GitHub Format)
To ensure these are properly recognized in your GitHub contributors list or README.md:
- @coderabbitai
- @deepsource-bot
- @sourcery-ai
Milestone 16: Fix main scene orphan leaks and tune parallax decor with tests, Part #1
PR Summary: Parallax Performance Optimization and Test Suite Refactor
This Pull Request addresses critical FPS drops related to background generation and standardizes the project's unit testing architecture to ensure long-term stability and memory integrity.
1. Performance Optimizations
- Parallax "Goldilocks Zone" Implementation: Optimized the background layer heights from 20 screens down to 8 screens. This significantly reduces the Bounding Volume Hierarchy (BVH) overhead and restores a high FPS buffer during gameplay.
- Sprite Density Reduction: Adjusted the background sprite multiplier from 5x to 2x. This maintains visual density while drastically cutting draw calls and CPU processing time during layer initialization.
- Centralized Tuning: Introduced an
@exportvariableparallax_screens_tallinmain_scene.gd. This allows for real-time performance tuning of all background layers via the Godot Inspector without modifying code.
2. Memory & Stability Fixes
- Orphan Node Elimination: Refactored the cleanup loops in
setup_bushes_layer()andsetup_decor_layer()to use an immediatefree()strategy. By detaching children withremove_child()and instantly incinerating them, we have eliminated the "orphan window" bug where nodes persisted until the end of a frame. - Safe Lifecycle Management: Implemented a standardized
safe_hard_freehelper to prevent "previously freed" object errors and engine crashes during rapid scene transitions and unit test teardowns.
3. Test Suite Enhancements
- Consolidated Testing Architecture: Merged redundant test files into
test_main_scene_parallax_and_performance.gdto reduce maintenance overhead. - Centralized Test Utilities: Integrated shared cleanup logic and mock builders into
gut_test_helper.gd. All test suites now utilize this shared helper for consistent teardown behavior. - Robust Performance Assertions:
- Updated execution time tests with a looser threshold (2ms-5ms) to prevent false positives in CI environments while still catching script regressions.
- Improved randomization tests to verify that
flip_handflip_vare actively producing varied results rather than just checking data types.
- Strict Type Compliance: Added explicit
-> boolreturn types to all anonymous lambda functions within the test suite to satisfy strict GDScript type-checking requirements.
Summary by @sourcery-ai & @coderabbitai
Resolve orphan node leaks in the main scene while enforcing performance and visual constraints on its parallax background layers and tightening player lifecycle cleanup.
New Features:
- Introduce randomized rotation, scaling, and horizontal/vertical flipping for decor sprites in the main scene to increase visual variety.
- Denser, taller parallax vegetation and decor with increased variety (larger vertical span, doubled instances, wider scale range, random flips and cardinal rotations).
Bug Fixes:
- Fix orphan node leaks by properly clearing parallax layer children and synchronizing queue_free cleanup with frame processing in tests.
- Prevent orphan node leaks by hard-freeing detached parallax children and synchronizing scene teardown with frame processing in tests.
- Ensure player lifecycle tests disconnect signals without breaking the SceneTree and cleanly free the main scene between runs.
- More immediate cleanup of old layer nodes and removal of debug printouts for cleaner runtime and reduced orphan-node buildup.
Enhancements:
- Tune parallax bushes and decor layers to use an 8-screen chunk height with a 2x sprite density multiplier for better infinite scrolling and visual variety.
- Improve decor layer visuals with wider scale variance and strict cardinal rotations while maintaining performance.
- Standardize parallax bushes and decor layers to an 8-screen chunk height with a 2x sprite density multiplier to balance infinite scrolling visuals with performance.
- Refine decor layer appearance with a wider uniform scale range and constrained cardinal rotations for consistent, varied scenery.
Tests:
- Add comprehensive GUT test suites to validate main scene orphan-node behavior, parallax chunk sizing and density, decor layer transformations, and main scene _process performance.
- Tighten existing player lifecycle tests to assert signal disconnection and orphan-free teardown with explicit frame flushing.
- Add GUT test suites to validate main scene orphan-node behavior, parallax chunk sizing and density, decor layer transformations, and _process execution time.
- Strengthen existing player lifecycle tests with explicit frame flushing and stricter assertions around signal disconnection and orphan-free teardown.
- Added comprehensive GUT suites validating layer density, transforms, lifecycle stability, orphan-node absence, and performance limits.
Reviewer's Guide
Fixes orphan node leaks and enforces performance/visual constraints for the main scene’s parallax background while tightening player lifecycle cleanup and adding targeted GUT coverage.
File-Level Changes
| Change | Details | Files |
|---|---|---|
| Adjust parallax bushes and decor setup to destroy old children immediately and tune chunk height/density and visual variety. |
|
scripts/main_scene.gd |
| Tighten player lifecycle tests to free scenes deterministically and ensure signal disconnection and frame flushing behave correctly. |
|
test/gut/test_player_lifecycle.gd |
| Add GUT tests to enforce main scene parallax configuration, decor transformations, orphan-node behavior, and _process performance bounds. |
|
test/gut/test_main_scene_parallax_and_performance.gdtest/gut/test_decor_layer_transformations.gdtest/gut/test_main_scene_orphan_nodes.gdtest/gut/test_decor_layer_transformations.gd.uidtest/gut/test_main_scene_orphan_nodes.gd.uidtest/gut/test_main_scene_parallax_and_performance.gd.uid |
Assessment against linked issues
| Issue | Objective | Addressed | Explanation |
|---|---|---|---|
| #540 | Update setup_bushes_layer() and setup_decor_layer() in main_scene.gd to clear existing children using an immediate free() (instead of remove_child() + queue_free()) so placeholder Sprite2D nodes do not become orphans. |
✅ | |
| #540 | Modify test_player_lifecycle.gd so that test teardown uses a hard main_scene.free() instead of queue_free(), and adjust lifecycle tests to manually call player_root._exit_tree() (rather than remove_child()) while ensuring cleanup does not leave orphan nodes. |
✅ | |
| #549 | Ensure setup_bushes_layer() and setup_decor_layer() clean up their previous children without leaving persistent orphan nodes. | ✅ | |
| #549 | Add automated GUT tests that implement the orphan-node QA test plan scenarios (teardown memory sync, repeated setup, immediate rebuild integrity, scene reload lifecycle, stress input, and layer isolation) with appropriate frame syncing. | ✅ | |
| #549 | Align test and teardown behavior with Godot’s deletion semantics (queue_free vs free), ensuring orphan checks occur after ... |
Milestone 15: Decouple Fuel System using GameSettingsResource and Signals, Part #3
Introduce a new speed_changed(float) signal in player.gd and hook it up to update UI and warnings. Connect/disconnect the handler in _ready/_exit_tree to avoid dangling connections, and emit the signal when speed actually changes (in _physics_process and on flameout). Also add guards for _settings validity and ensure flameout resets speed and notifies listeners. Add comprehensive GUT tests (test_player_fuel_logic.gd, test_player_movement_signals.gd and their uid files) that validate fuel behavior, rotor/timer reactions, lateral movement constraints, signal emission semantics, UI reactivity, and speed clamping.
Summary by @sourcery-ai & @coderabbitai
Decouple player speed and fuel UI from the player controller by introducing observer-based signals and a dedicated HUD script, and extend tests and settings to validate the new behavior.
New Features:
- Add speed_changed, speed_low, and speed_maxed signals on the player to notify observers of speed state changes.
- Introduce a dedicated HUD controller script to manage fuel and speed UI, including bar colors and warning animations, driven by settings and player signals.
- New HUD for fuel and speed with configurable speed system (min/max, lateral speed, accel/decel, warning thresholds) and player speed signals.
Bug Fixes:
- Ensure engine flameout and refueling correctly reset and restart speed, rotors, and fuel timers without dangling signal connections.
- Guard global logging and signal connections against missing or reused GameSettings resources to avoid null references and invalid parameter errors.
- Engine stops on fuel depletion and restarts on refuel; lateral movement blocked without fuel. Speed clamps to configured bounds and only emits updates when changed.
Enhancements:
- Move speed and fuel tuning parameters into GameSettingsResource, with invariants and change notifications for dynamic configuration.
- Refine player movement to rely on global speed settings, centralize speed clamping, and restrict lateral motion when out of fuel.
- Wire the main scene to initialize the HUD with the player instance for proper signal-driven updates.
- Simplify and harden rotor startup/teardown and settings initialization in the player controller.
Tests:
- Add comprehensive GUT tests for HUD behavior, player movement signals, and fuel logic, including UI color thresholds, blinking behavior, speed clamping, and signal emission semantics.
- Update existing GdUnit tests and helpers to consume shared settings-based speed/fuel parameters and the new HUD-driven UI, and add a reusable mock scene builder for player/HUD tests.
- Added comprehensive unit/integration tests for fuel, engine, HUD, and movement/signal behaviors.
Refactor:
- Decoupled gameplay speed logic from HUD; HUD is wired at runtime with safety checks.
CI:
- Bump the Release Drafter GitHub Action SHA in release and PR workflows to a newer version.
Updated-dependencies:
dependency-name: release-drafter/release-drafter dependency-version: 7.2.0 dependency-type: direct:production update-type: version-update:semver-minor ...
Reviewer's Guide
Decouples player speed/fuel UI from the player controller by introducing player speed signals and a dedicated HUD script, centralizes speed configuration in GameSettingsResource, and adds comprehensive GUT/GdUnit tests for speed, fuel, HUD, and movement behavior.
Updates the GitHub Actions workflows to use a newer pinned commit of the release-drafter action for both the main release and pull-request drafting workflows.
File-Level Changes
| Change | Details | Files |
|---|---|---|
| Decouple player controller from UI and introduce speed signals for observer-based HUD updates. |
|
scripts/player.gd |
| Add a dedicated HUD controller script that observes player and GameSettingsResource state to drive fuel/speed UI and warnings. |
|
scripts/hud.gdscripts/main_scene.gdscenes/main_scene.tscn |
| Move and formalize speed configuration into GameSettingsResource with invariants and notifications. |
|
scripts/game_settings_resource.gd |
| Harden global logging and scene wiring to be robust to missing settings/HUD scripts. |
|
scripts/globals.gdscripts/main_scene.gd |
| Update existing GdUnit tests to respect the new HUD and settings-based speed/fuel configuration. |
|
test/gdunit4/test_player.gdtest/gdunit4/test_helpers.gdtest/gdunit4/test_difficulty.gdtest/gdunit4/test_difficulty_integration.gd |
| Add shared GUT mock builder and new GUT tests covering HUD behavior, player fuel logic, and speed signal semantics. |
|
test/gut/gut_test_helper.gdtest/gut/test_hud.gdtest/gut/test_player_movement_signals.gdtest/gut/test_player_fuel_logic.gdtest/gut/gut_test_helper.gd.uidtest/gut/test_hud.gd.uidtest/gut/test_player_fuel_logic.gd.uidtest/gut/test_player_movement_signals.gd.uidscripts/hud.gd.uid |
| Bump the pinned commit SHA of the release-drafter GitHub Action in the release workflow. |
|
.github/workflows/release_drafter.yml |
| Bump the pinned commit SHA of the release-drafter GitHub Action in the PR workflow. |
|
.github/workflows/release_drafter_pr.yml |
Assessment against linked issues
| Issue | Objective | Addressed | Explanation |
|---|---|---|---|
| #279 | Introduce speed-related signals in Player.gd (speed_changed(new_speed: float, max_speed: float), speed_low(threshold: float), speed_maxed()) and update the speed logic to emit them appropriately, including on flameout. | ✅ | |
| #279 | Decouple speed UI logic from Player.gd by moving it into a dedicated HUD script (HUD.gd) and connecting the Player’s speed signals to this HUD for UI updates. | ✅ | |
| #279 | Add automated tests to verify speed signal emission behavior and the HUD/UI reactions to speed changes. | ✅ |
Possibly linked issues
- #279: PR implements the requested speed_changed/low/maxed signals in Player.gd, wires them to HUD, and adds tests, fully addressing the issue.
Contributions
Milestone 15: Decouple Fuel System using GameSettingsResource and Signals, Part #2
📦 PR Summary
Introduce a centralized fuel subsystem via GameSettingsResource: adds max_fuel, current_fuel, base_consumption_rate, a refuel() helper, and signals (setting_changed, fuel_depleted). Persist/load fuel settings in globals.gd and validate types when loading. Update player.gd to read/write fuel from Globals.settings, connect to setting_changed and fuel_depleted, and move consumption calculations to use the new resource values; UI updates are driven by the resource signals. Add GUT tests covering the resource behavior, UI reactivity, and integration/persistence edge cases (including signal emission and invalid config handling). Clamping and one-time depletion signaling are enforced.
Overview
This PR migrates the fuel system from a hard-coded local state into a robust, globally accessible Godot Resource (GameSettingsResource). In doing so, it establishes a new standard for data management, UI reactivity, and defensive programming across the project.
Key Features & Architectural Changes:
- The Observer Pattern: Decoupled the UI and Player logic from the
_processloop. UI elements and player states now update instantly and automatically by listening to thesetting_changedandfuel_depletedsignals emitted by the global resource. - Defensive "Fail-Safe" Architecture: Implemented strict
is_instance_valid()null guards across hot paths (_physics_processinplayer.gd,_processinmain_scene.gd) to prevent engine crashes during scene transitions or isolated tests. - Zombie Node & Split-Brain Prevention: The Player node now safely generates and injects a fallback
GameSettingsResourceinto theGlobalssingleton if the primary settings fail to load, ensuring all systems stay synchronized. - Refined Persistence Logic: Separated volatile session data from permanent upgrades.
max_fuelanddifficultyare saved to the player's disk, whilecurrent_fuelcorrectly resets on load to prevent inescapable 0-fuel death loops. - Monotonic Threshold Validation: The color-changing UI thresholds (High, Medium, Low, Empty) now automatically clamp against each other in the resource setters, mathematically preventing broken UI states.
- Engine Reignite Logic: Fixed a state-machine bug where refueling a dead airplane wouldn't restart the engine. The player script now actively detects refuels from 0 and reignites the rotors and consumption timers.
- Comprehensive GUT Testing: Built out a robust suite of unit and integration tests (
test_fuel_edge_cases.gd,test_fuel_persistence_integration.gd, etc.) to definitively prove signal constraints, persistence fallbacks, and UI reactivity.
Summary by @sourcery-ai & @coderabbitai
New Features:
- Introduce a configurable fuel subsystem in GameSettingsResource, including max/current fuel, consumption rate, thresholds, a refuel helper, and fuel_depleted signaling. @ikostan
- Drive the player’s fuel behavior and UI from the shared fuel resource, including engine flameout handling when fuel is depleted. @ikostan
- Introduce a fuel subsystem in GameSettingsResource, including capacity, current fuel, consumption rate, color thresholds, refuel helper, and fuel_depleted signal. @ikostan
- Drive player fuel behavior and UI entirely from the shared settings resource, including engine shutdown on depletion and reactive HUD updates via signals. @ikostan
Bug Fixes:
- Prevent log spam and excessive disk writes by excluding current_fuel changes from automatic logging and autosave. @ikostan
- Ensure fuel bar limits and color calculations remain correct when max_fuel changes or is misconfigured in saved settings. @ikostan
- Avoid crashes and leaks by validating Globals/settings presence, guarding against invalid instances, and disconnecting player signal handlers on exit. @ikostan
- Prevent log spam and unnecessary disk writes by excluding high-frequency current_fuel updates from automatic logging and saving. @ikostan
- Ensure new resources and player instances always start with a full fuel tank to avoid bad save-state loops and uninitialized fuel values. @ikostan
- Clamp fuel capacity and level to valid ranges to avoid negative fuel, zero-capacity tanks, and repeated depletion events. @ikostan
Enhancements:
- Persist and load fuel-related settings with type validation and safe fallbacks for missing or invalid config values.
- Refactor fuel thresholds, consumption, and depletion calculations from the player script into the centralized settings resource.
- Update background scroll and other systems to reference global fuel state instead of local player fuel fields.
- Refactor fuel-related logic out of player.gd into the settings resource, making fuel thresholds, capacity, and consumption configurable from a single location.
- Add defensive handling for missing Globals.settings and clean signal disconnection in the player lifecycle to avoid crashes and dangling listeners.
- Align main_scene background behavior and movement controls with the centralized fuel state instead of local player dictionaries.
Tests:
- Add extensive GUT and GdUnit tests for the fuel resource, persistence edge cases, UI reactivity to signals, difficulty-based fuel scaling, and player lifecycle signal cleanup.
- Augment existing difficulty and player tests to use the new fuel resource API and dynamic max_fuel rather than hardcoded values.
- Extend existing GdUnit tests to use the centralized fuel settings and dynamic max_fuel instead of hardcoded values.
- Add GUT test suites for fuel resource behavior, signal emission, UI reactivity, persistence (including invalid/missing config handling), and player lifecycle cleanup.
Reviewer's Guide
Centralizes the fuel system in GameSettingsResource, rewires player/main_scene and globals persistence to use it as the single source of truth, and adds GUT/GdUnit tests for fuel behavior, UI reactivity, lifecycle cleanup, and persistence edge cases.
File-Level Changes
| Change | Details | Files |
|---|---|---|
| Centralize fuel configuration and state in GameSettingsResource, including thresholds, consumption, refuel helper, and signals. |
|
scripts/game_settings_resource.gd |
| Refactor player to consume and display fuel from the shared GameSettingsResource and respond to its signals. |
|
scripts/player.gd |
| Wire main_scene and globals to the centralized fuel settings and improve persistence/load behavior. |
|
scripts/main_scene.gdscripts/globals.gd |
| Adapt existing GdUnit tests to the centralized fuel system and dynamic max_fuel. |
|
test/gdunit4/test_difficulty.gdtest/gdunit4/test_difficulty_integration.gdtest/gdunit4/test_player.gdtest/gdunit4/test_helpers.gd |
| Add GUT test suites covering fuel resource behavior, UI reactivity, lifecycle cleanup, scaling, and persistence edge cases. |
|
Milestone 15: Update README docs, Part #1
Summary by @sourcery-ai & @coderabbitai
Update README to document recent audio system and JavaScript bridge improvements and related test coverage.
Documentation:
- Describe UI navigation sounds and dedicated Menu SFX bus in the feature overview and accessibility sections.
- Document hardening of the JavaScript gameplay settings bridge and the AudioWebBridge for robust web communication.
- Note new GUT test coverage for the JavaScript bridge and web integration reliability.
- Add release notes-style entries referencing PRs that documented the observer-based settings system, hardened the JS bridge, and integrated UI navigation sounds.
- Added documentation for dedicated UI navigation audio system
- Updated roadmap with completed features including observer-based settings system and improved web integration reliability
- Enhanced documentation for JavaScript-browser communication hardening
Reviewer's Guide
Updates README.md to document new UI navigation audio features, hardened JavaScript/web bridges, and corresponding testing and roadmap notes for the project.
File-Level Changes
| Change | Details | Files |
|---|---|---|
| Document new UI navigation audio system and dedicated Menu SFX bus. |
|
README.md |
| Document hardened JavaScript bridges between Godot and the web environment and their test coverage. |
|
README.md |
| Update project history/roadmap to reference specific prior PRs related to settings system and CI stability. | README.md |
Assessment against linked issues
| Issue | Objective | Addressed | Explanation |
|---|---|---|---|
| #454 | Update README.md to document the features, refactors, and improvements delivered in Milestone 14, especially in the milestone/changelog or progress sections. | ✅ | |
| #454 | Enhance README.md to clearly highlight new systems relevant for onboarding (e.g., audio system changes, JavaScript/web bridge hardening, and related testing), reflecting current project capabilities. | ✅ |
Possibly linked issues
- #14: PR updates README with newly delivered features and improvements, directly fulfilling the documentation refresh requested in the issue. @ikostan
- #13: The PR updates README to document newly delivered features and tests, directly fulfilling the milestone documentation update goal. @ikostan
🤖 Bot & AI Contributions
This pull request features significant contributions from automated systems and AI agents, focusing on code quality, security, and documentation accuracy during the project's ongoing development.
Summary of Activity
- Automated Code Review: AI agents performed a line-by-line analysis of the changes, identifying potential logic errors and suggesting optimizations for the Godot GDScript files. This included verifying signal connections and ensuring consistency with the
GameSettingsResourcearchitecture. - Static Analysis & Linting: Automated tools scanned the codebase for anti-patterns and performance bottlenecks, helping to maintain a high standard of code health and readability.
- Security Scanning: Integrated bots performed dependency and vulnerability checks to ensure the PR remains compliant with safety standards.
- Documentation & Changelog Automation: Bots assisted in synchronizing the PR description with project issues and updating the automated changelogs to reflect the new updates.
AI & Bot Contributors
The following automated entities are recognized for their contributions to this PR:
- @coderabbitai – Provided contextual code reviews, logic verification, and actionable feedback on script changes.
- @deepsource-io – Conducted static analysis and identified potential bug risks to ensure long-term maintainability.
- @sourcery-ai – Assisted in refactoring suggestions and generating concise summaries for the review process.
- @github-project-automation – Managed the workflow transitions and synchronized project board statuses.
Milestone 14: Add Menu SFX bus, AudioWebBridge, and UI navigation sounds, Part #3
Summary by @sourcery-ai & @coderabbitai
Add a dedicated Add a dedicated menu SFX bus and global UI navigation sound, while decoupling web audio bridging into a new autoload and updating audio settings UI and tests accordingly. SFX audio bus and UI controls, and hook up global UI navigation sounds to that bus.
Stop forcing preload of key_mapping_scene and options_scene in GameSettingsResource; export them as PackedScene properties instead so they can be assigned via resources/editor and avoid circular dependencies. Update default_settings.tres to include ExtResource entries for the two scenes. No behavioral changes besides how scenes are referenced/loaded.
Update GitHub workflows to use newer pinned SHAs for third-party actions.
New Features:
- Introduce a separate Menu SFX volume and mute channel alongside existing audio buses. @ikostan
- Play a global UI navigation sound on focus and directional UI input, routed through the Menu SFX bus. @espanakosta-jpg
- Introduce a separate SFX_Menu audio bus with corresponding volume and mute controls in the audio settings UI and HTML shell. @ikostan
- Add a global UI navigation sound that plays on menu navigation inputs via a persistent audio player on the new menu SFX bus. @ikostan
- Provide an AudioWebBridge autoload to handle all web/JavaScript audio integration and DOM syncing independently of the audio settings scene. @ikostan
Enhancements:
- Extend in‑game and web audio settings UIs to control Menu SFX volume/mute, including DOM bridge callbacks and syncing logic.
- Refactor audio_settings.gd to centralize bus UI wiring, enforce hierarchical mute/lock behavior, and sync with AudioManager via new volume/mute signals.
- Improve back navigation handling from the audio settings menu, including DOM visibility restoration and focus management across menus.
- Extend AudioManager and AudioConstants to support the new menu bus and emit signals for volume and mute changes so UI and web layers stay in sync.
- Expose key mapping and options menu scenes as assignable PackedScene exports in the game settings resource instead of hard-coded preloads.
New Features:
- Menu SFX controls: added a menu effects volume slider and mute toggle in Audio Settings.
- Browser overlay: audio controls can show/hide in-browser and sync bidirectionally with the app.
- Menu navigation SFX: dedicated UI navigation sound and player for menu interactions.
Refactor:
- Optimized scene resource loading and initialization patterns to improve application startup performance.
Tests:
- Update existing GdUnit and Playwright tests to cover the new menu SFX bus, UI reset behavior, back-navigation logging, and revised logging messages.
- Add a new GUT test suite for the AudioWebBridge to validate initialization paths, DOM synchronization, and JS-to-Godot signal routing.
- Adjust audio save/load tests to account for the additional menu volume and mute fields in the config.
- Added and updated tests for web bridge, DOM sync, sliders/mutes, and back navigation.
Audio:
- Dedicated menu SFX channel for UI/menu effects.
- Settings now emit volume/mute events so external overlays stay in sync.
UI:
- Improved focus/navigation flow and centralized interactivity locking.
CI:
- Bump the pinned Codecov action SHA in the browser test workflow.
- Update the pinned markdownlint-cli2 action SHA in the README lint workflow.
- Refresh the pinned Release Drafter action SHAs in both release drafting workflows.
Chores:
- Updated GitHub Actions tool versions across CI/CD workflows to maintain compatibility and ensure optimal performance of automated testing, code quality, and release management processes.
Reviewer's Guide
Introduces a dedicated Menu SFX bus and global UI navigation sound, and refactors web audio integration into an AudioWebBridge autoload while updating audio settings UI, Globals, and tests to support the new bus and DOM-sync signaling.
This PR stops preloading the key mapping and options menu scenes in GameSettingsResource and instead exposes them as exported PackedScene references wired up via the default settings resource, eliminating a circular dependency while preserving behavior.
This PR performs maintenance on GitHub Actions workflows by updating pinned SHAs for third-party actions (Codecov, markdownlint-cli2, and release-drafter) to newer revisions for security and reliability, without changing workflow behavior or project code.
File-Level Changes
| Change | Details | Files |
|---|---|---|
| Refactor audio settings UI logic to support a hierarchical menu SFX bus, centralize mute/volume wiring, and delegate web/DOM responsibilities to a bridge autoload. |
|
scripts/audio_settings.gdscenes/audio_settings.tscntest/gdunit4/test_audio_settings.gdtest/gdunit4/test_audio_unexpected_exit.gdtests/back_flow_test.py |
| Add a dedicated SFX_Menu audio bus, persistent UI navigation sound, and expose audio changes via signals for UI and web layers. |
|
scripts/audio_constants.gdscripts/audio_manager.gdscripts/globals.gddefault_bus_layout.trestest/gut/test_basic_save_load_without_other_settings.gdtest/gdunit4/test_volume_slider.gdfiles/sounds/sfx/ui_navigation.wav.import |
| Introduce an AudioWebBridge autoload to own all web/JavaScript audio callbacks and DOM synchronization for sliders, mutes, and menu visibility. |
|
scripts/audio_web_bridge.gdscripts/audio_web_bridge.gd.uidtest/gut/test_audio_web_bridge.gdtest/gut/test_audio_web_bridge.gd.uid |
| Extend the HTML shell and Playwright/E2E tests to cover the new menu bus and updated logging and back-flow semantics. |
|
custom_shell.htmltests/volume_sliders_mutes_test.pytests/back_flow_test.py |
| Expose menu scenes as exported PackedScene references instead of preloading them directly to avoid circular dependencies. |
|
scripts/game_settings_resource.gd |
| Wire the key mapping and options menu scenes into the default settings resource inste... |
Milestone 14: Harden gameplay settings JS bridge and add comprehensive tests, Part #2
Description
This PR implements a comprehensive suite of unit tests and defensive programming patterns for the GameplaySettings module. The primary goal is to resolve Issue #471 (engine crashes during JavaScript-to-Godot communication) and to ensure the UI menu remains stable during complex lifecycle events and teardowns.
Key Changes & Bug Fixes
- Hardened JS Bridge: Added stricter type, bounds, and payload validation for JavaScript-to-Godot communication. This prevents engine crashes from malformed, empty, or out-of-range
JavaScriptBridgepayloads. - Lifecycle & Teardown Safety: Ensured
GameplaySettingsUI and observers safely handle missing or invalidGlobalssettings, freed nodes, and unexpected tree exits without crashing. - UI Synchronization: Fixed the difficulty label and slider to accurately reflect clamped values from the settings resource, including when values are updated via JavaScript.
- Signal Safety: Guarded against duplicate signal connections and unsafe disconnections by checking node validity before wiring or unwiring.
- Web Overlay State: Improved teardown logic to consistently clear JS callbacks and web overlay states while seamlessly restoring previous menus when appropriate.
- Type Flexibility: Relaxed the
js_windowreference type to a genericVariantto better support dictionary-based mocks and flexible JS interfaces.
Testing
- Resource Tests: Added tests for
GameSettingsResourceclamping, signal emission behavior, and boundary values. - UI & Reactivity Tests: Verified that the UI safely synchronizes from the resource, handles slider changes, resets behavior, and propagates observer-driven updates without feedback loops.
- JS Bridge Tests: Added coverage for valid payload shapes, malformed inputs, unsupported types, scalar regressions, and missing-node edge cases.
- Lifecycle Tests: Verified that cleanup on exit properly disconnects observers, restores previous menus, tears down web overlays, and nullifies callbacks (even if
Globalsis shaky).
Contributions
- @ikostan:
- Authored the core refactoring logic to resolve Issue #471, implementing strict
is_instance_validlifecycle guards across theGameplaySettingsmodule. - Designed and wrote the comprehensive GUT unit test suites covering the resource, UI reactivity, JS bridge, and lifecycle teardown paths.
- Fixed the critical WebGL/Emscripten crash by correctly implementing standard dot notation (
.length) forJavaScriptObjectproperties to avoid bridge evaluation errors. - Updated and verified E2E Playwright tests (
difficulty_flow_test.pyandreset_audio_flow_test.py) to align with the new value-normalization and DOM overlay logic. - Integrated and resolved feedback from automated review tools to ensure maximum stability and code quality.
- Authored the core refactoring logic to resolve Issue #471, implementing strict
AI & Bot Contributions
-
- Conducted automated code reviews and identified an edge case in
_on_change_difficulty_jswhereJavaScriptObjectpayloads could be improperly rejected, suggesting primitive extraction prior to type-checking. - Recommended hardening
_unset_gameplay_settings_window_callbacksto handle genericVariantscenarios safely in non-web or mocked environments. - Suggested test suite improvements, including adding
after_each()teardowns to prevent cross-test pollution and ensuring all JS callbacks (like_gameplay_reset_cb) are explicitly asserted as nullified during cleanup tests. - Generated detailed PR breakdowns categorizing changes by bug fixes, enhancements, and testing.
- Conducted automated code reviews and identified an edge case in
-
- Formatted and refined the pull request description structure.
- Generated high-level automated summaries emphasizing defensive signal wiring, missing-node safety, and strict validation of external JS inputs.
- Tracked chore-level updates, including the removal of inline citation comments to improve code readability.
-
@deepsource-io:
- Conducted automated static analysis and code review.
- Evaluated the pull request with an overall "A" grade, verifying that the new changes maintain high standards across security, reliability, complexity, and code hygiene.
Summary by @sourcery-ai & @coderabbitai
Harden GameplaySettings initialization, cleanup, and JS bridge handling while adding comprehensive tests for settings resource, UI synchronization, lifecycle behavior, and JavaScript communication.
Bug Fixes:
- Ensure gameplay settings UI and observers safely handle missing or invalid Globals/settings, freed nodes, and unexpected tree exits without crashing.
- Fix difficulty label and slider to always reflect clamped difficulty values from the settings resource, including values coming from JavaScript.
- Prevent engine crashes and bad state from malformed or scalar JavaScriptBridge payloads by validating types, bounds, and node availability before applying changes.
- Avoid duplicate signal connections and unsafe disconnections by guarding connections and checking node validity before connecting or disconnecting signals.
- Hardened gameplay settings UI: defensive signal wiring/teardown, safe handling when UI nodes are missing, and stricter validation/logging for external JS inputs (malformed, empty, out-of-range payloads).
Enhancements:
- Relax the type of the JS window reference to a generic Variant to support dictionary-based mocks and more flexible JS interfaces.
- Improve gameplay settings teardown to consistently clear JS callbacks and web overlay state while restoring previous menus when appropriate.
- Simplify and clarify Globals settings observer comments without changing behavior.
Tests:
- Add unit tests for GameSettingsResource clamping, signal emission behavior, and default/boundary values.
- Add initialization tests to verify GameplaySettings syncs its UI from the resource, connects observers once, and initializes safely in non-web environments.
- Add UI interaction tests to confirm slider changes, reset behavior, and observer-driven updates propagate correctly without feedback loops.
- Add JavaScriptBridge-focused tests covering valid payload shapes, malformed inputs, unsupported types, scalar regressions, and missing-node safety.
- Add lifecycle tests ensuring cleanup on exit disconnects observers, restores previous menus, tears down web overlays, and nullifies callbacks even with shaky Globals.
- Added comprehensive tests covering resource behavior, UI interactions, lifecycle/teardown, observer reactivity, and JS-bridge edge cases; updated an integration test's expected logs.
Chores:
- Removed inline citation comments for clarity. @deepsource-io
Reviewer's Guide
Strengthens GameplaySettings’ resilience to invalid or late JS / lifecycle events by guarding node and Globals access, routing all difficulty updates through the settings resource (with clamping), relaxing js_window typing, and adds extensive GUT test suites for the settings resource, gameplay settings UI, JS bridge, and lifecycle/cleanup paths.
File-Level Changes
| Change | Details | Files |
|---|---|---|
| Harden GameplaySettings initialization, observer wiring, and cleanup around missing or freed nodes and potentially-null Globals.settings. |
|
scripts/gameplay_settings.gd |
| Rework difficulty update flow and JS bridge callback to rely on the settings resource for clamping and to robustly handle varied JS payload shapes. |
|
scripts/gameplay_settings.gd |
| Remove inline citation-style comments from globals and existing tests for clarity. |
|
scripts/globals.gdtest/gut/test_globals_resource.gdtest/gut/test_settings_observer.gd |
| Introduce a focused lifecycle and cleanup test suite for GameplaySettings to validate signal disconnection, callback nulling, back-button behavior, and web overlay teardown. |
|
Milestone 14: Document observer-based settings system and pin CI actions, Part #1
Summary by @sourcery-ai & @coderabbitai
Document the observer-based game settings architecture and update CI workflows to use pinned, up-to-date GitHub Actions SHAs.
Enhancements:
- Harden gameplay settings cleanup by safely validating the global settings resource before disconnecting observers on tree exit. @ikostan
CI:
- Update CodeQL, Release Drafter, Snyk SARIF upload, and Trivy-related GitHub Actions to newer, SHA-pinned versions for consistency and security. @dependabot
Documentation:
- Expand the development guide with conceptual and technical documentation for the observer-based GameSettingsResource system and its setting_changed signal. @ikostan
- Highlight the observer-based settings system, automatic persistence, real-time UI synchronization, and dedicated settings tests in the main README. @ikostan
Tests:
- Document the dedicated GUT test suite for validating settings observer behavior, clamping, and serialization.
- Updated development status to Milestone 14.
- Added documentation for the observer-based Settings System with automatic persistence and real-time UI synchronization.
- Added Settings Observer Tests section describing validation coverage.
- Added new development guide for working with Game Settings.
Chores:
- Updated GitHub Actions versions for CodeQL, Release Drafter, Snyk, and Trivy.
Reviewer's Guide
Documents the observer-based game settings system (including signal signatures and core file responsibilities), tightens cleanup of settings observers in gameplay_settings.gd, and updates several GitHub Actions (CodeQL, upload-sarif, Release Drafter) to newer pinned SHAs for consistency and security.
File-Level Changes
| Change | Details | Files |
|---|---|---|
| Document the observer-based GameSettingsResource settings system and its usage patterns. |
|
files/docs/Development_Guide.md |
| Update project README to reflect the observer-based settings system and current development status. |
|
README.md |
| Harden cleanup of settings observers in gameplay_settings.gd to avoid invalid references during node teardown. |
|
scripts/gameplay_settings.gd |
| Refresh CodeQL workflow to a newer pinned SHA for improved security and consistency. |
|
.github/workflows/codeql.yml |
| Align Snyk and Trivy workflows to a newer pinned upload-sarif action and update Release Drafter GitHub Action SHAs. |
|
.github/workflows/snyk.yml.github/workflows/trivy.yml.github/workflows/release_drafter.yml.github/workflows/release_drafter_pr.yml |
Assessment against linked issues
| Issue | Objective | Addressed | Explanation |
|---|---|---|---|
| #453 | Update README.md to reflect the current development milestone status and overall project progress for the latest completed milestone. | ✅ | |
| #453 | Update README.md to summarize and highlight newly delivered features and improvements relevant to this milestone, ensuring it remains a clear, up-to-date project hub (including documenting the observer-based settings system and its tests). | ✅ |
🤖 AI & Bot Contributions Summary
Pull Request #479 significantly benefited from automated maintenance, security scanning, and documentation support. These contributions ensure code quality, dependency security, and project transparency.
Key Contributions
- Automated Dependency Management: Scanned and updated project dependencies to ensure the development environment remains secure and up-to-date.
- Continuous Integration (CI): Executed automated test suites via GitHub Actions to validate gameplay logic, fuel systems, and input remapping.
- Security Analysis: Performed static analysis to identify potential vulnerabilities within the Godot and Python-based toolsets.
- Documentation Automation: Assisted in generating changelogs and updating project milestones to reflect current development progress.
Contributor Credits
To ensure these automated contributors are properly recognized in the GitHub contributors list, they are credited using their official GitHub handles:
| Contributor | Role |
|---|---|
| @github-actions[bot] | CI/CD Pipeline & Automated Testing |
| @dependabot[bot] | Dependency Updates & Security Patches |
| @snyk-bot | Vulnerability Scanning & Security Analysis |
| @release-drafter[bot] | Automated Changelog & Release Management |
This summary was generated to provide a clear overview of non-human contributions to the SkyLockAssault repository.
Milestone 13: Adopt observer-based settings with automatic save and UI sync, Part #4
Summary by @sourcery-ai & @coderabbitai
Adopt an observer-based settings system that centralizes reactions to configuration changes, enabling automatic logging, persistence, and UI synchronization.
New Features:
- Introduce a settings_changed signal on GameSettingsResource to notify observers of configuration updates. @ikostan
- Add support for an enable_debug_logging setting that can be toggled and persisted. @ikostan
- Wire gameplay and advanced settings UIs to observe GameSettingsResource so they react automatically to external changes. @ikostan
- Real-time settings propagation so UI components update immediately when settings change. @ikostan
Enhancements:
- Refine settings properties to use validated setters/getters, including clamping difficulty and emitting change notifications.
- Have Globals.gd observe GameSettingsResource changes to automatically log updates and save settings without direct UI calls.
- Ensure gameplay difficulty UI stays in sync with the resource using signal-safe updates and removes redundant manual persistence calls.
- Settings now auto-persist and emit change notifications; UI no longer triggers manual saves.
- Difficulty input is validated/clamped; UI syncs from external updates.
- Minor log message wording updated for clarity.
Tests:
- Add a GUT test suite validating the settings observer pattern, including signal emission, clamping behavior, persistence to disk, and UI reactivity.
- Update the difficulty flow end-to-end test to match the new difficulty change log message text.
- Added tests covering observer behavior, clamping, persistence, and UI synchronization.
Reviewer's Guide
Introduce an observer-based settings flow where GameSettingsResource emits setting_changed signals, Globals listens for those to log and persist automatically, and the gameplay/advanced settings UIs plus tests are updated to align with this reactive, clamped, and auto-synced model.
File-Level Changes
| Change | Details | Files |
|---|---|---|
| Turn GameSettingsResource into an observable settings source with clamped setters and backing fields. |
|
scripts/game_settings_resource.gd |
| Make Globals observe GameSettingsResource changes and centralize logging and persistence. |
|
scripts/globals.gd |
| Update gameplay and advanced settings menus to rely on the observable resource instead of manual save/logging. |
|
scripts/gameplay_settings.gdscripts/advanced_settings.gd |
| Align tests with the observer pattern and new logging format. |
|
tests/difficulty_flow_test.pytest/gut/test_settings_observer.gdtest/gut/test_settings_observer.gd.uid |
Assessment against linked issues
| Issue | Objective | Addressed | Explanation |
|---|---|---|---|
| #432 | Replace ConfigFile-based persistence in Globals._load_settings() and Globals._save_settings() with Resource-backed persistence using ResourceLoader/ResourceSaver for GameSettingsResource (storing settings as .tres). | ❌ | The PR keeps using ConfigFile in Globals._load_settings() and Globals._save_settings(), only extending it to handle enable_debug_logging. There is no use of ResourceLoader.load() or ResourceSaver.save(), nor any .tres-based persistence paths introduced. |
| #432 | Update tests to validate the new Resource-based settings persistence instead of relying on the legacy ConfigFile format. | ❌ | Existing tests remain ConfigFile-oriented (e.g., difficulty_flow_test.py checks logs around settings saved), and the new GUT tests in test_settings_observer.gd explicitly interact with ConfigFile and .cfg paths for persistence. No tests are added or modified to verify .tres Resource save/load behavior. |
AI & Bot Contributions Summary
@sourcery-ai
- Summary Generation: Provided a high-level summary of the PR, highlighting the transition to an observer-based settings system.
- Code Review: Reviewed the implementation of the
GameSettingsResourcesignals and the automatic synchronization with the UI. - Description Refinement: Assisted in refining the PR description to clearly outline new features like
enable_debug_loggingand the GUT test suite for observer pattern validation.
@coderabbitai
- Feature Review: Analyzed the real-time settings propagation to ensure UI components update immediately upon resource changes.
- Logic Validation: Identified and suggested improvements for the validation and clamping of difficulty settings.
- Maintenance Recommendations: Flagged potential memory leak issues, specifically recommending the explicit disconnection of the
setting_changedsignal in_on_tree_exitedto avoid stale observers. - Co-authored Commits: Contributed directly to script updates in
game_settings_resource.gdandgameplay_settings.gd.
@deepsource-autofix
- Code Quality & Styling: Automatically performed linting and code formatting for Python files.
- Standardization: Applied
Blackandisortformatting todifficulty_flow_test.pyto ensure compliance with project style guides after manual updates.
Milestone 13: Maintenance, Part #3
Summary by @sourcery-ai & @coderabbitai
Update security and release GitHub Actions to newer pinned versions.
CI:
- Bump CodeQL init, autobuild, and analyze actions to v4.32.6 in the code scanning workflow. @dependabot[
- Update github/codeql-action upload-sarif SHA used by Snyk and Trivy workflows. @dependabot[
- Refresh release-drafter action to a newer pinned commit in both release and PR workflows. @dependabot[
Chores:
- Updated GitHub Actions versions in CI/CD pipelines to the latest releases for enhanced security scanning, code analysis, and release automation reliability. @ikostan
Reviewer's Guide
This PR performs maintenance on GitHub Actions workflows by updating pinned versions of CodeQL-related actions, Snyk SARIF upload steps, Trivy SARIF upload steps, and Release Drafter to newer commits/versions.
File-Level Changes
| Change | Details | Files |
|---|---|---|
| Update CodeQL workflow actions to the latest pinned v4.32.6 series. |
|
.github/workflows/codeql.yml |
| Update github/codeql-action/upload-sarif pins used by Snyk workflows to a newer commit. |
|
.github/workflows/snyk.yml |
| Update Release Drafter GitHub Action to a newer pinned commit in both release and PR workflows. |
|
.github/workflows/release_drafter.yml.github/workflows/release_drafter_pr.yml |
| Update github/codeql-action/upload-sarif pin used by Trivy workflow to a newer commit. |
|
.github/workflows/trivy.yml |
Ingame images are optimized!
The image file size has been reduced by 5% 🎉 @imgbot[bot]
Details
| File | Before | After | Percent reduction |
|---|---|---|---|
| /files/rotor/rotor00.png | 3.13kb | 0.88kb | 72.09% |
| /files/rotor/rotor11.png | 3.15kb | 0.89kb | 71.81% |
| /files/rotor/rotor10.png | 3.14kb | 0.89kb | 71.65% |
| /files/rotor/rotor01.png | 3.16kb | 0.91kb | 71.30% |
| /files/rotor/rotor02.png | 3.15kb | 0.92kb | 70.67% |
| /files/rotor/rotor09.png | 3.17kb | 0.94kb | 70.42% |
| /files/rotor/rotor08.png | 3.21kb | 1.02kb | 68.25% |
| /files/rotor/rotor03.png | 3.18kb | 1.03kb | 67.71% |
| /files/rotor/rotor07.png | 3.21kb | 1.08kb | 66.19% |
| /files/rotor/rotor05.png | 3.22kb | 1.10kb | 65.87% |
| /files/rotor/rotor04.png | 3.19kb | 1.09kb | 65.74% |
| /files/rotor/rotor06.png | 3.24kb | 1.11kb | 65.65% |
| /files/sprite/PixelPlanesAssetPack.png | 7.42kb | 3.53kb | 52.48% |
| /files/sprite/laser_sprites/47.png | 14.27kb | 10.60kb | 25.71% |
| /files/sprite/laser_sprites/29.png | 9.39kb | 7.00kb | 25.50% |
| /files/sprite/laser_sprites/20.png | 9.74kb | 7.61kb | 21.82% |
| /files/img/main_menu_3.jpeg | 428.74kb | 337.78kb | 21.22% |
| /files/sprite/laser_sprites/38.png | 22.53kb | 17.76kb | 21.16% |
| /files/img/main_menu.jpeg | 331.37kb | 261.31kb | 21.14% |
| /files/img/main_menu_2.png | 1,595.46kb | 1,397.91kb | 12.38% |
| /files/sprite/laser_sprites/52.png | 10.72kb | 9.97kb | 7.00% |
| /files/sprite/laser_sprites/54.png | 10.40kb | 9.68kb | 6.96% |
| /files/sprite/laser_sprites/17.png | 11.43kb | 10.65kb | 6.77% |
| /files/sprite/laser_sprites/15.png | 11.95kb | 11.16kb | 6.64% |
| /files/sprite/laser_sprites/16.png | 12.06kb | 11.27kb | 6.55% |
| /files/sprite/laser_sprites/50.png | 10.73kb | 10.05kb | 6.35% |
| /files/sprite/laser_sprites/32.png | 51.94kb | 48.65kb | 6.34% |
| /files/sprite/laser_sprites/11.png | 14.25kb | 13.35kb | 6.31% |
| /files/sprite/laser_sprites/51.png | 10.92kb | 10.23kb | 6.30% |
| /files/sprite/laser_sprites/18.png | 11.25kb | 10.54kb | 6.28% |
| /files/sprite/laser_sprites/53.png | 10.92kb | 10.24kb | 6.24% |
| /files/sprite/laser_sprites/64.png | 22.15kb | 20.78kb | 6.22% |
| /files/sprite/laser_sprites/31.png | 51.24kb | 48.05kb | 6.22% |
| /files/sprite/laser_sprites/49.png | 10.94kb | 10.27kb | 6.20% |
| /files/sprite/laser_sprites/35.png | 33.04kb | 31.02kb | 6.13% |
| /files/sprite/laser_sprites/30.png | 49.44kb | 46.48kb | 6.00% |
| /files/sprite/laser_sprites/19.png | 13.23kb | 12.44kb | 5.99% |
| /files/sprite/laser_sprites/14.png | 13.92kb | 13.12kb | 5.75% |
| /files/sprite/laser_sprites/12.png | 14.92kb | 14.06kb | 5.75% |
| /files/sprite/laser_sprites/33.png | 40.73kb | 38.41kb | 5.69% |
| /files/sprite/laser_sprites/37.png | 37.07kb | 34.98kb | 5.64% |
| /files/sprite/laser_sprites/13.png | 14.74kb | 13.92kb | 5.55% |
| /files/sprite/laser_sprites/42.png | 19.68kb | 18.61kb | 5.41% |
| /files/sprite/laser_sprites/66.png | 23.57kb | 22.31kb | 5.31% |
| /files/sprite/laser_sprites/65.png | 23.76kb | 22.52kb | 5.22% |
| /files/sprite/laser_sprites/36.png | 32.77kb | 31.09kb | 5.13% |
| /files/sprite/laser_sprites/27.png | 11.32kb | 10.75kb | 5.05% |
| /files/sprite/laser_sprites/34.png | 34.15kb | 32.52kb | 4.77% |
| /files/sprite/laser_sprites/09.png | 6.32kb | 6.02kb | 4.68% |
| /files/sprite/laser_sprites/05.png | 9.49kb | 9.06kb | 4.58% |
| /files/trees/tree_44.png | 20.72kb | 19.78kb | 4.58% |
| /files/sprite/laser_sprites/46.png | 18.66kb | 17.81kb | 4.57% |
| /files/trees/tree_55.png | 12.17kb | 11.61kb | 4.56% |
| /files/sprite/laser_sprites/39.png | 20.84kb | 19.89kb | 4.55% |
| /files/sprite/laser_sprites/44.png | 17.34kb | 16.57kb | 4.42% |
| /files/sprite/laser_sprites/40.png | 24.12kb | 23.07kb | 4.39% |
| /files/sprite/laser_sprites/43.png | 16.12kb | 15.43kb | 4.30% |
| /files/sprite/laser_sprites/45.png | 18.00kb | 17.23kb | 4.24% |
| /files/trees/tree_52.png | 8.50kb | 8.14kb | 4.24% |
| /files/trees/tree_54.png | 14.93kb | 14.31kb | 4.15% |
| /files/sprite/laser_sprites/26.png | 10.05kb | 9.65kb | 3.98% |
| /files/trees/tree_40.png | 8.57kb | 8.23kb | 3.97% |
| /files/sprite/laser_sprites/25.png | 12.29kb | 11.81kb | 3.93% |
| /files/trees/tree_53.png | 15.83kb | 15.21kb | 3.88% |
| /files/sprite/laser_sprites/41.png | 20.11kb | 19.34kb | 3.83% |
| /files/sprite/laser_sprites/08.png | 7.12kb | 6.85kb | 3.77% |
| /files/ground_tilesest/decor/road_2.png | 22.28kb | 21.44kb | 3.77% |
| /files/sprite/laser_sprites/10.png | 6.62kb | 6.38kb | 3.69% |
| /files/sprite/laser_sprites/04.png | 9.00kb | 8.67kb | 3.68% |
| /files/sprite/laser_sprites/28.png | 13.30kb | 12.82kb | 3.66% |
| /files/sprite/laser_sprites/03.png | 8.18kb | 7.88kb | 3.64% |
| /files/random_decor/crates_2.png | 5.30kb | 5.11kb | 3.63% |
| /files/ground_tilesest/decor/crates_2.png | 5.30kb | 5.11kb | 3.63% |
| /files/sprite/laser_sprites/22.png | 12.48kb | 12.04kb | 3.51% |
| /files/sprite/laser_sprites/01.png | 8.60kb | 8.30kb | 3.51% |
| /files/sprite/laser_sprites/21.png | 13.05kb | 12.59kb | 3.49% |
| /files/sprite/laser_sprites/62.png | 34.05kb | 32.86kb | 3.48% |
| /files/sprite/laser_sprites/02.png | 8.57kb | 8.28kb | 3.47% |
| /files/sprite/laser_sprites/06.png | 8.88kb | 8.57kb | 3.46% |
| /files/sprite/laser_sprites/07.png | 7.45kb | 7.19kb | 3.42% |
| /files/sprite/laser_sprites/59.png | 34.06kb | 32.91kb | 3.39% |
| /files/ground_tilesest/images/beach_r_up_diagonal_grass.png | 44.09kb | 42.61kb | 3.36% |
| /files/sprite/laser_sprites/56.png | 33.97kb | 32.86kb | 3.27% |
| /files/trees/tree_39.png | 21.81kb | 21.11kb | 3.20% |
| /files/sprite/laser_sprites/63.png | 33.92kb | 32.84kb | 3.17% |
| /files/trees/tree_48.png | 5.04kb | 4.88kb | 3.16% |
| /files/ground_tilesest/decor/road_corner_3.png | 10.85kb | 10.51kb | 3.11% |
| /files/sprite/laser_sprites/60.png | 34.19kb | 33.13kb | 3.10% |
| /files/sprite/laser_sprites/55.png | 33.19kb | 32.17kb | 3.07% |
| /files/sprite/laser_sprites/58.png | 33.77kb | 32.74kb | 3.05% |
| /files/sprite/laser_sprites/23.png | 14.21kb | 13.78kb | 3.03% |
| /files/sprite/laser_sprites/57.png | 34.25kb | 33.22kb | 2.99% |
| /files/trees/tree_38.png | 23.50kb | 22.80kb | 2.95% |
| /files/ground_tilesest/decor/road_corner_4.png | 10.81kb | 10.49kb | 2.92% |
| /files/ground_tilesest/images/beach_rm_02_grass.png | 45.17kb | 43.86kb | 2.90% |
| /files/ground_tilesest/decor/road_corner_1.png | 10.74kb | 10.43kb | 2.87% |
| /files/sprite/laser_sprites/61.png | 33.22kb | 32.27kb | 2.86% |
| /files/ground_tilesest/images/beach_l_up_diagonal_grass.png | 43.71kb | 42.46kb | 2.86% |
| /files/ground_tilesest/images/beach_lm_04_grass.png | 44.87kb | 43.60kb | 2.83% |
| /files/ground_tilesest/images/beach_bm_03_grass.png | 44.41kb | 43.20kb | 2.72% |
| /files/ground_tilesest/decor/road_corner_2.png | 10.86kb | 10.57kb | 2.67% |
| /files/trees/tree_43.png | 11.84kb | 11.52kb | 2.64% |
| /files/ground_tilesest/images/beach_rm_04_grass.png | 45.22kb | 44.05kb | 2.57% |
| /files/ground_tilesest/images/beach_r_down_diagonal_grass.png | 43.31kb | 42.22kb | 2.51% |
| /files/ground_tilesest/decor/road_4.png | 34.37kb | 33.50kb | 2.51% |
| /files/ground_tilesest/decor/road_3.png | 34.96kb | 34.10kb | 2.47% |
| /files/trees/tree_49.png | 5.26kb | 5.13kb | 2.41% |
| /files/trees/tree_28.png | 13.52kb | 13.20kb | 2.40% |
| /files/ground_tilesest/images/beach_rm_01_grass-22.png | 42.06kb | 41.05kb | 2.39% |
| /files/trees/tree_41.png | 10.33kb | 10.09kb | 2.34% |
| /files/ground_tilesest/decor/grass_02.png | 43.65kb | 42.64kb | 2.31% |
| /files/random_decor/grass_02.png | 43.65kb | 42.64kb | 2.31% |
| /files/ground... |