feat: Implement the main game scene, initializing core managers, a new message bar system, and a pre-game countdown.

This commit is contained in:
2026-03-03 05:01:59 +08:00
parent e6dceaf173
commit 09d08093e2
4 changed files with 242 additions and 6 deletions
+20 -4
View File
@@ -1575,12 +1575,12 @@ func request_randomize_item(grid_position: Vector2i):
func sync_grid_item(x: int, y: int, z: int, item: int):
var enhanced_gridmap = $EnhancedGridMap
if enhanced_gridmap:
# WALL-SAFETY CHECK: Block tiles (7-20) from being placed on walls (4)
# WALL-SAFETY CHECK: Block tiles (7-20) from being placed on walls (4) or void (-1)
if y == 1 and item >= 7 and item <= 20:
var f0 = enhanced_gridmap.get_cell_item(Vector3i(x, 0, z))
if f0 == 4:
if f0 == 4 or f0 == -1:
# Log and block illegal placement
print("[Main] Blocked illegal tile (%d) placement on wall at (%d, %d)" % [item, x, z])
print("[Main] Blocked illegal tile (%d) placement on wall/void at (%d, %d)" % [item, x, z])
return
enhanced_gridmap.set_cell_item(Vector3i(x, y, z), item)
@@ -1909,7 +1909,7 @@ func _show_game_over_panel():
var rank_colors = [
Color(1.0, 0.84, 0.0), # Gold
Color(0.75, 0.75, 0.75), # Silver
Color(0.8, 0.5, 0.2) # Bronze
Color(0.8, 0.5, 0.2) # Bronze
]
var rank_emojis = ["🥇", "🥈", "🥉"]
@@ -2217,6 +2217,22 @@ func _on_resume_pressed():
pause_menu.visible = false
get_tree().paused = false
func _on_how_to_play_pressed():
var pause_menu = get_node_or_null("PauseMenu")
var help_panel = get_node_or_null("HowToPlayPanel")
if pause_menu:
pause_menu.visible = false
if help_panel:
help_panel.visible = true
func _on_how_to_play_back_pressed():
var pause_menu = get_node_or_null("PauseMenu")
var help_panel = get_node_or_null("HowToPlayPanel")
if help_panel:
help_panel.visible = false
if pause_menu:
pause_menu.visible = true
func _on_settings_pressed():
var pause_menu = get_node_or_null("PauseMenu")
var settings_panel = get_node_or_null("SettingsPanel")
+188
View File
@@ -9923,6 +9923,11 @@ custom_minimum_size = Vector2(200, 45)
layout_mode = 2
text = "Resume"
[node name="HowToPlayBtn" type="Button" parent="PauseMenu/Panel/VBox" unique_id=987654321]
custom_minimum_size = Vector2(200, 45)
layout_mode = 2
text = "How to Play"
[node name="SettingsBtn" type="Button" parent="PauseMenu/Panel/VBox" unique_id=215865401]
custom_minimum_size = Vector2(200, 45)
layout_mode = 2
@@ -9933,6 +9938,187 @@ custom_minimum_size = Vector2(200, 45)
layout_mode = 2
text = "Quit Match"
[node name="HowToPlayPanel" type="CanvasLayer" parent="." unique_id=123456789]
process_mode = 3
layer = 11
visible = false
[node name="Background" type="ColorRect" parent="HowToPlayPanel" unique_id=123456790]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0, 0, 0, 0.8)
[node name="Panel" type="PanelContainer" parent="HowToPlayPanel" unique_id=123456791]
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -300.0
offset_top = -250.0
offset_right = 300.0
offset_bottom = 250.0
grow_horizontal = 2
grow_vertical = 2
[node name="VBox" type="VBoxContainer" parent="HowToPlayPanel/Panel" unique_id=123456792]
layout_mode = 2
theme_override_constants/separation = 12
alignment = 1
[node name="Title" type="Label" parent="HowToPlayPanel/Panel/VBox" unique_id=123456793]
layout_mode = 2
theme_override_font_sizes/font_size = 22
text = "How to Play"
horizontal_alignment = 1
[node name="TabContainer" type="TabContainer" parent="HowToPlayPanel/Panel/VBox" unique_id=123456794]
layout_mode = 2
size_flags_vertical = 3
[node name="Free Mode" type="MarginContainer" parent="HowToPlayPanel/Panel/VBox/TabContainer" unique_id=123456795]
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="RichTextLabel" type="RichTextLabel" parent="HowToPlayPanel/Panel/VBox/TabContainer/Free Mode" unique_id=123456796]
layout_mode = 2
bbcode_enabled = true
text = "[b]Free Mode[/b]
- Move around the grid and attack Tektons to spawn tiles.
- Grab tiles and use the [b]ARRANGE[/b] action to slot them into your player board.
- Match a 3x3 pattern shown in your [b]GOALS[/b] to score points and earn powerups.
- The player with the highest score when the global match timer ends wins!"
[node name="Stop n Go" type="MarginContainer" parent="HowToPlayPanel/Panel/VBox/TabContainer" unique_id=123456797]
visible = false
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="RichTextLabel" type="RichTextLabel" parent="HowToPlayPanel/Panel/VBox/TabContainer/Stop n Go" unique_id=123456798]
layout_mode = 2
bbcode_enabled = true
text = "[b]Stop n Go[/b]
- The classic red light, green light experience.
- Move forward when the phase is [color=green][b]GO[/b][/color] (Green).
- Stop completely when the phase is [color=red][b]STOP[/b][/color] (Red). Moving during a red phase will reset you to the start!
- Your objective is to reach the mission tiles at the far end of the arena and safely carry them back to your starting zone.
- The first player to complete 3 missions wins."
[node name="Tekton Doors" type="MarginContainer" parent="HowToPlayPanel/Panel/VBox/TabContainer" unique_id=123456799]
visible = false
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="RichTextLabel" type="RichTextLabel" parent="HowToPlayPanel/Panel/VBox/TabContainer/Tekton Doors" unique_id=123456800]
layout_mode = 2
bbcode_enabled = true
text = "[b]Tekton Doors[/b]
- Navigate a sprawling arena connected by color-coded portal doors.
- Grab tiles and match goal patterns to earn mission completions.
- Use doors to quickly teleport across rooms, but watch out for closures and traps.
- The first player to complete 8 missions wins."
[node name="Controls" type="MarginContainer" parent="HowToPlayPanel/Panel/VBox/TabContainer" unique_id=123456805]
visible = false
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="RichTextLabel" type="RichTextLabel" parent="HowToPlayPanel/Panel/VBox/TabContainer/Controls" unique_id=123456806]
layout_mode = 2
bbcode_enabled = true
text = "[b]Basic Controls[/b]
• [b]Movement:[/b] W/A/S/D, Arrow Keys, or Virtual Joystick.
• [b]Interact:[/b] Click or tap on game elements.
• [b]ATTACK:[/b] Strike an adjacent Tekton to make it drop items.
• [b]GRAB:[/b] Pick up a nearby tile.
• [b]ARRANGE:[/b] Insert a carried tile into your 3x3 Player Board.
• [b]THROW:[/b] Toss a carried item away.
• [b]KNOCK:[/b] Stun a Tekton temporarily."
[node name="The Grid" type="MarginContainer" parent="HowToPlayPanel/Panel/VBox/TabContainer" unique_id=123456807]
visible = false
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="RichTextLabel" type="RichTextLabel" parent="HowToPlayPanel/Panel/VBox/TabContainer/The Grid" unique_id=123456808]
layout_mode = 2
bbcode_enabled = true
text = "[b]The Grid & Tiles[/b]
• The arena is built on a grid. You interact with objects positioned on these grid coordinates.
• [b]Tiles:[/b] Core items shaped like Hearts, Diamonds, Stars, and Coins.
• [b]Player Board:[/b] A 3x3 grid assigned to you.
• [b]Goals:[/b] To score points or progress, you must pick up Tiles and ARRANGE them on your Player Board to match the 3x3 pattern shown in your Goals Window. Matching grants points or mission progression!"
[node name="Tektons" type="MarginContainer" parent="HowToPlayPanel/Panel/VBox/TabContainer" unique_id=123456809]
visible = false
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="RichTextLabel" type="RichTextLabel" parent="HowToPlayPanel/Panel/VBox/TabContainer/Tektons" unique_id=123456810]
layout_mode = 2
bbcode_enabled = true
text = "[b]Tektons[/b]
• [b]Dynamic Tektons:[/b] Roaming metallic entities. [color=orange]ATTACK[/color] them to force them to drop a valuable Tile.
• [b]Static Tektons:[/b] Stationary sentry turrets that occupy a large 3x3 space. They periodically throw tiles and obstacles around themselves. Stay alert when navigating near them!"
[node name="Skills" type="MarginContainer" parent="HowToPlayPanel/Panel/VBox/TabContainer" unique_id=123456811]
visible = false
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="RichTextLabel" type="RichTextLabel" parent="HowToPlayPanel/Panel/VBox/TabContainer/Skills" unique_id=123456812]
layout_mode = 2
bbcode_enabled = true
text = "[b]Skills & Power-ups[/b]
Earn powerups by matching Goal tiles (in Free Mode and Tekton Doors) or finding them in the arena.
• [color=yellow][b]Speed Boost:[/b][/color] Gain a temporary burst of movement speed.
• [color=gray][b]Wall Build:[/b][/color] Place a temporary wall to block enemies or safely trap other players.
• [color=aqua][b]Freeze Area:[/b][/color] Create a frozen zone on the grid that freezes anyone who steps on it.
• [color=purple][b]Ghost Mode:[/b][/color] Become temporarily invisible and invincible, allowing you to phase past blockades and opponents safely.
[i]*Note: In Stop n Go, focus primarily on movement and avoiding the Red phase![/i]"
[node name="Spacer" type="Control" parent="HowToPlayPanel/Panel/VBox" unique_id=123456801]
custom_minimum_size = Vector2(0, 10)
layout_mode = 2
[node name="BackBtn" type="Button" parent="HowToPlayPanel/Panel/VBox" unique_id=123456802]
custom_minimum_size = Vector2(0, 40)
layout_mode = 2
text = "Back"
[node name="SettingsPanel" type="CanvasLayer" parent="." unique_id=268064562]
process_mode = 3
layer = 11
@@ -10027,8 +10213,10 @@ text = "Back"
[connection signal="pressed" from="Menu/Join" to="." method="_on_join_pressed"]
[connection signal="text_submitted" from="MessageInput" to="." method="_on_message_input_text_submitted"]
[connection signal="pressed" from="PauseMenu/Panel/VBox/ResumeBtn" to="." method="_on_resume_pressed"]
[connection signal="pressed" from="PauseMenu/Panel/VBox/HowToPlayBtn" to="." method="_on_how_to_play_pressed"]
[connection signal="pressed" from="PauseMenu/Panel/VBox/SettingsBtn" to="." method="_on_settings_pressed"]
[connection signal="pressed" from="PauseMenu/Panel/VBox/QuitBtn" to="." method="_on_quit_match_pressed"]
[connection signal="pressed" from="HowToPlayPanel/Panel/VBox/BackBtn" to="." method="_on_how_to_play_back_pressed"]
[connection signal="value_changed" from="SettingsPanel/Panel/VBox/ButtonSizeRow/ButtonSizeSlider" to="." method="_on_button_size_changed"]
[connection signal="value_changed" from="SettingsPanel/Panel/VBox/OpacityRow/OpacitySlider" to="." method="_on_opacity_changed"]
[connection signal="toggled" from="SettingsPanel/Panel/VBox/JoystickToggle" to="." method="_on_joystick_toggled"]
+5
View File
@@ -408,6 +408,11 @@ func _randomize_tiles_around_player(player: Node):
# Check if position is valid
if not enhanced_gridmap.is_position_valid(pos):
continue
# EXTRA CHECK: Do not spawn tiles on void (-1) or walls (4) on Floor 0
var floor_0_item = enhanced_gridmap.get_cell_item(Vector3i(pos.x, 0, pos.y))
if floor_0_item == -1 or floor_0_item == 4:
continue
# Check if there are tiles nearby or if empty
var current_item = enhanced_gridmap.get_cell_item(cell)
+29 -2
View File
@@ -11,11 +11,15 @@ extends StaticBody3D
func _ready():
add_to_group("StaticTektonStands")
print("Static Stand Ready: ", name)
print("Static Stand Ready: ", name)
# Clear 3x3 local GridMap void for late joiners
call_deferred("_clear_local_gridmap_area")
if multiplayer.is_server():
# Only randomize if not already set (Main.gd sets it now)
if shape_index == -1:
shape_index = randi() % 4
shape_index = randi() % 4
_update_mesh_from_index()
else:
# Client side:
@@ -27,6 +31,29 @@ func _ready():
# But just in case, we can try to request it or use a default
pass
func _clear_local_gridmap_area():
var main = get_tree().get_root().get_node_or_null("Main")
if not main: return
var gridmap = main.get_node_or_null("EnhancedGridMap")
if not gridmap or not "cell_size" in gridmap: return
var grid_x = int(round((global_position.x - gridmap.cell_size.x / 2.0) / gridmap.cell_size.x))
var grid_z = int(round((global_position.z - gridmap.cell_size.z / 2.0) / gridmap.cell_size.z))
var floor_count = 3
if "floors" in gridmap: floor_count = gridmap.floors
for dx in range(-1, 2):
for dy in range(-1, 2):
for f in range(floor_count):
gridmap.set_cell_item(Vector3i(grid_x + dx, f, grid_z + dy), -1)
# Force pathfinding update if methods exist
if gridmap.has_method("update_grid_data"):
gridmap.update_grid_data()
if gridmap.has_method("update_astar_costs"):
gridmap.update_astar_costs()
func _update_mesh_from_index():
if not mesh_instance: return