feat: completing tutorial
This commit is contained in:
@@ -2,12 +2,15 @@ extends CanvasLayer
|
||||
class_name TutorialOverlay
|
||||
|
||||
# --- Scene node references ---
|
||||
@onready var dim_rect: ColorRect = $DimRect
|
||||
@onready var highlight_border: Panel = $HighlightBorder
|
||||
@onready var dim_rect: ColorRect = $DimRect
|
||||
@onready var highlight_border: Panel = $HighlightBorder
|
||||
@onready var dialogue_panel: PanelContainer = $DialoguePanel
|
||||
@onready var text_label: RichTextLabel = $DialoguePanel/MarginContainer/HBoxContainer/VBoxContainer/DialogueText
|
||||
@onready var next_indicator: Label = $DialoguePanel/MarginContainer/HBoxContainer/VBoxContainer/NextIndicator
|
||||
@onready var highlight_zones: Node = $HighlightZones
|
||||
@onready var text_label: RichTextLabel = $DialoguePanel/MarginContainer/HBoxContainer/VBoxContainer/DialogueText
|
||||
@onready var next_indicator: Label = $DialoguePanel/MarginContainer/HBoxContainer/VBoxContainer/NextIndicator
|
||||
@onready var highlight_zones: Node = $HighlightZones
|
||||
|
||||
@onready var objective_panel: PanelContainer = $ObjectivePanel
|
||||
@onready var objective_text: RichTextLabel = $ObjectivePanel/MarginContainer/VBoxContainer/ObjectiveText
|
||||
|
||||
# --- State ---
|
||||
var is_waiting_for_input: bool = false
|
||||
@@ -63,15 +66,15 @@ func highlight_rect(rect: Rect2) -> void:
|
||||
|
||||
# Position the glowing border panel on top
|
||||
highlight_border.position = rect.position - Vector2(6, 6)
|
||||
highlight_border.size = rect.size + Vector2(12, 12)
|
||||
highlight_border.visible = true
|
||||
highlight_border.size = rect.size + Vector2(12, 12)
|
||||
highlight_border.visible = true
|
||||
|
||||
# Pulsing glow animation
|
||||
if _pulse_tween:
|
||||
_pulse_tween.kill()
|
||||
_pulse_tween = create_tween().set_loops()
|
||||
_pulse_tween.tween_property(highlight_border, "self_modulate:a", 0.25, 0.75)
|
||||
_pulse_tween.tween_property(highlight_border, "self_modulate:a", 1.0, 0.75)
|
||||
_pulse_tween.tween_property(highlight_border, "self_modulate:a", 1.0, 0.75)
|
||||
|
||||
func clear_highlight() -> void:
|
||||
if _dim_material:
|
||||
@@ -86,14 +89,23 @@ func clear_highlight() -> void:
|
||||
# Show / Hide whole overlay
|
||||
# ---------------------------------------------------------------------------
|
||||
func hide_overlay() -> void:
|
||||
dim_rect.visible = false
|
||||
dim_rect.visible = false
|
||||
highlight_border.visible = false
|
||||
dialogue_panel.visible = false
|
||||
dialogue_panel.visible = false
|
||||
|
||||
func show_overlay() -> void:
|
||||
dim_rect.visible = true
|
||||
dim_rect.visible = true
|
||||
dialogue_panel.visible = true
|
||||
|
||||
func set_objective(text: String) -> void:
|
||||
if objective_panel and objective_text:
|
||||
objective_text.text = text
|
||||
objective_panel.visible = true
|
||||
|
||||
func hide_objective() -> void:
|
||||
if objective_panel:
|
||||
objective_panel.visible = false
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Dialogue
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -106,11 +118,11 @@ func display_text(bbcode_text: String, wait_for_click: bool = true) -> void:
|
||||
|
||||
if wait_for_click:
|
||||
next_indicator.visible = true
|
||||
is_waiting_for_input = true
|
||||
is_waiting_for_input = true
|
||||
await next_pressed
|
||||
else:
|
||||
next_indicator.visible = false
|
||||
is_waiting_for_input = false
|
||||
is_waiting_for_input = false
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if not is_waiting_for_input:
|
||||
@@ -121,38 +133,46 @@ func _input(event: InputEvent) -> void:
|
||||
elif event is InputEventScreenTouch and event.pressed:
|
||||
consumed = true
|
||||
if consumed:
|
||||
is_waiting_for_input = false
|
||||
is_waiting_for_input = false
|
||||
next_indicator.visible = false
|
||||
next_pressed.emit()
|
||||
get_viewport().set_input_as_handled()
|
||||
var vp = get_viewport()
|
||||
if vp:
|
||||
vp.set_input_as_handled()
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Power-Up Showcase — one card per powerup with icon + name + description
|
||||
# ---------------------------------------------------------------------------
|
||||
func show_powerup_showcase() -> void:
|
||||
"""Display each powerup as an interactive card. Awaits click between each."""
|
||||
var powerups = [
|
||||
{
|
||||
var _current_showcase: Control
|
||||
|
||||
func show_powerup_card(pid: int) -> void:
|
||||
var powerups = {
|
||||
11: {
|
||||
"icon": "res://assets/graphics/touch_control/speed.png",
|
||||
"name": "[color=gold]⚡ Speed Boost[/color]",
|
||||
"name": "[color=gold]Speed Boost[/color]",
|
||||
"desc": "Temporarily increases your movement speed for [color=yellow]5 seconds[/color]. Great for racing across the board to grab tiles before opponents."
|
||||
},
|
||||
{
|
||||
12: {
|
||||
"icon": "res://assets/graphics/touch_control/freeze_area.png",
|
||||
"name": "[color=aqua]❄ Area Freeze[/color]",
|
||||
"name": "[color=aqua]Area Freeze[/color]",
|
||||
"desc": "Freezes all opponents within a radius of [color=aqua]5 tiles[/color] around you, slowing them to a crawl for [color=yellow]3 seconds[/color]."
|
||||
},
|
||||
{
|
||||
13: {
|
||||
"icon": "res://assets/graphics/touch_control/wall.png",
|
||||
"name": "[color=gray]🧱 Iron Wall[/color]",
|
||||
"name": "[color=gray]Iron Wall[/color]",
|
||||
"desc": "Projects a full row or column of wall tiles in front of you, blocking opponent movement and protecting your tiles."
|
||||
},
|
||||
{
|
||||
14: {
|
||||
"icon": "res://assets/graphics/touch_control/ghost.png",
|
||||
"name": "[color=white]👻 Ghost Mode[/color]",
|
||||
"name": "[color=white]Ghost Mode[/color]",
|
||||
"desc": "Makes you [color=white]invisible[/color] for [color=yellow]6 seconds[/color]. You cannot be rammed while invisible — perfect for escaping danger or sneaking around."
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if not powerups.has(pid):
|
||||
return
|
||||
|
||||
var pu = powerups[pid]
|
||||
|
||||
# Build a showcase panel sitting above the dialogue panel
|
||||
var showcase = PanelContainer.new()
|
||||
@@ -161,22 +181,22 @@ func show_powerup_showcase() -> void:
|
||||
|
||||
var showcase_style = StyleBoxFlat.new()
|
||||
showcase_style.bg_color = Color(0.05, 0.05, 0.12, 0.97)
|
||||
showcase_style.border_width_left = 3
|
||||
showcase_style.border_width_top = 3
|
||||
showcase_style.border_width_right = 3
|
||||
showcase_style.border_width_left = 3
|
||||
showcase_style.border_width_top = 3
|
||||
showcase_style.border_width_right = 3
|
||||
showcase_style.border_width_bottom = 3
|
||||
showcase_style.border_color = Color(0.6, 0.4, 1.0, 1.0)
|
||||
showcase_style.corner_radius_top_left = 12
|
||||
showcase_style.corner_radius_top_right = 12
|
||||
showcase_style.corner_radius_bottom_left = 12
|
||||
showcase_style.corner_radius_top_left = 12
|
||||
showcase_style.corner_radius_top_right = 12
|
||||
showcase_style.corner_radius_bottom_left = 12
|
||||
showcase_style.corner_radius_bottom_right = 12
|
||||
showcase.add_theme_stylebox_override("panel", showcase_style)
|
||||
add_child(showcase)
|
||||
|
||||
var margin = MarginContainer.new()
|
||||
margin.add_theme_constant_override("margin_left", 24)
|
||||
margin.add_theme_constant_override("margin_top", 16)
|
||||
margin.add_theme_constant_override("margin_right", 24)
|
||||
margin.add_theme_constant_override("margin_left", 24)
|
||||
margin.add_theme_constant_override("margin_top", 16)
|
||||
margin.add_theme_constant_override("margin_right", 24)
|
||||
margin.add_theme_constant_override("margin_bottom", 16)
|
||||
showcase.add_child(margin)
|
||||
|
||||
@@ -187,9 +207,12 @@ func show_powerup_showcase() -> void:
|
||||
# Icon
|
||||
var icon_rect = TextureRect.new()
|
||||
icon_rect.custom_minimum_size = Vector2(96, 96)
|
||||
icon_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
icon_rect.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
var tex = load(pu["icon"])
|
||||
if tex:
|
||||
icon_rect.texture = tex
|
||||
hbox.add_child(icon_rect)
|
||||
|
||||
# Text column
|
||||
@@ -203,6 +226,7 @@ func show_powerup_showcase() -> void:
|
||||
name_label.fit_content = true
|
||||
name_label.scroll_active = false
|
||||
name_label.add_theme_font_size_override("normal_font_size", 24)
|
||||
name_label.text = pu["name"]
|
||||
vbox.add_child(name_label)
|
||||
|
||||
var desc_label = RichTextLabel.new()
|
||||
@@ -211,36 +235,24 @@ func show_powerup_showcase() -> void:
|
||||
desc_label.scroll_active = false
|
||||
desc_label.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
desc_label.add_theme_font_size_override("normal_font_size", 18)
|
||||
desc_label.text = pu["desc"]
|
||||
vbox.add_child(desc_label)
|
||||
|
||||
# Counter label (e.g. "1 / 4")
|
||||
var counter_label = Label.new()
|
||||
counter_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||
counter_label.add_theme_font_size_override("font_size", 14)
|
||||
counter_label.add_theme_color_override("font_color", Color(0.6, 0.6, 0.8))
|
||||
vbox.add_child(counter_label)
|
||||
|
||||
# Position the showcase above the dialogue panel
|
||||
# We rely on call deferred or await frame to ensure layout sizing is processed
|
||||
await get_tree().process_frame
|
||||
if not is_inside_tree() or not is_instance_valid(showcase):
|
||||
return
|
||||
|
||||
var vp = get_viewport().get_visible_rect().size
|
||||
showcase.position = Vector2(
|
||||
(vp.x - showcase.custom_minimum_size.x) / 2.0,
|
||||
dialogue_panel.position.y - showcase.custom_minimum_size.y - 12
|
||||
)
|
||||
|
||||
# Cycle through each powerup
|
||||
for i in powerups.size():
|
||||
var pu = powerups[i]
|
||||
var tex = load(pu["icon"])
|
||||
if tex:
|
||||
icon_rect.texture = tex
|
||||
name_label.text = pu["name"]
|
||||
desc_label.text = pu["desc"]
|
||||
counter_label.text = "Power-Up %d / %d — Click to continue ▼" % [i + 1, powerups.size()]
|
||||
_current_showcase = showcase
|
||||
|
||||
# Reuse the existing input wait mechanism
|
||||
is_waiting_for_input = true
|
||||
await next_pressed
|
||||
|
||||
# Clean up showcase
|
||||
showcase.queue_free()
|
||||
func hide_powerup_card() -> void:
|
||||
if is_instance_valid(_current_showcase):
|
||||
_current_showcase.queue_free()
|
||||
_current_showcase = null
|
||||
|
||||
Reference in New Issue
Block a user