feat: Add a loading screen, a lobby scene, and a new main game script, along with a custom font.
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,36 @@
|
||||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://dsqg0x5lnosou"
|
||||
path="res://.godot/imported/TektonDash2.ttf-1516aff8b98a916de0041ae3337aaaad.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/fonts/TektonDash2.ttf"
|
||||
dest_files=["res://.godot/imported/TektonDash2.ttf-1516aff8b98a916de0041ae3337aaaad.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
disable_embedded_bitmaps=true
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
modulate_color_glyphs=false
|
||||
hinting=1
|
||||
subpixel_positioning=4
|
||||
keep_rounding_remainders=true
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
||||
@@ -0,0 +1,149 @@
|
||||
[gd_scene load_steps=10 format=3 uid="uid://dtjppx0u68jw5"]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/ui/loading_screen.gd" id="1_u2jrd"]
|
||||
[ext_resource type="Texture2D" uid="uid://beimain5tk480" path="res://assets/graphics/loading_screen/bg_loading.png" id="2_gardl"]
|
||||
[ext_resource type="Shader" uid="uid://df6pi8e32lmco" path="res://assets/graphics/loading_screen/loading_screen.gdshader" id="3_vqw5v"]
|
||||
[ext_resource type="Texture2D" uid="uid://boenrxbgftva1" path="res://assets/graphics/loading_screen/pattern.png" id="4_u2jrd"]
|
||||
[ext_resource type="FontFile" path="res://assets/fonts/TektonDash2.ttf" id="5_ho08k"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_pc0ba"]
|
||||
shader = ExtResource("3_vqw5v")
|
||||
|
||||
[sub_resource type="FontVariation" id="FontVariation_8cml4"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_a8kcw"]
|
||||
bg_color = Color(0.529067, 0.529067, 0.529067, 1)
|
||||
border_width_left = 5
|
||||
border_width_top = 5
|
||||
border_width_right = 5
|
||||
border_width_bottom = 5
|
||||
border_color = Color(0, 0, 0, 1)
|
||||
corner_radius_top_left = 10
|
||||
corner_radius_top_right = 10
|
||||
corner_radius_bottom_right = 10
|
||||
corner_radius_bottom_left = 10
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8cml4"]
|
||||
bg_color = Color(1, 1, 1, 1)
|
||||
border_width_left = 5
|
||||
border_width_top = 5
|
||||
border_width_right = 5
|
||||
border_width_bottom = 5
|
||||
border_color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="loading_screen" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_u2jrd")
|
||||
|
||||
[node name="Bg" type="TextureRect" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("2_gardl")
|
||||
|
||||
[node name="BgSeamless" type="TextureRect" parent="."]
|
||||
self_modulate = Color(1, 1, 1, 0.3529412)
|
||||
texture_repeat = 2
|
||||
material = SubResource("ShaderMaterial_pc0ba")
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_top = -421.0
|
||||
offset_bottom = 421.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("4_u2jrd")
|
||||
stretch_mode = 1
|
||||
|
||||
[node name="Control" type="Control" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="scene_name" type="VBoxContainer" parent="Control"]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -100.0
|
||||
offset_top = -100.0
|
||||
offset_right = 100.0
|
||||
offset_bottom = -20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="label" type="Label" parent="Control/scene_name"]
|
||||
layout_mode = 2
|
||||
text = "Loading..."
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="name_of_load_scene" type="Label" parent="Control/scene_name"]
|
||||
layout_mode = 2
|
||||
text = "Map"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="tips" type="VBoxContainer" parent="Control"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -200.0
|
||||
offset_top = -150.0
|
||||
offset_right = 200.0
|
||||
offset_bottom = -100.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
alignment = 1
|
||||
|
||||
[node name="label" type="Label" parent="Control/tips"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 10
|
||||
theme_override_fonts/font = ExtResource("5_ho08k")
|
||||
theme_override_font_sizes/font_size = 24
|
||||
text = "Tips"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="tip_value" type="Label" parent="Control/tips"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 10
|
||||
theme_override_fonts/font = ExtResource("5_ho08k")
|
||||
theme_override_font_sizes/font_size = 30
|
||||
text = "Tip Value"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="progress_bar" type="ProgressBar" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 12
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 50.0
|
||||
offset_top = -50.0
|
||||
offset_right = -50.0
|
||||
offset_bottom = -20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = SubResource("FontVariation_8cml4")
|
||||
theme_override_styles/background = SubResource("StyleBoxFlat_a8kcw")
|
||||
theme_override_styles/fill = SubResource("StyleBoxFlat_8cml4")
|
||||
+10
-2
@@ -736,8 +736,16 @@ func _on_all_players_ready() -> void:
|
||||
|
||||
func _on_game_starting() -> void:
|
||||
connection_status.text = "Starting game..."
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
get_tree().change_scene_to_file("res://scenes/main.tscn")
|
||||
|
||||
# Instantiate and use the loading screen
|
||||
var loading_screen_scene = load("res://scenes/loading_screen/loading_screen.tscn")
|
||||
if loading_screen_scene:
|
||||
var loading_screen = loading_screen_scene.instantiate()
|
||||
get_tree().root.add_child(loading_screen)
|
||||
loading_screen.load_level("res://scenes/main.tscn")
|
||||
else:
|
||||
# Fallback if loading screen fails to load
|
||||
get_tree().change_scene_to_file("res://scenes/main.tscn")
|
||||
|
||||
func _on_match_duration_changed(duration_seconds: int) -> void:
|
||||
if not LobbyManager.is_host:
|
||||
|
||||
+2
-2
@@ -1136,9 +1136,9 @@ anchors_preset = 12
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 466.0
|
||||
offset_left = 462.0
|
||||
offset_top = -65.0
|
||||
offset_right = -459.0
|
||||
offset_right = -463.0
|
||||
offset_bottom = -16.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
|
||||
+39
-13
@@ -364,11 +364,19 @@ func _start_pre_game_countdown():
|
||||
|
||||
@rpc("call_local", "reliable")
|
||||
func sync_countdown(text: String):
|
||||
var label = get_node_or_null("CountdownLabel")
|
||||
# Use a CanvasLayer to ensure the countdown is on top of everything
|
||||
var countdown_layer = get_node_or_null("CountdownLayerUI")
|
||||
if not countdown_layer:
|
||||
countdown_layer = CanvasLayer.new()
|
||||
countdown_layer.name = "CountdownLayerUI"
|
||||
countdown_layer.layer = 100 # Very high priority
|
||||
add_child(countdown_layer)
|
||||
|
||||
var label = countdown_layer.get_node_or_null("CountdownLabel")
|
||||
if not label and text != "":
|
||||
label = Label.new()
|
||||
label.name = "CountdownLabel"
|
||||
add_child(label)
|
||||
countdown_layer.add_child(label)
|
||||
|
||||
# Center and Style
|
||||
label.anchors_preset = Control.PRESET_CENTER
|
||||
@@ -378,15 +386,20 @@ func sync_countdown(text: String):
|
||||
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
|
||||
label.add_theme_font_size_override("font_size", 120)
|
||||
label.add_theme_font_size_override("font_size", 140)
|
||||
label.add_theme_color_override("font_outline_color", Color.BLACK)
|
||||
label.add_theme_constant_override("outline_size", 12)
|
||||
label.add_theme_constant_override("outline_size", 20)
|
||||
label.add_theme_color_override("font_color", Color.YELLOW)
|
||||
|
||||
# Use Nougat font if available
|
||||
var nougat = load("res://assets/fonts/Nougat-ExtraBlack.ttf")
|
||||
if nougat:
|
||||
label.add_theme_font_override("font", nougat)
|
||||
|
||||
if label:
|
||||
label.text = text
|
||||
if text == "":
|
||||
label.queue_free()
|
||||
countdown_layer.queue_free()
|
||||
elif text == "GO!":
|
||||
label.add_theme_color_override("font_color", Color.GREEN)
|
||||
|
||||
@@ -687,8 +700,8 @@ func _start_game():
|
||||
wait_time += 0.2
|
||||
|
||||
# Allow socket/peer to stabilize before blasting RPCs
|
||||
# Snappier delay for LAN mode
|
||||
var delay = 0.5 if LobbyManager.is_lan_mode else 2.0
|
||||
# Snappier delay since we already waited for scene load
|
||||
var delay = 0.2 if LobbyManager.is_lan_mode else 0.5
|
||||
await get_tree().create_timer(delay).timeout
|
||||
|
||||
# NOW assign spawn positions for EVERYONE (Host, Client, Bots)
|
||||
@@ -2391,8 +2404,16 @@ func _on_quit_match_pressed():
|
||||
get_tree().paused = false # Ensure unpaused when returning to menu
|
||||
# Properly disconnect from Nakama and clear lobby state to prevent desync
|
||||
LobbyManager.leave_room()
|
||||
# Return to lobby or main menu
|
||||
get_tree().change_scene_to_file("res://scenes/lobby.tscn")
|
||||
|
||||
# Return to lobby via loading screen
|
||||
var loading_screen_scene = load("res://scenes/loading_screen/loading_screen.tscn")
|
||||
if loading_screen_scene:
|
||||
var loading_screen = loading_screen_scene.instantiate()
|
||||
get_tree().root.add_child(loading_screen)
|
||||
loading_screen.load_level("res://scenes/lobby.tscn")
|
||||
else:
|
||||
# Fallback
|
||||
get_tree().change_scene_to_file("res://scenes/lobby.tscn")
|
||||
|
||||
func _on_settings_back_pressed():
|
||||
var pause_menu = get_node_or_null("PauseMenu")
|
||||
@@ -2418,11 +2439,16 @@ func _on_joystick_toggled(enabled: bool):
|
||||
touch_controls._save_settings()
|
||||
|
||||
func can_rpc() -> bool:
|
||||
if not multiplayer.has_multiplayer_peer() or multiplayer.multiplayer_peer.get_connection_status() != MultiplayerPeer.CONNECTION_CONNECTED:
|
||||
return false
|
||||
if not multiplayer.has_multiplayer_peer(): return false
|
||||
if multiplayer.multiplayer_peer.get_connection_status() != MultiplayerPeer.CONNECTION_CONNECTED: return false
|
||||
|
||||
if LobbyManager.is_lan_mode:
|
||||
return true
|
||||
|
||||
var nakama = get_node_or_null("/root/NakamaManager")
|
||||
if nakama and nakama.has_method("is_connected_to_nakama") and not nakama.is_connected_to_nakama():
|
||||
return false
|
||||
if nakama and nakama.has_method("is_connected_to_nakama"):
|
||||
return nakama.is_connected_to_nakama()
|
||||
|
||||
return true
|
||||
|
||||
@rpc("authority", "call_local", "reliable")
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
extends Control
|
||||
|
||||
@export var tips: Array[String] = [
|
||||
"Use your cards wisely!",
|
||||
"Plan your moves ahead.",
|
||||
"Watch out for obstacles!",
|
||||
"Combine cards for powerful effects."
|
||||
]
|
||||
|
||||
var is_loading: bool = false
|
||||
var path: String = ""
|
||||
var progress: Array[float] = []
|
||||
|
||||
@onready var progress_bar = $progress_bar
|
||||
@onready var tip_value = $Control/tips/tip_value
|
||||
@onready var scene_name_label = $Control/scene_name/name_of_load_scene
|
||||
@onready var content_control = $Control
|
||||
|
||||
func _ready():
|
||||
set_process(false)
|
||||
|
||||
var load_start_time = 0.0
|
||||
var stuck_time = 0.0
|
||||
var last_progress = 0.0
|
||||
|
||||
func _process(delta):
|
||||
if is_loading:
|
||||
var status = ResourceLoader.load_threaded_get_status(path, progress)
|
||||
match status:
|
||||
ResourceLoader.THREAD_LOAD_IN_PROGRESS:
|
||||
if progress.size() > 0:
|
||||
var actual_progress = progress[0] * 100
|
||||
|
||||
# If progress is actually advancing, use it and reset stuck timer
|
||||
if actual_progress > last_progress:
|
||||
progress_bar.value = actual_progress
|
||||
last_progress = actual_progress
|
||||
stuck_time = 0.0
|
||||
else:
|
||||
# Progress is stuck, increment stuck timer
|
||||
stuck_time += delta
|
||||
|
||||
# If stuck for more than 0.5 seconds, start simulating progress
|
||||
if stuck_time > 0.5:
|
||||
# Calculate how much more progress needed
|
||||
var remaining_percent = 99.0 - progress_bar.value
|
||||
|
||||
# Adjust increment speed based on how much progress we've already made
|
||||
# Slower at the beginning, faster near the end
|
||||
var increment_speed = 5.0 + (progress_bar.value / 20.0)
|
||||
|
||||
# Apply increment
|
||||
progress_bar.value = min(progress_bar.value + increment_speed * delta, 99.0)
|
||||
|
||||
ResourceLoader.THREAD_LOAD_LOADED:
|
||||
progress_bar.value = 100
|
||||
call_deferred("_handle_load_complete")
|
||||
|
||||
ResourceLoader.THREAD_LOAD_FAILED:
|
||||
print("Loading failed: ", path)
|
||||
is_loading = false
|
||||
set_process(false)
|
||||
|
||||
func _handle_load_complete():
|
||||
var resource = ResourceLoader.load_threaded_get(path)
|
||||
if resource:
|
||||
change_scene(resource)
|
||||
else:
|
||||
print("Failed to get loaded resource")
|
||||
|
||||
set_process(false)
|
||||
is_loading = false
|
||||
|
||||
func change_scene(resource: PackedScene):
|
||||
print("Loading complete. Switching scene...")
|
||||
# The Lobby (parent) should be removed by the caller or we handle it here if we are the root.
|
||||
# But in this architecture, the Lobby is a child of root or MainMenu?
|
||||
# Actually, usually we use get_tree().change_scene_to_packed(resource)
|
||||
|
||||
get_tree().change_scene_to_packed(resource)
|
||||
|
||||
# Clean up self (Loading Screen)
|
||||
queue_free()
|
||||
|
||||
|
||||
func load_level(_path: String):
|
||||
print("Starting load for: ", _path)
|
||||
path = _path
|
||||
show()
|
||||
content_control.show()
|
||||
|
||||
if scene_name_label:
|
||||
scene_name_label.text = "Loading Game..." # _path.get_file().get_basename()
|
||||
|
||||
if tips.size() > 0:
|
||||
$Control/tips.show()
|
||||
tip_value.text = tips.pick_random()
|
||||
else:
|
||||
$Control/tips.hide()
|
||||
|
||||
# 1. Request Load
|
||||
var error = ResourceLoader.load_threaded_request(path)
|
||||
if error == OK:
|
||||
is_loading = true
|
||||
set_process(true)
|
||||
else:
|
||||
print("Failed to start loading: ", error)
|
||||
# Fallback?
|
||||
@@ -0,0 +1 @@
|
||||
uid://dffsxj8h5sud6
|
||||
Reference in New Issue
Block a user