feat: Implement core game managers for power-ups, UI, goals, and player actions, and establish initial game scene and player.
This commit is contained in:
+69
-11
@@ -62,41 +62,99 @@ func _init_managers():
|
||||
|
||||
# Message Bar Configuration
|
||||
const MAX_MESSAGES := 5
|
||||
const MESSAGE_DURATION := 3.0
|
||||
const MESSAGE_DURATION := 4.0
|
||||
|
||||
@onready var message_bar: PanelContainer = $MessageBar
|
||||
@onready var message_container: VBoxContainer = $MessageBar/MarginContainer/MessageContainer
|
||||
|
||||
func add_message_to_bar(player_name: String, message: String):
|
||||
# Message types for different styling
|
||||
enum MessageType {NORMAL, POWERUP, GOAL, CYCLE, WARNING}
|
||||
|
||||
func add_message_to_bar(player_name: String, message: String, type: int = MessageType.NORMAL):
|
||||
if not message_container:
|
||||
return
|
||||
|
||||
# Create message label
|
||||
# Create message label with rich styling
|
||||
var label = Label.new()
|
||||
label.text = "[%s] %s" % [player_name, message]
|
||||
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
label.add_theme_color_override("font_color", Color.WHITE)
|
||||
label.add_theme_font_size_override("font_size", 14)
|
||||
label.add_theme_font_size_override("font_size", 16)
|
||||
label.modulate.a = 0.0 # Start invisible for fade-in
|
||||
|
||||
# Style based on message type
|
||||
var icon = ""
|
||||
var color = Color.WHITE
|
||||
match type:
|
||||
MessageType.POWERUP:
|
||||
icon = "⚡ "
|
||||
color = Color(0.4, 1.0, 0.4) # Bright green
|
||||
MessageType.GOAL:
|
||||
icon = "🎯 "
|
||||
color = Color(1.0, 0.85, 0.2) # Gold
|
||||
MessageType.CYCLE:
|
||||
icon = "⏱️ "
|
||||
color = Color(0.4, 0.8, 1.0) # Light blue
|
||||
MessageType.WARNING:
|
||||
icon = "⚠️ "
|
||||
color = Color(1.0, 0.5, 0.3) # Orange
|
||||
_:
|
||||
icon = "💬 "
|
||||
color = Color(0.9, 0.9, 0.9) # Light gray
|
||||
|
||||
label.text = "%s%s" % [icon, message]
|
||||
label.add_theme_color_override("font_color", color)
|
||||
|
||||
# Add shadow for better visibility
|
||||
label.add_theme_constant_override("shadow_offset_x", 2)
|
||||
label.add_theme_constant_override("shadow_offset_y", 2)
|
||||
label.add_theme_color_override("font_shadow_color", Color(0, 0, 0, 0.7))
|
||||
|
||||
# Add to container
|
||||
message_container.add_child(label)
|
||||
|
||||
# Show the message bar
|
||||
message_bar.visible = true
|
||||
# Show the message bar with fade
|
||||
if not message_bar.visible:
|
||||
message_bar.visible = true
|
||||
message_bar.modulate.a = 0.0
|
||||
var bar_tween = create_tween()
|
||||
bar_tween.tween_property(message_bar, "modulate:a", 1.0, 0.2)
|
||||
|
||||
# Animate label entrance (slide in + fade)
|
||||
label.position.x = -50
|
||||
var entrance_tween = create_tween()
|
||||
entrance_tween.set_parallel(true)
|
||||
entrance_tween.tween_property(label, "modulate:a", 1.0, 0.3)
|
||||
entrance_tween.tween_property(label, "position:x", 0.0, 0.3).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
|
||||
|
||||
# Powerup gets extra pulse effect
|
||||
if type == MessageType.POWERUP:
|
||||
await entrance_tween.finished
|
||||
var pulse_tween = create_tween()
|
||||
pulse_tween.set_loops(2)
|
||||
pulse_tween.tween_property(label, "scale", Vector2(1.1, 1.1), 0.15).set_trans(Tween.TRANS_SINE)
|
||||
pulse_tween.tween_property(label, "scale", Vector2(1.0, 1.0), 0.15).set_trans(Tween.TRANS_SINE)
|
||||
|
||||
# Remove oldest messages if over limit
|
||||
while message_container.get_child_count() > MAX_MESSAGES:
|
||||
var oldest = message_container.get_child(0)
|
||||
oldest.queue_free()
|
||||
|
||||
# Auto-remove after duration
|
||||
# Auto-remove after duration with fade-out
|
||||
await get_tree().create_timer(MESSAGE_DURATION).timeout
|
||||
if is_instance_valid(label):
|
||||
label.queue_free()
|
||||
var exit_tween = create_tween()
|
||||
exit_tween.set_parallel(true)
|
||||
exit_tween.tween_property(label, "modulate:a", 0.0, 0.3)
|
||||
exit_tween.tween_property(label, "position:x", 50.0, 0.3)
|
||||
await exit_tween.finished
|
||||
if is_instance_valid(label):
|
||||
label.queue_free()
|
||||
|
||||
# Hide bar when empty
|
||||
# Hide bar when empty with fade
|
||||
await get_tree().process_frame
|
||||
if message_container.get_child_count() == 0:
|
||||
var hide_tween = create_tween()
|
||||
hide_tween.tween_property(message_bar, "modulate:a", 0.0, 0.3)
|
||||
await hide_tween.finished
|
||||
message_bar.visible = false
|
||||
|
||||
@rpc("any_peer", "call_local")
|
||||
|
||||
+46
-18
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=26 format=3 uid="uid://dxn87yj8qnfpp"]
|
||||
[gd_scene load_steps=27 format=3 uid="uid://dxn87yj8qnfpp"]
|
||||
|
||||
[ext_resource type="MeshLibrary" uid="uid://kcv6ans86ug7" path="res://addons/enhanced_gridmap/meshlibrary/default.tres" id="1_110wo"]
|
||||
[ext_resource type="Script" uid="uid://co1ads72by6na" path="res://scenes/main.gd" id="1_xcpe3"]
|
||||
@@ -30,6 +30,22 @@ texture = ExtResource("13_ahjgs")
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_s1l63"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_playerboard"]
|
||||
bg_color = Color(0.08, 0.08, 0.12, 0.9)
|
||||
border_color = Color(0.3, 0.3, 0.4, 0.8)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
corner_radius_top_left = 8
|
||||
corner_radius_top_right = 8
|
||||
corner_radius_bottom_right = 8
|
||||
corner_radius_bottom_left = 8
|
||||
content_margin_left = 8.0
|
||||
content_margin_top = 8.0
|
||||
content_margin_right = 8.0
|
||||
content_margin_bottom = 8.0
|
||||
|
||||
[node name="Main" type="Node3D"]
|
||||
script = ExtResource("1_xcpe3")
|
||||
|
||||
@@ -88,15 +104,26 @@ text = "Unique Peer ID"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="PlayerboardPanel" type="PanelContainer" parent="."]
|
||||
anchors_preset = 4
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 10.0
|
||||
offset_top = -120.0
|
||||
offset_right = 216.0
|
||||
offset_bottom = 120.0
|
||||
grow_vertical = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_playerboard")
|
||||
|
||||
[node name="PlayerboardUI" type="GridContainer" parent="."]
|
||||
clip_contents = true
|
||||
anchors_preset = 4
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 32.0
|
||||
offset_top = -104.0
|
||||
offset_right = 228.0
|
||||
offset_bottom = 92.0
|
||||
offset_left = 18.0
|
||||
offset_top = -88.0
|
||||
offset_right = 208.0
|
||||
offset_bottom = 102.0
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 3
|
||||
columns = 5
|
||||
@@ -1065,6 +1092,7 @@ environment = ExtResource("4_ky38j")
|
||||
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
||||
|
||||
[node name="AllPlayerGoals" type="HBoxContainer" parent="."]
|
||||
visible = false
|
||||
y_sort_enabled = true
|
||||
clip_contents = true
|
||||
layout_direction = 2
|
||||
@@ -9325,14 +9353,14 @@ layout_mode = 2
|
||||
theme_override_constants/separation = 4
|
||||
|
||||
[node name="PowerUpBar" type="PanelContainer" parent="."]
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -110.0
|
||||
offset_top = 125.0
|
||||
anchors_preset = 4
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 18.0
|
||||
offset_top = -115.0
|
||||
offset_right = 110.0
|
||||
offset_bottom = 161.0
|
||||
grow_horizontal = 2
|
||||
offset_bottom = -92.0
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="HBox" type="HBoxContainer" parent="PowerUpBar"]
|
||||
layout_mode = 2
|
||||
@@ -9340,23 +9368,23 @@ theme_override_constants/separation = 4
|
||||
|
||||
[node name="PowerLabel" type="Label" parent="PowerUpBar/HBox"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 14
|
||||
text = "POWER "
|
||||
theme_override_font_sizes/font_size = 18
|
||||
text = "⚡"
|
||||
|
||||
[node name="Segment0" type="Panel" parent="PowerUpBar/HBox"]
|
||||
custom_minimum_size = Vector2(36, 20)
|
||||
custom_minimum_size = Vector2(20, 16)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment1" type="Panel" parent="PowerUpBar/HBox"]
|
||||
custom_minimum_size = Vector2(36, 20)
|
||||
custom_minimum_size = Vector2(20, 16)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment2" type="Panel" parent="PowerUpBar/HBox"]
|
||||
custom_minimum_size = Vector2(36, 20)
|
||||
custom_minimum_size = Vector2(20, 16)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment3" type="Panel" parent="PowerUpBar/HBox"]
|
||||
custom_minimum_size = Vector2(36, 20)
|
||||
custom_minimum_size = Vector2(20, 16)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="LeaderboardPanel" type="PanelContainer" parent="."]
|
||||
|
||||
+2
-2
@@ -675,12 +675,12 @@ func remote_set_position(authority_position):
|
||||
global_position = authority_position
|
||||
|
||||
@rpc("any_peer", "call_local")
|
||||
func display_message(message):
|
||||
func display_message(message, type: int = 0):
|
||||
# Send message to the main scene's message bar instead of player bubble
|
||||
var main = get_tree().get_root().get_node_or_null("Main")
|
||||
if main and main.has_method("add_message_to_bar"):
|
||||
var player_name = $Name.text.split("\n")[0] if $Name else str(name)
|
||||
main.add_message_to_bar(player_name, message)
|
||||
main.add_message_to_bar(player_name, message, type)
|
||||
|
||||
func initialize_random_goals(_size: int, min_value: int, max_value: int, null_count: float) -> Array[int]:
|
||||
goals.clear()
|
||||
|
||||
Reference in New Issue
Block a user