This commit is contained in:
2026-03-09 11:57:48 -07:00
parent 041c0ebbdb
commit 7203c843ec
10 changed files with 246 additions and 21 deletions

View File

@@ -20,6 +20,9 @@ class ScriptNode:
func interrupt():
return false
func handle_input(event: InputEvent) -> bool:
return false
class Say:
extends ScriptNode
@@ -71,6 +74,96 @@ class Say:
subject.stop_animation()
subject.play_animation_raw("idle_" + subject.facing)
subject.find_child("label-root").hide()
class Narrate:
extends ScriptNode
var text
var done = false
var started = false
var dismissed_by_click = false
var fade_in_duration = 0.3
var fade_out_duration = 0.3
var chars_per_second = 20.0 # Reading speed
var min_duration = 2.0
var max_duration = 10.0
func step_type():
return "Narrate " + text.substr(0, 20)
func calculate_duration() -> float:
var duration = text.length() / chars_per_second
return clamp(duration, min_duration, max_duration)
func do(delta):
if !started:
started = true
dismissed_by_click = false
# Show narrator overlay with fade in
var narrator_overlay = scene.find_child("NarratorOverlay")
if narrator_overlay:
var panel = narrator_overlay.find_child("Panel")
var label = panel.find_child("Label")
if label:
label.text = text
if panel:
panel.modulate = Color(1, 1, 1, 0)
panel.show()
# Fade in
var tween = scene.create_tween()
tween.tween_property(panel, "modulate", Color(1, 1, 1, 1), fade_in_duration)
await tween.finished
# Set global flag that narrator is active
scene.set_meta("narrator_active", true)
# Calculate display duration
var display_duration = calculate_duration()
# Wait for either timeout or click
var timer = scene.get_tree().create_timer(display_duration)
while timer.time_left > 0 and not dismissed_by_click:
await scene.get_tree().process_frame
# Fade out (keep narrator_active flag true during fade to prevent walk trigger)
var overlay = scene.find_child("NarratorOverlay")
if overlay:
var p = overlay.find_child("Panel")
if p and p.visible:
var tween = scene.create_tween()
tween.tween_property(p, "modulate", Color(1, 1, 1, 0), fade_out_duration)
await tween.finished
p.hide()
# Clear global flag AFTER fade completes
scene.set_meta("narrator_active", false)
done = true
started = true
func is_done():
return done
func dismiss():
dismissed_by_click = true
func interrupt():
done = true
var overlay = scene.find_child("NarratorOverlay")
if overlay:
var p = overlay.find_child("Panel")
if p:
p.hide()
scene.set_meta("narrator_active", false)
func handle_input(event: InputEvent) -> bool:
if event is InputEventMouseButton and Input.is_action_just_released("interact"):
if not dismissed_by_click and not done:
dismissed_by_click = true
return true
return false
class WalkTo:
@@ -292,6 +385,12 @@ class ScriptGraph:
for c in current:
c.interrupt()
return can_interrupt
func handle_input(event: InputEvent) -> bool:
for c in current:
if c.handle_input(event):
return true
return false
var script_graph: ScriptGraph
@@ -340,6 +439,19 @@ func say(subject, text, stop=true):
say.stop = stop
return say
func narrate(text):
var narrate = Narrate.new()
narrate.text = text
return narrate
func dismiss_current_narrator():
if current_script:
for node in current_script.current:
if node is Narrate:
node.dismiss()
return true
return false
func walk_to_deferred(named_from, named_to):
var say = WalkToDeferred.new()
say.subject_name = "SceneViewport/background/Graham"