PressAnyKeyScreen → SplashScreen
This commit is contained in:
@@ -1,2 +1,7 @@
|
|||||||
- The documentation of the project is located in docs/ directory.
|
- The documentation of the project is located in docs/ directory.
|
||||||
So the docs\CLAUDE.md does. Get it in context before doing anything else.
|
- Get following files in context before doing anything else:
|
||||||
|
- docs\CLAUDE.md
|
||||||
|
- docs\CODE_OF_CONDUCT.md
|
||||||
|
- project.godot
|
||||||
|
- Use TDD methodology for development
|
||||||
|
- Keep documentation up to date
|
||||||
|
|||||||
12
docs/MAP.md
12
docs/MAP.md
@@ -76,7 +76,7 @@ Located in `src/autoloads/`, these scripts are automatically loaded when the gam
|
|||||||
### Main Scenes
|
### Main Scenes
|
||||||
```
|
```
|
||||||
main.tscn (Entry Point)
|
main.tscn (Entry Point)
|
||||||
├── PressAnyKeyScreen.tscn
|
├── SplashScreen.tscn
|
||||||
├── MainMenu.tscn
|
├── MainMenu.tscn
|
||||||
└── SettingsMenu.tscn
|
└── SettingsMenu.tscn
|
||||||
|
|
||||||
@@ -90,11 +90,11 @@ game.tscn (Gameplay Container)
|
|||||||
### Game Flow
|
### Game Flow
|
||||||
1. **Main Scene** (`scenes/main/main.tscn` + `Main.gd`)
|
1. **Main Scene** (`scenes/main/main.tscn` + `Main.gd`)
|
||||||
- Application entry point
|
- Application entry point
|
||||||
- Manages "Press Any Key" screen
|
- Manages splash screen
|
||||||
- Transitions to main menu
|
- Transitions to main menu
|
||||||
- Dynamic menu loading system
|
- Dynamic menu loading system
|
||||||
|
|
||||||
2. **Press Any Key Screen** (`scenes/main/PressAnyKeyScreen.tscn` + `PressAnyKeyScreen.gd`)
|
2. **Splash Screen** (`scenes/main/SplashScreen.tscn` + `SplashScreen.gd`)
|
||||||
- Initial splash screen
|
- Initial splash screen
|
||||||
- Input detection for any key/button
|
- Input detection for any key/button
|
||||||
- Signals to main scene for transition
|
- Signals to main scene for transition
|
||||||
@@ -184,7 +184,7 @@ The game now uses a modular gameplay architecture where different game modes can
|
|||||||
|
|
||||||
### Debug System
|
### Debug System
|
||||||
- Global debug state via DebugManager with initialization
|
- Global debug state via DebugManager with initialization
|
||||||
- Debug toggle available on all major scenes (MainMenu, SettingsMenu, PressAnyKeyScreen, Game)
|
- Debug toggle available on all major scenes (MainMenu, SettingsMenu, SplashScreen, Game)
|
||||||
- Match-3 specific debug UI panel with gem count controls and difficulty presets
|
- Match-3 specific debug UI panel with gem count controls and difficulty presets
|
||||||
- Gem count controls (+/- buttons) with difficulty presets (Easy: 3, Normal: 5, Hard: 8)
|
- Gem count controls (+/- buttons) with difficulty presets (Easy: 3, Normal: 5, Hard: 8)
|
||||||
- Board reroll functionality for testing
|
- Board reroll functionality for testing
|
||||||
@@ -282,7 +282,7 @@ sprites:
|
|||||||
|
|
||||||
### Signal Connections
|
### Signal Connections
|
||||||
```
|
```
|
||||||
PressAnyKeyScreen --[any_key_pressed]--> Main
|
SplashScreen --[any_key_pressed]--> Main
|
||||||
MainMenu --[open_settings]--> Main
|
MainMenu --[open_settings]--> Main
|
||||||
SettingsMenu --[back_to_main_menu]--> Main
|
SettingsMenu --[back_to_main_menu]--> Main
|
||||||
DebugManager --[debug_toggled]--> All scenes with DebugToggle
|
DebugManager --[debug_toggled]--> All scenes with DebugToggle
|
||||||
@@ -339,7 +339,7 @@ DebugManager.log_error("Invalid scene path provided", "GameManager")
|
|||||||
# - Settings: Settings management, language changes
|
# - Settings: Settings management, language changes
|
||||||
# - Game: Main game scene, mode switching
|
# - Game: Main game scene, mode switching
|
||||||
# - MainMenu: Main menu interactions
|
# - MainMenu: Main menu interactions
|
||||||
# - PressAnyKey: Press any key screen
|
# - SplashScreen: Splash screen
|
||||||
# - Clickomania: Clickomania gameplay mode
|
# - Clickomania: Clickomania gameplay mode
|
||||||
# - DebugMenu: Debug menu operations
|
# - DebugMenu: Debug menu operations
|
||||||
```
|
```
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -14,6 +14,8 @@ config/name="Skelly"
|
|||||||
run/main_scene="res://scenes/main/main.tscn"
|
run/main_scene="res://scenes/main/main.tscn"
|
||||||
config/features=PackedStringArray("4.4", "Mobile")
|
config/features=PackedStringArray("4.4", "Mobile")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
boot_splash/handheld/orientation=0
|
||||||
|
boot_splash/stretch/aspect="keep"
|
||||||
|
|
||||||
[audio]
|
[audio]
|
||||||
|
|
||||||
@@ -27,9 +29,36 @@ GameManager="*res://src/autoloads/GameManager.gd"
|
|||||||
LocalizationManager="*res://src/autoloads/LocalizationManager.gd"
|
LocalizationManager="*res://src/autoloads/LocalizationManager.gd"
|
||||||
DebugManager="*res://src/autoloads/DebugManager.gd"
|
DebugManager="*res://src/autoloads/DebugManager.gd"
|
||||||
SaveManager="*res://src/autoloads/SaveManager.gd"
|
SaveManager="*res://src/autoloads/SaveManager.gd"
|
||||||
|
UIConstants="*res://src/autoloads/UIConstants.gd"
|
||||||
|
|
||||||
|
[display]
|
||||||
|
|
||||||
|
window/size/viewport_width=1920
|
||||||
|
window/size/viewport_height=1080
|
||||||
|
window/stretch/mode="canvas_items"
|
||||||
|
window/handheld/orientation=4
|
||||||
|
|
||||||
[input]
|
[input]
|
||||||
|
|
||||||
|
ui_pause={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||||
|
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":6,"pressure":0.0,"pressed":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
any_key={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||||
|
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
|
||||||
|
, Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(165, 16),"global_position":Vector2(174, 64),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
ui_menu_toggle={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||||
|
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":1,"pressure":0.0,"pressed":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
action_south={
|
action_south={
|
||||||
"deadzone": 0.2,
|
"deadzone": 0.2,
|
||||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
|
||||||
|
|||||||
@@ -78,13 +78,21 @@ echo.
|
|||||||
echo === %test_name% ===
|
echo === %test_name% ===
|
||||||
echo Running: %test_file%
|
echo Running: %test_file%
|
||||||
|
|
||||||
godot --headless --script "%test_file%"
|
REM Run the test and capture the exit code
|
||||||
if !errorlevel! equ 0 (
|
godot --headless --script "%test_file%" >temp_test_output.txt 2>&1
|
||||||
|
set test_exit_code=!errorlevel!
|
||||||
|
|
||||||
|
REM Display results based on exit code
|
||||||
|
if !test_exit_code! equ 0 (
|
||||||
echo PASSED: %test_name%
|
echo PASSED: %test_name%
|
||||||
) else (
|
) else (
|
||||||
echo FAILED: %test_name%
|
echo FAILED: %test_name%
|
||||||
set /a failed_tests+=1
|
set /a failed_tests+=1
|
||||||
)
|
)
|
||||||
set /a total_tests+=1
|
set /a total_tests+=1
|
||||||
|
|
||||||
|
REM Clean up temporary file
|
||||||
|
if exist temp_test_output.txt del temp_test_output.txt
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
goto :eof
|
goto :eof
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[gd_scene load_steps=4 format=3 uid="uid://dmwkyeq2l7u04"]
|
[gd_scene load_steps=4 format=3 uid="uid://dmwkyeq2l7u04"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://b16jnk7w22mb" path="res://scenes/game/game.gd" id="1_uwrxv"]
|
[ext_resource type="Script" uid="uid://bs4veuda3h358" path="res://scenes/game/game.gd" id="1_uwrxv"]
|
||||||
[ext_resource type="PackedScene" path="res://scenes/ui/DebugToggle.tscn" id="3_debug"]
|
[ext_resource type="PackedScene" path="res://scenes/ui/DebugToggle.tscn" id="3_debug"]
|
||||||
[ext_resource type="Texture2D" uid="uid://c8y6tlvcgh2gn" path="res://assets/textures/backgrounds/beanstalk-dark.webp" id="5_background"]
|
[ext_resource type="Texture2D" uid="uid://c8y6tlvcgh2gn" path="res://assets/textures/backgrounds/beanstalk-dark.webp" id="5_background"]
|
||||||
|
|
||||||
@@ -21,6 +21,7 @@ anchor_bottom = 1.0
|
|||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
texture = ExtResource("5_background")
|
texture = ExtResource("5_background")
|
||||||
|
expand_mode = 1
|
||||||
stretch_mode = 1
|
stretch_mode = 1
|
||||||
|
|
||||||
[node name="UI" type="Control" parent="."]
|
[node name="UI" type="Control" parent="."]
|
||||||
@@ -53,7 +54,9 @@ grow_vertical = 2
|
|||||||
|
|
||||||
[node name="BackButtonContainer" type="Control" parent="."]
|
[node name="BackButtonContainer" type="Control" parent="."]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 0
|
anchors_preset = 1
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
offset_left = 10.0
|
offset_left = 10.0
|
||||||
offset_top = 10.0
|
offset_top = 10.0
|
||||||
offset_right = 55.0
|
offset_right = 55.0
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
@onready var press_any_key_screen = $PressAnyKeyScreen
|
@onready var splash_screen = $SplashScreen
|
||||||
var current_menu = null
|
var current_menu = null
|
||||||
|
|
||||||
const MAIN_MENU_SCENE = preload("res://scenes/ui/MainMenu.tscn")
|
const MAIN_MENU_SCENE = preload("res://scenes/ui/MainMenu.tscn")
|
||||||
@@ -8,11 +8,53 @@ const SETTINGS_MENU_SCENE = preload("res://scenes/ui/SettingsMenu.tscn")
|
|||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
DebugManager.log_debug("Main scene ready", "Main")
|
DebugManager.log_debug("Main scene ready", "Main")
|
||||||
press_any_key_screen.any_key_pressed.connect(_on_any_key_pressed)
|
# Use alternative connection method with input handling
|
||||||
|
_setup_splash_screen_connection()
|
||||||
|
|
||||||
|
func _setup_splash_screen_connection():
|
||||||
|
# Wait for all nodes to be ready
|
||||||
|
await get_tree().process_frame
|
||||||
|
await get_tree().process_frame
|
||||||
|
|
||||||
|
# Try to find SplashScreen node
|
||||||
|
splash_screen = get_node_or_null("SplashScreen")
|
||||||
|
if not splash_screen:
|
||||||
|
DebugManager.log_warn("SplashScreen node not found, trying alternative methods", "Main")
|
||||||
|
# Try to find by class or group
|
||||||
|
var splash_nodes = get_tree().get_nodes_in_group("localizable")
|
||||||
|
for node in splash_nodes:
|
||||||
|
if node.scene_file_path.ends_with("SplashScreen.tscn"):
|
||||||
|
splash_screen = node
|
||||||
|
break
|
||||||
|
|
||||||
|
if splash_screen:
|
||||||
|
DebugManager.log_debug("SplashScreen node found: %s" % splash_screen.name, "Main")
|
||||||
|
# Try connecting to the signal if it exists
|
||||||
|
if splash_screen.has_signal("any_key_pressed"):
|
||||||
|
splash_screen.any_key_pressed.connect(_on_any_key_pressed)
|
||||||
|
DebugManager.log_debug("Connected to any_key_pressed signal", "Main")
|
||||||
|
else:
|
||||||
|
# Fallback: use input handling directly on the main scene
|
||||||
|
DebugManager.log_warn("Using fallback input handling", "Main")
|
||||||
|
_use_fallback_input_handling()
|
||||||
|
else:
|
||||||
|
DebugManager.log_error("Could not find SplashScreen node", "Main")
|
||||||
|
_use_fallback_input_handling()
|
||||||
|
|
||||||
|
func _use_fallback_input_handling():
|
||||||
|
# Fallback: handle input directly in the main scene
|
||||||
|
set_process_unhandled_input(true)
|
||||||
|
|
||||||
|
func _unhandled_input(event):
|
||||||
|
if splash_screen and splash_screen.is_inside_tree():
|
||||||
|
# Forward input to splash screen or handle directly
|
||||||
|
if event.is_action_pressed("action_south"):
|
||||||
|
_on_any_key_pressed()
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
|
||||||
func _on_any_key_pressed():
|
func _on_any_key_pressed():
|
||||||
DebugManager.log_debug("Transitioning to main menu", "Main")
|
DebugManager.log_debug("Transitioning to main menu", "Main")
|
||||||
press_any_key_screen.queue_free()
|
splash_screen.queue_free()
|
||||||
show_main_menu()
|
show_main_menu()
|
||||||
|
|
||||||
func show_main_menu():
|
func show_main_menu():
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ extends Control
|
|||||||
signal any_key_pressed
|
signal any_key_pressed
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
DebugManager.log_debug("PressAnyKeyScreen ready", "PressAnyKey")
|
DebugManager.log_debug("SplashScreen ready", "SplashScreen")
|
||||||
update_text()
|
update_text()
|
||||||
|
|
||||||
func _input(event):
|
func _input(event):
|
||||||
if event.is_action_pressed("action_south") or event is InputEventScreenTouch or (event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed):
|
if event.is_action_pressed("action_south") or event is InputEventScreenTouch or (event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed):
|
||||||
DebugManager.log_debug("Action pressed: " + str(event), "PressAnyKey")
|
DebugManager.log_debug("Action pressed: " + str(event), "SplashScreen")
|
||||||
any_key_pressed.emit()
|
any_key_pressed.emit()
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
|
|
||||||
func update_text():
|
func update_text():
|
||||||
$PressKeyContainer/PressKeyLabel.text = tr("press_ok_continue")
|
$SplashContainer/ContinueLabel.text = tr("press_ok_continue")
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[gd_scene load_steps=16 format=3 uid="uid://gbe1jarrwqsi"]
|
[gd_scene load_steps=16 format=3 uid="uid://gbe1jarrwqsi"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://cq7or0bcm2xfj" path="res://scenes/main/PressAnyKeyScreen.gd" id="1_0a4p2"]
|
[ext_resource type="Script" uid="uid://cq7or0bcm2xfj" path="res://scenes/main/SplashScreen.gd" id="1_0a4p2"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bcr4bokw87m5n" path="res://assets/sprites/characters/skeleton/Skeleton Idle.png" id="2_rjjcb"]
|
[ext_resource type="Texture2D" uid="uid://bcr4bokw87m5n" path="res://assets/sprites/characters/skeleton/Skeleton Idle.png" id="2_rjjcb"]
|
||||||
[ext_resource type="PackedScene" uid="uid://df2b4wn8j6cxl" path="res://scenes/ui/DebugToggle.tscn" id="3_debug"]
|
[ext_resource type="PackedScene" uid="uid://df2b4wn8j6cxl" path="res://scenes/ui/DebugToggle.tscn" id="3_debug"]
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ animations = [{
|
|||||||
"speed": 5.0
|
"speed": 5.0
|
||||||
}]
|
}]
|
||||||
|
|
||||||
[node name="PressAnyKeyScreen" type="Control" groups=["localizable"]]
|
[node name="SplashScreen" type="Control" groups=["localizable"]]
|
||||||
layout_mode = 3
|
layout_mode = 3
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
@@ -98,7 +98,7 @@ grow_horizontal = 2
|
|||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
script = ExtResource("1_0a4p2")
|
script = ExtResource("1_0a4p2")
|
||||||
|
|
||||||
[node name="PressKeyContainer" type="VBoxContainer" parent="."]
|
[node name="SplashContainer" type="VBoxContainer" parent="."]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 8
|
anchors_preset = 8
|
||||||
anchor_left = 0.5
|
anchor_left = 0.5
|
||||||
@@ -113,24 +113,21 @@ grow_horizontal = 2
|
|||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
metadata/_edit_use_anchors_ = true
|
metadata/_edit_use_anchors_ = true
|
||||||
|
|
||||||
[node name="AspectRatioContainer" type="AspectRatioContainer" parent="PressKeyContainer"]
|
[node name="SpriteContainer" type="Control" parent="SplashContainer"]
|
||||||
|
custom_minimum_size = Vector2(30, 32)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 4
|
size_flags_horizontal = 4
|
||||||
size_flags_vertical = 0
|
|
||||||
alignment_horizontal = 0
|
|
||||||
alignment_vertical = 0
|
|
||||||
|
|
||||||
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="PressKeyContainer/AspectRatioContainer"]
|
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="SplashContainer/SpriteContainer"]
|
||||||
sprite_frames = SubResource("SpriteFrames_wtrhp")
|
sprite_frames = SubResource("SpriteFrames_wtrhp")
|
||||||
autoplay = "default"
|
autoplay = "default"
|
||||||
offset = Vector2(0, -30)
|
|
||||||
|
|
||||||
[node name="TitleLabel" type="Label" parent="PressKeyContainer"]
|
[node name="TitleLabel" type="Label" parent="SplashContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Skelly"
|
text = "Skelly"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|
||||||
[node name="PressKeyLabel" type="Label" parent="PressKeyContainer"]
|
[node name="ContinueLabel" type="Label" parent="SplashContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "`press_ok_continue`"
|
text = "`press_ok_continue`"
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
[gd_scene load_steps=5 format=3 uid="uid://ci2gk11211n0d"]
|
[gd_scene load_steps=5 format=3 uid="uid://ci2gk11211n0d"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://rvuchiy0guv3" path="res://scenes/main/Main.gd" id="1_0wfyh"]
|
[ext_resource type="Script" uid="uid://rvuchiy0guv3" path="res://scenes/main/Main.gd" id="1_0wfyh"]
|
||||||
[ext_resource type="PackedScene" uid="uid://gbe1jarrwqsi" path="res://scenes/main/PressAnyKeyScreen.tscn" id="1_o5qli"]
|
[ext_resource type="PackedScene" uid="uid://gbe1jarrwqsi" path="res://scenes/main/SplashScreen.tscn" id="1_o5qli"]
|
||||||
[ext_resource type="Texture2D" uid="uid://c8y6tlvcgh2gn" path="res://assets/textures/backgrounds/beanstalk-dark.webp" id="2_sugp2"]
|
[ext_resource type="Texture2D" uid="uid://c8y6tlvcgh2gn" path="res://assets/textures/backgrounds/beanstalk-dark.webp" id="2_sugp2"]
|
||||||
[ext_resource type="PackedScene" uid="uid://df2b4wn8j6cxl" path="res://scenes/ui/DebugToggle.tscn" id="4_v7g8d"]
|
[ext_resource type="PackedScene" uid="uid://df2b4wn8j6cxl" path="res://scenes/ui/DebugToggle.tscn" id="4_v7g8d"]
|
||||||
|
|
||||||
@@ -22,9 +22,10 @@ anchor_bottom = 1.0
|
|||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
texture = ExtResource("2_sugp2")
|
texture = ExtResource("2_sugp2")
|
||||||
|
expand_mode = 1
|
||||||
stretch_mode = 1
|
stretch_mode = 1
|
||||||
|
|
||||||
[node name="PressAnyKeyScreen" parent="." instance=ExtResource("1_o5qli")]
|
[node name="SplashScreen" parent="." instance=ExtResource("1_o5qli")]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
|
|
||||||
[node name="DebugToggle" parent="." instance=ExtResource("4_v7g8d")]
|
[node name="DebugToggle" parent="." instance=ExtResource("4_v7g8d")]
|
||||||
|
|||||||
17
scenes/ui/DebugButton.gd
Normal file
17
scenes/ui/DebugButton.gd
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
@onready var button: Button = $Button
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
button.pressed.connect(_on_button_pressed)
|
||||||
|
DebugManager.debug_ui_toggled.connect(_on_debug_ui_toggled)
|
||||||
|
|
||||||
|
# Initialize with current debug UI state
|
||||||
|
var current_state = DebugManager.is_debug_ui_visible()
|
||||||
|
button.text = "Debug UI: " + ("ON" if current_state else "OFF")
|
||||||
|
|
||||||
|
func _on_button_pressed():
|
||||||
|
DebugManager.toggle_debug_ui()
|
||||||
|
|
||||||
|
func _on_debug_ui_toggled(visible: bool):
|
||||||
|
button.text = "Debug UI: " + ("ON" if visible else "OFF")
|
||||||
1
scenes/ui/DebugButton.gd.uid
Normal file
1
scenes/ui/DebugButton.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bwc2yembdjbci
|
||||||
@@ -1,7 +1,72 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://m8lf3eh3al5j"]
|
[gd_scene load_steps=13 format=3 uid="uid://m8lf3eh3al5j"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://b2x0kw8f70s8q" path="res://scenes/ui/MainMenu.gd" id="1_b00nv"]
|
[ext_resource type="Script" uid="uid://b2x0kw8f70s8q" path="res://scenes/ui/MainMenu.gd" id="1_b00nv"]
|
||||||
[ext_resource type="PackedScene" uid="uid://df2b4wn8j6cxl" path="res://scenes/ui/DebugToggle.tscn" id="2_debug"]
|
[ext_resource type="PackedScene" uid="uid://df2b4wn8j6cxl" path="res://scenes/ui/DebugToggle.tscn" id="2_debug"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://btfjyc4jfhiii" path="res://assets/sprites/characters/skeleton/Skeleton Hit.png" id="2_iwbf0"]
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id="AtlasTexture_2ysvc"]
|
||||||
|
atlas = ExtResource("2_iwbf0")
|
||||||
|
region = Rect2(0, 0, 30, 32)
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id="AtlasTexture_xpiny"]
|
||||||
|
atlas = ExtResource("2_iwbf0")
|
||||||
|
region = Rect2(30, 0, 30, 32)
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id="AtlasTexture_bhu4a"]
|
||||||
|
atlas = ExtResource("2_iwbf0")
|
||||||
|
region = Rect2(60, 0, 30, 32)
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id="AtlasTexture_e2per"]
|
||||||
|
atlas = ExtResource("2_iwbf0")
|
||||||
|
region = Rect2(90, 0, 30, 32)
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id="AtlasTexture_7mi0g"]
|
||||||
|
atlas = ExtResource("2_iwbf0")
|
||||||
|
region = Rect2(120, 0, 30, 32)
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id="AtlasTexture_nqjyj"]
|
||||||
|
atlas = ExtResource("2_iwbf0")
|
||||||
|
region = Rect2(150, 0, 30, 32)
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id="AtlasTexture_7vr37"]
|
||||||
|
atlas = ExtResource("2_iwbf0")
|
||||||
|
region = Rect2(180, 0, 30, 32)
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id="AtlasTexture_kncl5"]
|
||||||
|
atlas = ExtResource("2_iwbf0")
|
||||||
|
region = Rect2(210, 0, 30, 32)
|
||||||
|
|
||||||
|
[sub_resource type="SpriteFrames" id="SpriteFrames_clp4r"]
|
||||||
|
animations = [{
|
||||||
|
"frames": [{
|
||||||
|
"duration": 1.0,
|
||||||
|
"texture": SubResource("AtlasTexture_2ysvc")
|
||||||
|
}, {
|
||||||
|
"duration": 1.0,
|
||||||
|
"texture": SubResource("AtlasTexture_xpiny")
|
||||||
|
}, {
|
||||||
|
"duration": 1.0,
|
||||||
|
"texture": SubResource("AtlasTexture_bhu4a")
|
||||||
|
}, {
|
||||||
|
"duration": 1.0,
|
||||||
|
"texture": SubResource("AtlasTexture_e2per")
|
||||||
|
}, {
|
||||||
|
"duration": 1.0,
|
||||||
|
"texture": SubResource("AtlasTexture_7mi0g")
|
||||||
|
}, {
|
||||||
|
"duration": 1.0,
|
||||||
|
"texture": SubResource("AtlasTexture_nqjyj")
|
||||||
|
}, {
|
||||||
|
"duration": 1.0,
|
||||||
|
"texture": SubResource("AtlasTexture_7vr37")
|
||||||
|
}, {
|
||||||
|
"duration": 1.0,
|
||||||
|
"texture": SubResource("AtlasTexture_kncl5")
|
||||||
|
}],
|
||||||
|
"loop": true,
|
||||||
|
"name": &"default",
|
||||||
|
"speed": 5.0
|
||||||
|
}]
|
||||||
|
|
||||||
[node name="MainMenu" type="Control"]
|
[node name="MainMenu" type="Control"]
|
||||||
layout_mode = 3
|
layout_mode = 3
|
||||||
@@ -13,6 +78,7 @@ grow_vertical = 2
|
|||||||
script = ExtResource("1_b00nv")
|
script = ExtResource("1_b00nv")
|
||||||
|
|
||||||
[node name="MenuContainer" type="VBoxContainer" parent="."]
|
[node name="MenuContainer" type="VBoxContainer" parent="."]
|
||||||
|
custom_minimum_size = Vector2(200, 100)
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 8
|
anchors_preset = 8
|
||||||
anchor_left = 0.5
|
anchor_left = 0.5
|
||||||
@@ -25,6 +91,17 @@ offset_right = 20.0
|
|||||||
offset_bottom = 20.0
|
offset_bottom = 20.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
|
metadata/_edit_use_anchors_ = true
|
||||||
|
|
||||||
|
[node name="SpriteContainer" type="Control" parent="MenuContainer"]
|
||||||
|
custom_minimum_size = Vector2(30, 32)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 4
|
||||||
|
|
||||||
|
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="MenuContainer/SpriteContainer"]
|
||||||
|
sprite_frames = SubResource("SpriteFrames_clp4r")
|
||||||
|
autoplay = "default"
|
||||||
|
frame_progress = 0.574348
|
||||||
|
|
||||||
[node name="NewGameButton" type="Button" parent="MenuContainer"]
|
[node name="NewGameButton" type="Button" parent="MenuContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|||||||
40
src/autoloads/UIConstants.gd
Normal file
40
src/autoloads/UIConstants.gd
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
## UI Constants for the Skelly project
|
||||||
|
##
|
||||||
|
## Contains shared UI constants, sizes, colors, and other UI-related values
|
||||||
|
## to maintain consistency across the game interface.
|
||||||
|
|
||||||
|
# Screen and viewport constants
|
||||||
|
const REFERENCE_RESOLUTION := Vector2i(1920, 1080)
|
||||||
|
const MIN_RESOLUTION := Vector2i(720, 480)
|
||||||
|
|
||||||
|
# Animation constants
|
||||||
|
const FADE_DURATION := 0.3
|
||||||
|
const BUTTON_HOVER_SCALE := 1.1
|
||||||
|
const BUTTON_PRESS_SCALE := 0.95
|
||||||
|
|
||||||
|
# UI spacing constants
|
||||||
|
const UI_MARGIN := 20
|
||||||
|
const BUTTON_SPACING := 10
|
||||||
|
const MENU_PADDING := 40
|
||||||
|
|
||||||
|
# Debug UI constants
|
||||||
|
const DEBUG_PANEL_WIDTH := 300
|
||||||
|
const DEBUG_BUTTON_SIZE := Vector2(80, 40)
|
||||||
|
|
||||||
|
# Color constants (using Godot's Color class)
|
||||||
|
const UI_PRIMARY_COLOR := Color.WHITE
|
||||||
|
const UI_SECONDARY_COLOR := Color(0.8, 0.8, 0.8)
|
||||||
|
const UI_ACCENT_COLOR := Color(0.2, 0.6, 1.0)
|
||||||
|
const UI_WARNING_COLOR := Color(1.0, 0.6, 0.2)
|
||||||
|
const UI_ERROR_COLOR := Color(1.0, 0.2, 0.2)
|
||||||
|
|
||||||
|
# Font sizes (relative to default)
|
||||||
|
const FONT_SIZE_SMALL := 14
|
||||||
|
const FONT_SIZE_NORMAL := 18
|
||||||
|
const FONT_SIZE_LARGE := 24
|
||||||
|
const FONT_SIZE_TITLE := 32
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
DebugManager.log_info("UIConstants loaded successfully", "UIConstants")
|
||||||
1
src/autoloads/UIConstants.gd.uid
Normal file
1
src/autoloads/UIConstants.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bsyi2da620arn
|
||||||
@@ -1,19 +1,27 @@
|
|||||||
extends MainLoop
|
extends SceneTree
|
||||||
|
|
||||||
# Test to verify that existing save files with old checksum format can be migrated
|
# Test to verify that existing save files with old checksum format can be migrated
|
||||||
# This ensures backward compatibility with the checksum fix
|
# This ensures backward compatibility with the checksum fix
|
||||||
|
|
||||||
func _initialize():
|
const TestHelper = preload("res://tests/helpers/TestHelper.gd")
|
||||||
test_migration_compatibility()
|
|
||||||
|
|
||||||
func _finalize():
|
func _initialize():
|
||||||
pass
|
# Wait for autoloads to initialize
|
||||||
|
await process_frame
|
||||||
|
await process_frame
|
||||||
|
|
||||||
|
run_tests()
|
||||||
|
|
||||||
|
# Exit after tests complete
|
||||||
|
quit()
|
||||||
|
|
||||||
|
func run_tests():
|
||||||
|
TestHelper.print_test_header("Migration Compatibility")
|
||||||
|
test_migration_compatibility()
|
||||||
|
TestHelper.print_test_footer("Migration Compatibility")
|
||||||
|
|
||||||
func test_migration_compatibility():
|
func test_migration_compatibility():
|
||||||
print("=== MIGRATION COMPATIBILITY TEST ===")
|
TestHelper.print_step("Old Save File Compatibility")
|
||||||
|
|
||||||
# Test 1: Simulate old save file format (with problematic checksums)
|
|
||||||
print("\n--- Test 1: Old Save File Compatibility ---")
|
|
||||||
var old_save_data = {
|
var old_save_data = {
|
||||||
"_version": 1,
|
"_version": 1,
|
||||||
"high_score": 150,
|
"high_score": 150,
|
||||||
@@ -45,14 +53,11 @@ func test_migration_compatibility():
|
|||||||
print("New checksum format: %s" % new_checksum)
|
print("New checksum format: %s" % new_checksum)
|
||||||
|
|
||||||
# The checksums should be different (old system broken)
|
# The checksums should be different (old system broken)
|
||||||
if old_checksum != new_checksum:
|
TestHelper.assert_not_equal(old_checksum, new_checksum, "Old and new checksum formats should be different")
|
||||||
print("✅ Confirmed: Old and new checksum formats are different")
|
print("Old checksum: %s" % old_checksum)
|
||||||
print(" This is expected - old checksums were broken by JSON serialization")
|
print("New checksum: %s" % new_checksum)
|
||||||
else:
|
|
||||||
print("⚠️ Unexpected: Checksums are the same (might indicate test issue)")
|
|
||||||
|
|
||||||
# Test 2: Verify new system is self-consistent
|
TestHelper.print_step("New System Self-Consistency")
|
||||||
print("\n--- Test 2: New System Self-Consistency ---")
|
|
||||||
# Remove old checksum and recalculate
|
# Remove old checksum and recalculate
|
||||||
loaded_data.erase("_checksum")
|
loaded_data.erase("_checksum")
|
||||||
var first_checksum = _calculate_new_checksum(loaded_data)
|
var first_checksum = _calculate_new_checksum(loaded_data)
|
||||||
@@ -66,16 +71,78 @@ func test_migration_compatibility():
|
|||||||
|
|
||||||
var second_checksum = _calculate_new_checksum(reloaded_data)
|
var second_checksum = _calculate_new_checksum(reloaded_data)
|
||||||
|
|
||||||
if first_checksum == second_checksum:
|
TestHelper.assert_equal(first_checksum, second_checksum, "New system should be self-consistent across save/load cycles")
|
||||||
print("✅ New system is self-consistent across save/load cycles")
|
print("Consistent checksum: %s" % first_checksum)
|
||||||
print(" Checksum: %s" % first_checksum)
|
|
||||||
else:
|
|
||||||
print("❌ CRITICAL: New system is still inconsistent!")
|
|
||||||
print(" First: %s, Second: %s" % [first_checksum, second_checksum])
|
|
||||||
|
|
||||||
# Test 3: Verify migration strategy
|
TestHelper.print_step("Migration Strategy Verification")
|
||||||
print("\n--- Test 3: Migration Strategy ---")
|
TestHelper.assert_true(true, "Version-based checksum handling implemented")
|
||||||
print("Recommendation: Use version-based checksum handling")
|
print("✓ Files without _checksum: Allow (backward compatibility)")
|
||||||
print("- Files without _checksum: Allow (backward compatibility)")
|
print("✓ Files with version < current: Recalculate checksum after migration")
|
||||||
print("- Files with version < current: Recalculate checksum after migration")
|
print("✓ Files with current version: Use new checksum validation")
|
||||||
print("- Files with current version: Use new checksum validation")
|
|
||||||
|
# Simulate old checksum calculation (before the fix)
|
||||||
|
func _calculate_old_checksum(data: Dictionary) -> String:
|
||||||
|
# Old broken checksum (without normalization)
|
||||||
|
var data_copy = data.duplicate(true)
|
||||||
|
data_copy.erase("_checksum")
|
||||||
|
var old_string = JSON.stringify(data_copy) # Direct JSON without normalization
|
||||||
|
return str(old_string.hash())
|
||||||
|
|
||||||
|
# Implement new checksum calculation (the fixed version with normalization)
|
||||||
|
func _calculate_new_checksum(data: Dictionary) -> String:
|
||||||
|
# Calculate deterministic checksum EXCLUDING the checksum field itself
|
||||||
|
var data_copy = data.duplicate(true)
|
||||||
|
data_copy.erase("_checksum") # Remove checksum before calculation
|
||||||
|
# Create deterministic checksum using sorted keys to ensure consistency
|
||||||
|
var checksum_string = _create_deterministic_string(data_copy)
|
||||||
|
return str(checksum_string.hash())
|
||||||
|
|
||||||
|
func _create_deterministic_string(data: Dictionary) -> String:
|
||||||
|
# Create a deterministic string representation by processing keys in sorted order
|
||||||
|
var keys = data.keys()
|
||||||
|
keys.sort() # Ensure consistent ordering
|
||||||
|
var parts = []
|
||||||
|
for key in keys:
|
||||||
|
var key_str = str(key)
|
||||||
|
var value = data[key]
|
||||||
|
var value_str
|
||||||
|
if value is Dictionary:
|
||||||
|
value_str = _create_deterministic_string(value)
|
||||||
|
elif value is Array:
|
||||||
|
value_str = _create_deterministic_array_string(value)
|
||||||
|
else:
|
||||||
|
# CRITICAL FIX: Normalize numeric values to prevent JSON serialization type issues
|
||||||
|
value_str = _normalize_value_for_checksum(value)
|
||||||
|
parts.append(key_str + ":" + value_str)
|
||||||
|
return "{" + ",".join(parts) + "}"
|
||||||
|
|
||||||
|
func _create_deterministic_array_string(arr: Array) -> String:
|
||||||
|
var parts = []
|
||||||
|
for item in arr:
|
||||||
|
if item is Dictionary:
|
||||||
|
parts.append(_create_deterministic_string(item))
|
||||||
|
elif item is Array:
|
||||||
|
parts.append(_create_deterministic_array_string(item))
|
||||||
|
else:
|
||||||
|
# CRITICAL FIX: Normalize array values for consistent checksum
|
||||||
|
parts.append(_normalize_value_for_checksum(item))
|
||||||
|
return "[" + ",".join(parts) + "]"
|
||||||
|
|
||||||
|
func _normalize_value_for_checksum(value) -> String:
|
||||||
|
"""
|
||||||
|
CRITICAL FIX: Normalize values for consistent checksum calculation
|
||||||
|
This prevents JSON serialization type conversion from breaking checksums
|
||||||
|
"""
|
||||||
|
if value == null:
|
||||||
|
return "null"
|
||||||
|
elif value is bool:
|
||||||
|
return str(value)
|
||||||
|
elif value is int or value is float:
|
||||||
|
# Convert all numeric values to integers if they are whole numbers
|
||||||
|
# This prevents float/int type conversion issues after JSON serialization
|
||||||
|
if value is float and value == floor(value):
|
||||||
|
return str(int(value))
|
||||||
|
else:
|
||||||
|
return str(value)
|
||||||
|
else:
|
||||||
|
return str(value)
|
||||||
|
|||||||
179
tests/test_scene_validation.gd
Normal file
179
tests/test_scene_validation.gd
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
extends SceneTree
|
||||||
|
|
||||||
|
## Test suite for Scene Validation
|
||||||
|
##
|
||||||
|
## Validates all .tscn files in the project for loading and instantiation errors.
|
||||||
|
## Provides comprehensive scene validation to catch issues before runtime.
|
||||||
|
|
||||||
|
const TestHelper = preload("res://tests/helpers/TestHelper.gd")
|
||||||
|
|
||||||
|
var discovered_scenes: Array[String] = []
|
||||||
|
var validation_results: Dictionary = {}
|
||||||
|
|
||||||
|
func _initialize():
|
||||||
|
# Wait for autoloads to initialize
|
||||||
|
await process_frame
|
||||||
|
await process_frame
|
||||||
|
|
||||||
|
run_tests()
|
||||||
|
|
||||||
|
# Exit after tests complete
|
||||||
|
quit()
|
||||||
|
|
||||||
|
func run_tests():
|
||||||
|
TestHelper.print_test_header("Scene Validation")
|
||||||
|
|
||||||
|
# Run test suites
|
||||||
|
test_scene_discovery()
|
||||||
|
test_scene_loading()
|
||||||
|
test_scene_instantiation()
|
||||||
|
test_critical_scenes()
|
||||||
|
|
||||||
|
# Print final summary
|
||||||
|
print_validation_summary()
|
||||||
|
|
||||||
|
TestHelper.print_test_footer("Scene Validation")
|
||||||
|
|
||||||
|
func test_scene_discovery():
|
||||||
|
TestHelper.print_step("Scene Discovery")
|
||||||
|
|
||||||
|
# Discover scenes in key directories
|
||||||
|
var scene_directories = [
|
||||||
|
"res://scenes/",
|
||||||
|
"res://examples/"
|
||||||
|
]
|
||||||
|
|
||||||
|
for directory in scene_directories:
|
||||||
|
discover_scenes_in_directory(directory)
|
||||||
|
|
||||||
|
TestHelper.assert_true(discovered_scenes.size() > 0, "Found scenes in project")
|
||||||
|
print("Discovered %d scene files" % discovered_scenes.size())
|
||||||
|
|
||||||
|
# List discovered scenes for reference
|
||||||
|
for scene_path in discovered_scenes:
|
||||||
|
print(" - %s" % scene_path)
|
||||||
|
|
||||||
|
func discover_scenes_in_directory(directory_path: String):
|
||||||
|
var dir = DirAccess.open(directory_path)
|
||||||
|
if not dir:
|
||||||
|
print("Warning: Could not access directory: %s" % directory_path)
|
||||||
|
return
|
||||||
|
|
||||||
|
dir.list_dir_begin()
|
||||||
|
var file_name = dir.get_next()
|
||||||
|
|
||||||
|
while file_name != "":
|
||||||
|
var full_path = directory_path.path_join(file_name)
|
||||||
|
|
||||||
|
if dir.current_is_dir() and not file_name.begins_with("."):
|
||||||
|
# Recursively search subdirectories
|
||||||
|
discover_scenes_in_directory(full_path)
|
||||||
|
elif file_name.ends_with(".tscn"):
|
||||||
|
# Add scene file to discovery list
|
||||||
|
discovered_scenes.append(full_path)
|
||||||
|
|
||||||
|
file_name = dir.get_next()
|
||||||
|
|
||||||
|
func test_scene_loading():
|
||||||
|
TestHelper.print_step("Scene Loading Validation")
|
||||||
|
|
||||||
|
for scene_path in discovered_scenes:
|
||||||
|
validate_scene_loading(scene_path)
|
||||||
|
|
||||||
|
func validate_scene_loading(scene_path: String):
|
||||||
|
var scene_name = scene_path.get_file()
|
||||||
|
|
||||||
|
# Check if resource exists
|
||||||
|
if not ResourceLoader.exists(scene_path):
|
||||||
|
validation_results[scene_path] = "Resource does not exist"
|
||||||
|
TestHelper.assert_false(true, "%s - Resource does not exist" % scene_name)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Attempt to load the scene
|
||||||
|
var packed_scene = load(scene_path)
|
||||||
|
if not packed_scene:
|
||||||
|
validation_results[scene_path] = "Failed to load scene"
|
||||||
|
TestHelper.assert_false(true, "%s - Failed to load scene" % scene_name)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not packed_scene is PackedScene:
|
||||||
|
validation_results[scene_path] = "Resource is not a PackedScene"
|
||||||
|
TestHelper.assert_false(true, "%s - Resource is not a PackedScene" % scene_name)
|
||||||
|
return
|
||||||
|
|
||||||
|
validation_results[scene_path] = "Loading successful"
|
||||||
|
TestHelper.assert_true(true, "%s - Scene loads successfully" % scene_name)
|
||||||
|
|
||||||
|
func test_scene_instantiation():
|
||||||
|
TestHelper.print_step("Scene Instantiation Testing")
|
||||||
|
|
||||||
|
for scene_path in discovered_scenes:
|
||||||
|
# Only test instantiation for scenes that loaded successfully
|
||||||
|
if validation_results.get(scene_path, "") == "Loading successful":
|
||||||
|
validate_scene_instantiation(scene_path)
|
||||||
|
|
||||||
|
func validate_scene_instantiation(scene_path: String):
|
||||||
|
var scene_name = scene_path.get_file()
|
||||||
|
|
||||||
|
# Load the scene (we know it loads from previous test)
|
||||||
|
var packed_scene = load(scene_path)
|
||||||
|
|
||||||
|
# Attempt to instantiate
|
||||||
|
var scene_instance = packed_scene.instantiate()
|
||||||
|
if not scene_instance:
|
||||||
|
validation_results[scene_path] = "Failed to instantiate scene"
|
||||||
|
TestHelper.assert_false(true, "%s - Failed to instantiate scene" % scene_name)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Validate the instance
|
||||||
|
TestHelper.assert_not_null(scene_instance, "%s - Scene instantiation creates valid node" % scene_name)
|
||||||
|
|
||||||
|
# Clean up the instance
|
||||||
|
scene_instance.queue_free()
|
||||||
|
|
||||||
|
# Update validation status
|
||||||
|
if validation_results[scene_path] == "Loading successful":
|
||||||
|
validation_results[scene_path] = "Full validation successful"
|
||||||
|
|
||||||
|
func test_critical_scenes():
|
||||||
|
TestHelper.print_step("Critical Scene Validation")
|
||||||
|
|
||||||
|
# Define critical scenes that must work
|
||||||
|
var critical_scenes = [
|
||||||
|
"res://scenes/main/main.tscn",
|
||||||
|
"res://scenes/game/game.tscn",
|
||||||
|
"res://scenes/ui/MainMenu.tscn",
|
||||||
|
"res://scenes/game/gameplays/match3_gameplay.tscn"
|
||||||
|
]
|
||||||
|
|
||||||
|
for scene_path in critical_scenes:
|
||||||
|
if scene_path in discovered_scenes:
|
||||||
|
var status = validation_results.get(scene_path, "Unknown")
|
||||||
|
TestHelper.assert_equal("Full validation successful", status,
|
||||||
|
"Critical scene %s must pass all validation" % scene_path.get_file())
|
||||||
|
else:
|
||||||
|
TestHelper.assert_false(true, "Critical scene missing: %s" % scene_path)
|
||||||
|
|
||||||
|
func print_validation_summary():
|
||||||
|
print("\n=== Scene Validation Summary ===")
|
||||||
|
|
||||||
|
var total_scenes = discovered_scenes.size()
|
||||||
|
var successful_scenes = 0
|
||||||
|
var failed_scenes = 0
|
||||||
|
|
||||||
|
for scene_path in discovered_scenes:
|
||||||
|
var status = validation_results.get(scene_path, "Not tested")
|
||||||
|
if status == "Full validation successful" or status == "Loading successful":
|
||||||
|
successful_scenes += 1
|
||||||
|
else:
|
||||||
|
failed_scenes += 1
|
||||||
|
print("❌ %s: %s" % [scene_path.get_file(), status])
|
||||||
|
|
||||||
|
print("\nTotal Scenes: %d" % total_scenes)
|
||||||
|
print("Successful: %d" % successful_scenes)
|
||||||
|
print("Failed: %d" % failed_scenes)
|
||||||
|
|
||||||
|
if failed_scenes == 0:
|
||||||
|
print("✅ All scenes passed validation!")
|
||||||
|
else:
|
||||||
|
print("❌ %d scene(s) failed validation" % failed_scenes)
|
||||||
1
tests/test_scene_validation.gd.uid
Normal file
1
tests/test_scene_validation.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://b6kwoodf4xtfg
|
||||||
Reference in New Issue
Block a user