324 lines
9.6 KiB
GDScript
324 lines
9.6 KiB
GDScript
extends CanvasLayer
|
||
|
||
signal exit(success: bool)
|
||
|
||
var audio_manual = preload("res://asset/audio/sfx/game/八音盒/操纵八音盒.mp3") as AudioStream
|
||
var audio_auto = preload("res://asset/audio/sfx/game/八音盒/自走八音盒.mp3") as AudioStream
|
||
|
||
@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):
|
||
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:
|
||
if Engine.is_editor_hint():
|
||
return
|
||
# 读取、配置参数
|
||
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)
|
||
|
||
|
||
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
|
||
|
||
|
||
func _on_drawer_picked(_node):
|
||
sfx_open_drawer.play()
|
||
box_animation.visible = true
|
||
box_animation.play()
|
||
drawer_btn.visible = false
|
||
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
|
||
# 判断是否对应到 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:
|
||
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
|
||
)
|
||
|
||
|
||
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
|
||
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)
|
||
box_opened.visible = true
|
||
if pic:
|
||
pic.visible = true
|
||
if play_sfx:
|
||
sfx_open_lid.play()
|
||
4:
|
||
box_opened.visible = true
|
||
d4.visible = true
|
||
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
|
||
draggables[i].set_meta("plug_pos", i)
|
||
draggables[i].freezing = true
|
||
|
||
|
||
func _unhandled_input(event: InputEvent) -> void:
|
||
if event.is_action_pressed("interact") and stage == 2:
|
||
get_viewport().set_input_as_handled()
|
||
# 尝试使用道具
|
||
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()
|
||
elif event.is_action_pressed("escape"):
|
||
get_viewport().set_input_as_handled()
|
||
exit.emit(false)
|