xiandie/scene/little_game/八音盒/八音盒.gd

320 lines
9.4 KiB
GDScript3
Raw Normal View History

extends CanvasLayer
signal exit(success: bool)
2025-05-30 11:05:06 +00:00
var audio_manual = preload("res://asset/audio/sfx/game/八音盒/操纵八音盒.mp3") as AudioStream
var audio_auto = preload("res://asset/audio/sfx/game/八音盒/自走八音盒.mp3") as AudioStream
2025-05-30 11:05:06 +00:00
@onready var box_closed = $All/ClosedBox as Draggable2D
@onready var box_opened = $All/OpenedBox as Sprite2D
@onready var box_broken = $All/BrokenBox as Sprite2D
@onready var box_drawer = $All/Drawer as Node2D
@onready var box_animation = $All/BoxAnimation as AnimatedSprite2D
@onready var drawer_btn = $"All/BrokenBox/Draggable抽屉" as Draggable2D
@onready var handle_wheel = $All/Wheel
@onready var side_handle = $All/SideHandle as AnimatedSprite2D
@onready var pic = $"All/Draggable照片" as Draggable2D
@onready var d1 = $"All/OpenedBox/Panel/Draggable2D1" as Draggable2D
@onready var d2 = $"All/OpenedBox/Panel/Draggable2D2" as Draggable2D
@onready var d3 = $"All/OpenedBox/Panel/Draggable2D3" as Draggable2D
@onready var d4 = $"All/OpenedBox/Panel/Draggable2D4" as Draggable2D
@onready var s0 = $"All/OpenedBox/Panel/Marker2D1" as Marker2D
@onready var s1 = $"All/OpenedBox/Panel/Marker2D2" as Marker2D
@onready var s2 = $"All/OpenedBox/Panel/Marker2D3" as Marker2D
@onready var s3 = $"All/OpenedBox/Panel/Marker2D4" as Marker2D
@onready var danzhu = $"All/Drawer/Draggable1" as Draggable2D
@onready var maotou = $"All/Drawer/Draggable2" as Draggable2D
@onready var xiaochan = $"All/Drawer/Draggable3" as Draggable2D
var slots: PackedVector2Array = []
var draggables: Array[Draggable2D] = []
@onready var sfx_music = $MusicPlayer as AudioStreamPlayer
@onready var sfx_picked = $Picked as AudioStreamPlayer
@onready var sfx_dropped = $Dropped as AudioStreamPlayer
@onready var sfx_plugged = $Plugged as AudioStreamPlayer
@onready var sfx_plugged_finish = $PluggedFinish as AudioStreamPlayer
@onready var sfx_open_lid = $OpenLid as AudioStreamPlayer
@onready var sfx_close_lid = $CloseLid as AudioStreamPlayer
@onready var sfx_open_drawer = $OpenDrawer as AudioStreamPlayer
# 1关闭 2打开 3放入小蝉人偶 4全部放置正确可摇手柄 5已播放完成
var stage := 1:
set(value):
2025-05-30 11:05:06 +00:00
stage = value
ArchiveManager.set_global_entry("c02_musicbox_stage", value)
# 父,母,蝶,蝉
var playing_step_sec := 0.5
var playing_step_degree := 45.0
var playing_steps := 10
func _ready() -> void:
2025-05-14 20:43:55 +00:00
if Engine.is_editor_hint():
return
2025-05-30 11:05:06 +00:00
# 读取、配置参数
stage = ArchiveManager.get_global_value("c02_musicbox_stage", 1)
playing_step_sec = audio_manual.get_length() / playing_steps
handle_wheel.rotated.connect(_on_wheel_rotated)
box_closed.picked.connect(_on_box_picked)
drawer_btn.picked.connect(_on_drawer_picked)
if ArchiveManager.get_global_value("c02_musicbox_pic_taken"):
pic.queue_free()
if ArchiveManager.get_global_value("c02_musicbox_danzhu_taken"):
danzhu.queue_free()
if ArchiveManager.get_global_value("c02_musicbox_maotou_taken"):
maotou.queue_free()
if ArchiveManager.get_global_value("c02_musicbox_xiaochan_taken"):
xiaochan.queue_free()
pic.picked.connect(_on_prop_picked.bind("pic"))
danzhu.picked.connect(_on_prop_picked.bind("danzhu"))
maotou.picked.connect(_on_prop_picked.bind("maotou"))
xiaochan.picked.connect(_on_prop_picked.bind("xiaochan"))
d1.picked.connect(_on_picked)
d1.dropped.connect(_on_dropped)
d2.picked.connect(_on_picked)
d2.dropped.connect(_on_dropped)
d3.picked.connect(_on_picked)
d3.dropped.connect(_on_dropped)
d4.picked.connect(_on_picked)
d4.dropped.connect(_on_dropped)
draggables = [d1, d2, d3, d4]
slots = [s0.position, s1.position, s2.position, s3.position]
# 1关闭 2打开 3放入小蝉人偶 4全部放置正确可摇手柄 5已播放完成
_chechout_stage(stage, false)
2025-05-30 11:05:06 +00:00
func _toggle_side_handle_outline(display: bool):
var tween = create_tween()
if display:
tween.tween_property(side_handle.material, "shader_parameter/thickness", 1.0, 0.2)
else:
tween.tween_property(side_handle.material, "shader_parameter/thickness", 0.0, 0.2)
func _on_box_picked(_node):
# 1关闭 2打开 3放入小蝉人偶 4全部放置正确可摇手柄 5已播放完成
if stage == 1:
_chechout_stage(2)
else:
box_closed.visible = false
box_broken.visible = true
if pic:
pic.visible = true
2025-05-30 11:05:06 +00:00
func _on_drawer_picked(_node):
sfx_open_drawer.play()
box_animation.visible = true
box_animation.play()
drawer_btn.visible = false
2025-05-30 11:05:06 +00:00
await box_animation.animation_finished
await get_tree().create_timer(1.0).timeout
box_animation.visible = false
box_broken.visible = false
box_drawer.visible = true
box_drawer.modulate.a = 0
create_tween().tween_property(box_drawer, "modulate:a", 1.0, 0.5)
func _on_prop_picked(node: Draggable2D, archive_key: String):
node.freezing = true
var key = node.item_name
# var tween = create_tween()
# # 撕下来的 fade out
# tween.tween_property(node, "modulate:a", 0.0, 1.0)
# tween.tween_callback(node.queue_free)
# tween.tween_interval(0.5)
# await tween.finished
node.queue_free()
SceneManager.enable_prop_item(key)
ArchiveManager.set_global_entry("c02_musicbox_" + archive_key + "_taken", true)
func _on_picked(node: Draggable2D):
sfx_picked.play()
# 使用 plug_pos 作为 meta 标记 node 位置
node.set_meta("plug_pos", -1)
func _on_dropped(node: Draggable2D):
var limit_squared = 100.0
2025-05-30 11:05:06 +00:00
# 判断是否对应到 slots 在 limit_squared 范围内
for i in range(len(slots)):
var slot_pos = slots[i]
var distance_squared = (node.position - slot_pos).length_squared()
if distance_squared < limit_squared:
node.position = slot_pos
node.set_meta("plug_pos", i)
post_plugged()
else:
sfx_dropped.play()
func post_plugged():
# If all items are placed
var all_plugged = true
for i in range(4):
if draggables[i].get_meta("plug_pos", -1) != i:
2025-05-30 11:05:06 +00:00
all_plugged = false
break
if all_plugged:
# 全部插入stage 进入下一阶段
sfx_plugged_finish.play()
_chechout_stage(stage + 1)
else:
sfx_plugged.play()
var accumulated_radiant := 0.0
# 8 steps in total, then auto play
var accumulated_steps := 0
var playing := false
var continue_playing := false
func _on_wheel_rotated(radiant: float) -> void:
if stage != 4 or accumulated_steps >= playing_steps:
return
accumulated_radiant += radiant
if abs(accumulated_radiant) > deg_to_rad(playing_step_degree):
accumulated_radiant = 0
if playing:
continue_playing = true
else:
playing = true
side_handle.play("default")
if accumulated_steps == 0:
sfx_music.play()
else:
sfx_music.stream_paused = false
get_tree().create_timer(playing_step_sec).timeout.connect(_on_playing_step_finished)
func _on_playing_step_finished():
accumulated_steps += 1
if accumulated_steps == playing_steps:
# auto play
_checkout_auto_play()
return
if continue_playing:
continue_playing = false
get_tree().create_timer(playing_step_sec).timeout.connect(_on_playing_step_finished)
else:
playing = false
sfx_music.stream_paused = true
side_handle.pause()
func _checkout_auto_play():
sfx_music.stop()
sfx_music.stream = audio_auto
sfx_music.play()
side_handle.play()
# var audio_len = audio_auto.get_length()
# 音效 9.5 秒时关闭盒子
var audio_len = 9.5
get_tree().create_timer(audio_len).timeout.connect(_on_auto_play_finished)
func _on_auto_play_finished():
side_handle.pause()
stage = 5
# 不播放关闭音效,因为自动播放时已经播放过了
_chechout_stage(5, false)
# 抖动效果,逐渐减弱
var tween = create_tween()
var fps := 10.0
var duration := 0.4
var delta := 6.0
var origin_pos = box_closed.position
var count = int(duration * fps)
var delta_t = 1.0 / fps
for i in range(count):
var _offset = Vector2(randf_range(-delta, delta), randf_range(-delta, delta)) * exp(-i)
tween.tween_property(box_closed, "position", origin_pos + _offset, delta_t).set_trans(
Tween.TRANS_CUBIC
)
2025-05-30 11:05:06 +00:00
func _hide_all():
if pic:
pic.visible = false
box_broken.visible = false
box_closed.visible = false
box_opened.visible = false
box_drawer.visible = false
box_animation.visible = false
func _chechout_stage(s: int, play_sfx := true) -> void:
_hide_all()
var display_handle_outline = false
# 1关闭 2打开 3放入小蝉人偶 4全部放置正确可摇手柄 5已播放完成
stage = s
match s:
1:
box_closed.visible = true
if play_sfx:
sfx_close_lid.play()
2:
SceneManager.pop_center_notification(tr("ui_use_prop"))
box_opened.visible = true
d4.visible = false
2025-05-30 11:05:06 +00:00
if pic:
pic.visible = true
if play_sfx:
sfx_open_lid.play()
3:
d4.visible = true
d4.modulate.a = 0
create_tween().tween_property(d4, "modulate:a", 1.0, 1.0)
2025-05-30 11:05:06 +00:00
box_opened.visible = true
if pic:
pic.visible = true
if play_sfx:
sfx_open_lid.play()
4:
box_opened.visible = true
d4.visible = true
2025-05-30 11:05:06 +00:00
if pic:
pic.visible = true
_settle_plug_positions()
display_handle_outline = true
if play_sfx:
sfx_open_lid.play()
5:
box_closed.visible = true
_toggle_side_handle_outline(display_handle_outline)
func _settle_plug_positions():
for i in range(4):
draggables[i].position = slots[i]
draggables[i].rotation = 0
2025-05-30 11:05:06 +00:00
draggables[i].set_meta("plug_pos", i)
draggables[i].freezing = true
func _unhandled_input(event: InputEvent) -> void:
2025-05-30 11:05:06 +00:00
if event.is_action_pressed("interact") and stage == 2:
2025-05-14 20:43:55 +00:00
# 尝试使用道具
2025-05-30 11:05:06 +00:00
var hud = SceneManager.get_prop_hud() as PropHud
var key = SceneManager.get_current_prop(false)
if key == "prop_木头人偶":
SceneManager.disable_prop_item(key)
_chechout_stage(3)
else:
# hud 无效shaking
hud.on_toggle_invalid_prop()