diff --git a/asset/art/scene/c02/s04_保卫科/花名册/翻开页.png b/asset/art/scene/c02/s04_保卫科/花名册/翻开页.png index b71bb1db..a3972800 100644 Binary files a/asset/art/scene/c02/s04_保卫科/花名册/翻开页.png and b/asset/art/scene/c02/s04_保卫科/花名册/翻开页.png differ diff --git a/asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part1.wav b/asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part1.wav new file mode 100644 index 00000000..b8722690 Binary files /dev/null and b/asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part1.wav differ diff --git a/asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part1.wav.import b/asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part1.wav.import new file mode 100644 index 00000000..1f1ade85 --- /dev/null +++ b/asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part1.wav.import @@ -0,0 +1,24 @@ +[remap] + +importer="wav" +type="AudioStreamWAV" +uid="uid://nvnoy6pb1ogy" +path="res://.godot/imported/mx_追逐part1.wav-783996c8bca80652b51d8b780783db55.sample" + +[deps] + +source_file="res://asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part1.wav" +dest_files=["res://.godot/imported/mx_追逐part1.wav-783996c8bca80652b51d8b780783db55.sample"] + +[params] + +force/8_bit=false +force/mono=false +force/max_rate=false +force/max_rate_hz=44100 +edit/trim=false +edit/normalize=false +edit/loop_mode=0 +edit/loop_begin=0 +edit/loop_end=-1 +compress/mode=2 diff --git a/asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part2.wav b/asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part2.wav new file mode 100644 index 00000000..b31d9b9e Binary files /dev/null and b/asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part2.wav differ diff --git a/asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part2.wav.import b/asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part2.wav.import new file mode 100644 index 00000000..4db617c2 --- /dev/null +++ b/asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part2.wav.import @@ -0,0 +1,24 @@ +[remap] + +importer="wav" +type="AudioStreamWAV" +uid="uid://blrlxkkkf5w84" +path="res://.godot/imported/mx_追逐part2.wav-4442ef0529a748eed651332699b745b7.sample" + +[deps] + +source_file="res://asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part2.wav" +dest_files=["res://.godot/imported/mx_追逐part2.wav-4442ef0529a748eed651332699b745b7.sample"] + +[params] + +force/8_bit=false +force/mono=false +force/max_rate=false +force/max_rate_hz=44100 +edit/trim=false +edit/normalize=false +edit/loop_mode=0 +edit/loop_begin=0 +edit/loop_end=-1 +compress/mode=2 diff --git a/asset/dialogue/c01.csv b/asset/dialogue/c01.csv index 97451d7d..4b98a9e9 100644 --- a/asset/dialogue/c01.csv +++ b/asset/dialogue/c01.csv @@ -24,11 +24,11 @@ c01_5残疾小孩_1,我们玩游戏还差个人,就你了,吕萍。,孩子 c01_5围观A_1,这次咱们又玩什么好玩的游戏?,小肉圆,,,, c01_5胖小孩_3,我们俩说话的时候,你把嘴闭上,听见没有?,大胖,,,, c01_5围观A_2,知道了胖哥,也带我一个,嘿嘿。,小肉圆,,,, -c01_5残疾小孩_2,猫捉老鼠,我们四个当猫,你当老鼠。,孩子王,,,, -c01_5残疾小孩_3,倒数三个数,你要是被抓到了,我们就请你吃西瓜虫。,孩子王,,,, -c01_5胖小孩倒数_3,三!,小胖孩,,[#wait=0.5],, -c01_5胖小孩倒数_2,二!,小胖孩,,[#wait=0.5],, -c01_5胖小孩倒数_1,一!,小胖孩,,[#wait=2],, +c01_5残疾小孩_2,猫捉老鼠,我们四个当猫,你当老鼠。,孩子王,,[#ban_skip],, +c01_5残疾小孩_3,倒数三个数,你要是被抓到了,我们就请你吃西瓜虫。,孩子王,,[#ban_skip],, +c01_5胖小孩倒数_3,三!,大胖,,[#ban_skip][#wait=0.5],, +c01_5胖小孩倒数_2,二!,大胖,,[#ban_skip][#wait=0.5],, +c01_5胖小孩倒数_1,一!,大胖,,[#ban_skip][#wait=2],, c01_6监督小孩_1,瞧一瞧,看一看,动动各位的发财手,老爷夫人别急走,什么把戏咱都有...,监督小孩,,,, c01_6监督小孩_2,不要千、不要万,只求一顿温饱饭,又集福、又集善,亲戚儿孙中状元!,监督小孩,,,, c01_6监督小孩_3,儿孙坐在那金銮殿,荣华富贵顶上天!,监督小孩,,,, diff --git a/asset/dialogue/c01.dialogue b/asset/dialogue/c01.dialogue index 7218fceb..b0730653 100644 --- a/asset/dialogue/c01.dialogue +++ b/asset/dialogue/c01.dialogue @@ -39,14 +39,17 @@ 小肉圆: 这次咱们又玩什么好玩的游戏? [ID:c01_5围观A_1] 大胖: 我们俩说话的时候,你把嘴闭上,听见没有? [ID:c01_5胖小孩_3] 小肉圆: 知道了胖哥,也带我一个,嘿嘿。 [ID:c01_5围观A_2] -孩子王: 猫捉老鼠,我们四个当猫,你当老鼠。 [ID:c01_5残疾小孩_2] -孩子王: 倒数三个数,你要是被抓到了,我们就请你吃西瓜虫。 [ID:c01_5残疾小孩_3] => END -~ c01_s06_猫鼠游戏 -小胖孩: 三! [#wait=0.5] [ID:c01_5胖小孩倒数_3] -小胖孩: 二! [#wait=0.5] [ID:c01_5胖小孩倒数_2] -小胖孩: 一! [#wait=2] [ID:c01_5胖小孩倒数_1] +~ c01_s06_猫鼠游戏BGM开始 +孩子王: 猫捉老鼠,我们四个当猫,你当老鼠。[#ban_skip] [ID:c01_5残疾小孩_2] +孩子王: 倒数三个数,你要是被抓到了,我们就请你吃西瓜虫。[#ban_skip] [ID:c01_5残疾小孩_3] +=> END + +~ c01_s06_猫鼠游戏倒计时 +大胖: 三![#ban_skip] [#wait=0.5] [ID:c01_5胖小孩倒数_3] +大胖: 二![#ban_skip] [#wait=0.5] [ID:c01_5胖小孩倒数_2] +大胖: 一![#ban_skip] [#wait=2] [ID:c01_5胖小孩倒数_1] => END diff --git a/manager/scene/scene_manager.gd b/manager/scene/scene_manager.gd index 7127a137..a32c2575 100644 --- a/manager/scene/scene_manager.gd +++ b/manager/scene/scene_manager.gd @@ -67,31 +67,39 @@ func focus_player_and_reset_zoom(duration := 1.2) -> void: marker.focus_node(get_player(), duration + .3) -# action_locked 用于设置界面等强制锁定,action_freezed 用于查看物品等锁定 -# action_locked 优先级高于 action_freezed -# action_locked 对应 lock 与 unlock 方法 -func lock_player(): - var player = get_player() - if player: - player.action_locked = true +func get_lock() -> PlayerReenterLock: + var ground = get_ground() + if ground: + return ground.reenter_lock + printerr("get_lock: Ground node not found. return new detached lock") + # 允许访问 lock + return PlayerReenterLock.new() + + +func lock_player(duration := 0): + get_lock().lock_all(duration) func unlock_player(): - var player = get_player() - if player: - player.action_locked = false + get_lock().unlock_all() -# func is_palyer_operational() -> bool: -# var player = get_player() as MainPlayer -# if not player: -# return true -# return player.operational +func hold_player(duration := 0): + get_lock().hold(duration) -# func set_player_operational(val := true): -# var player = get_player() as MainPlayer -# if player: -# player.operational = val + +func unhold_player(): + get_lock().unhold() + + +# lock_time: the time to lock the player action. 0 means lock forever, thus the player will be locked until release_player is called. +func freeze_player(lock_time: float, action := 3, auto_quit := false) -> void: + player_action(action, auto_quit) + get_lock().freeze(lock_time) + + +func release_player(): + get_lock().release() func player_action(action_code: int, auto_quit := false): @@ -102,32 +110,6 @@ func player_action(action_code: int, auto_quit := false): printerr("player_action: Player node not found") -# action_freezed 对应 freeze 与 release 方法 -# lock_time: the time to lock the player action. 0 means lock forever, thus the player will be locked until release_player is called. -func freeze_player(lock_time: float, action := 3, auto_quit := false) -> void: - var player = get_player() - if player: - player.freeze_player(lock_time, action, auto_quit) - else: - printerr("Player node not found") - - -func freeze_and_play(lock_time: float, animation := "", auto_quit := false) -> void: - var player = get_player() - if player: - player.freeze_and_play(lock_time, animation, auto_quit) - else: - printerr("Player node not found") - - -func release_player(force_clear:=false): - var player = get_player() - if player: - player.release_player(force_clear) - else: - printerr("Player node not found") - - func set_camera_boundary(rect: Rect2) -> void: var camera_marker = get_camera_marker() camera_marker.limit_left = rect.position.x @@ -236,15 +218,14 @@ func disable_prop_item(prop_key: String) -> void: printerr("disable_prop_item PropHud node not found") -func pop_os_with_str(translation_key: String, auto_freeze := true, auto_release := true) -> Tween: +func pop_os_with_str(translation_key: String, auto_freeze := true, auto_release := true) -> void: var player = get_player() as MainPlayer if player: var msg = tr(translation_key).replace("
", "\n") var lines = await DialogueUtil.generate_lines(msg) - return player.pop_os(lines, auto_freeze, auto_release) + player.pop_os(lines, auto_freeze, auto_release) else: printerr("Player node not found") - return create_tween() func pop_notification(msg: String, number := 1) -> void: diff --git a/scene/character/main_player.gd b/scene/character/main_player.gd index 8457cf8e..1357db65 100644 --- a/scene/character/main_player.gd +++ b/scene/character/main_player.gd @@ -4,6 +4,7 @@ extends CharacterBody2D class_name MainPlayer signal position_updated(global_pos: Vector2) +# 保证每次 pop_os 后都会有一次 os_finished 信号 signal os_finished signal animation_finished @@ -20,6 +21,7 @@ signal animation_finished @export var catty_light_energy := 0.7 @export var lock_move_left := false @export var lock_move_right := false +@export var reenter_lock: PlayerReenterLock @export var camera_marker: CameraFocusMarker @export_enum("吕萍", "吕萍爬行", "吕萍带小猫", "吕萍推柜子", "小小蝶", "盒子猫", "小小小蝶") var character := "吕萍": set(val): @@ -32,19 +34,6 @@ signal animation_finished @export var player_movement_rect := Rect2(50, -500, 1400, 1000) @export var velocity_ratio := 1.0 @export var running_locked := false -# action_locked 用于设置界面等强制锁定(禁止游戏场景内的任何操作),action_freezed 用于查看物品等锁定(主要用于禁止在场景中移动) -# action_locked 优先级高于 action_freezed -# action_locked 对应 lock 与 unlock 方法 -@export var action_locked := false: - set(val): - action_locked = val - _process_action_lock() -# action_freezed 对应 freeze 与 release 方法 -@export var action_freezed := false: - set(val): - action_freezed = val - _process_action_lock() - @export_enum("idle", "walking", "running") var current_status := 0: set(val): current_status = val @@ -88,6 +77,9 @@ func _ready() -> void: footstep_timer.timeout.connect(_on_footstep_timer_timeout) footstep_timer.stop() sprite.animation_finished.connect(animation_finished.emit) + if not reenter_lock: + push_error("reenter_lock is not set.") + reenter_lock.freeze_changed.connect(_on_freeze_changed) func reparent_light(node: Node): @@ -131,17 +123,6 @@ func _on_footstep_timer_timeout(): ground.play_footstep_sound() -func _process_action_lock() -> void: - # reset status to idle or stay - if action_locked or action_freezed: - velocity = Vector2.ZERO - if ( - current_status == PlayerAnimationConfig.MOVEMENT_WALKING - or current_status == PlayerAnimationConfig.MOVEMENT_RUNNING - ): - current_status = PlayerAnimationConfig.MOVEMENT_IDLE - - # return whether the player status or facing direction has changed. func _check_status(direction) -> bool: var tmp_status = current_status @@ -234,7 +215,8 @@ func _get_speed(direction: Vector2) -> Vector2: func _physics_process(_delta: float) -> void: - if action_locked or action_freezed or Engine.is_editor_hint() or not is_visible_in_tree(): + if Engine.is_editor_hint() or (reenter_lock and reenter_lock.is_frozen()): + # or not is_visible_in_tree() velocity = Vector2.ZERO return var x_direction := Input.get_axis("left", "right") @@ -297,39 +279,32 @@ func player_action(action_code: int, auto_quit: bool): sprite.animation_finished.connect(_play_animation, CONNECT_ONE_SHOT) -var freeze_counter := 0 -var release_timer: SceneTreeTimer +func _on_freeze_changed(count: int, is_add: bool): + if count == 1 and is_add: + _on_first_frozen() -# 自动解除对应 animation 的 loop 状态 -# lock_time: the time to lock the player action. 0 means lock forever, thus the player will be locked until release_player is called. -func freeze_player(lock_time: float, action_code: int, auto_quit: bool) -> void: - freeze_counter += 1 - action_freezed = true +# 非首次 freeze 不改变动画状态,因为在动画演出中可能多次 freeze 与 release +func _on_first_frozen() -> void: + # reset status to idle or stay + velocity = Vector2.ZERO + if ( + current_status == PlayerAnimationConfig.MOVEMENT_WALKING + or current_status == PlayerAnimationConfig.MOVEMENT_RUNNING + ): + current_status = PlayerAnimationConfig.MOVEMENT_IDLE + + +# duration: the time to lock the player action. 0 means lock forever, thus the player will be locked until release_player is called. +func freeze_player(duration: float, action_code: int, auto_quit: bool) -> void: player_action(action_code, auto_quit) - if lock_time: - if release_timer and release_timer.time_left > 0: - release_timer.time_left = max(lock_time, release_timer.time_left) - else: - release_timer = get_tree().create_timer(lock_time) - release_timer.timeout.connect(release_player) + if reenter_lock: + reenter_lock.freeze(duration) -# force_clear 强制清零计数器 -func release_player(force_clear := false): - release_timer = null - freeze_counter -= 1 - if force_clear: - if freeze_counter != 0 and GlobalConfig.DEBUG: - printerr( - "release_player force_clear=True worked. freeze_counter before: %s" % freeze_counter - ) - freeze_counter = 0 - if freeze_counter == 0: - action_freezed = false - elif freeze_counter < 0: - action_freezed = false - printerr("release_player called with freeze_counter < 0, this should not happen.") +func release_player(): + if reenter_lock: + reenter_lock.release() # velocity_ratio = 1.0 # _play_animation() @@ -405,12 +380,20 @@ func _reset_os_and_light_position(): var os_tween: Tween +# 保证每次 pop_os 后都会有一次 os_finished 信号 +var os_finish_emit_lock := Mutex.new() +var os_finished_not_emitted := false var os_pausing_timer: SceneTreeTimer -func pop_os(lines := [], auto_freeze := true, auto_release := true) -> Tween: +func pop_os(lines := [], auto_freeze := true, auto_release := true) -> void: if os_tween: os_tween.kill() + os_finish_emit_lock.lock() + if os_finished_not_emitted: + os_finished.emit() + os_finished_not_emitted = true + os_finish_emit_lock.unlock() if auto_freeze: freeze_player(0, 3, false) os_tween = create_tween() @@ -421,11 +404,15 @@ func pop_os(lines := [], auto_freeze := true, auto_release := true) -> Tween: # var duration = max(min(4.0, line.text.length() * 0.2), 2.0) - 0.4 os_tween.tween_callback(_os_load_line.bind(line, duration)) os_tween.tween_interval(0.1) - os_tween.tween_callback(os_finished.emit) os_tween.tween_property(os_contaner, "modulate:a", 0.0, 0.2) if auto_release: os_tween.tween_callback(release_player) - return os_tween + os_tween.tween_callback(func(): + os_finished.emit() + os_finish_emit_lock.lock() + os_finished_not_emitted = false + os_finish_emit_lock.unlock() + ) func _os_load_line(line, duration): @@ -491,11 +478,12 @@ func set_y_from_ground(player_y: float) -> void: global_position.y = player_y -func walk_to_x(global_pos_x: float, release_on_arrived := true) -> Tween: - return walk_to(Vector2(global_pos_x, global_position.y), release_on_arrived) +func walk_to_x(global_pos_x: float) -> Tween: + return walk_to(Vector2(global_pos_x, global_position.y)) -func walk_to(global_pos: Vector2, release_on_arrived := true) -> Tween: +# auto freeze and release +func walk_to(global_pos: Vector2) -> Tween: var tween = create_tween() velocity = Vector2.ZERO if GlobalConfig.DEBUG: @@ -511,13 +499,12 @@ func walk_to(global_pos: Vector2, release_on_arrived := true) -> Tween: _check_status(facing_direction) _play_animation() tween.tween_property(self, "global_position", global_pos, time_cost) - tween.tween_callback(_after_walk_to.bind(release_on_arrived)) + tween.tween_callback(_after_walk_to) return tween -func _after_walk_to(release_on_arrived: bool) -> void: +func _after_walk_to() -> void: velocity = Vector2.ZERO current_status = PlayerAnimationConfig.MOVEMENT_IDLE _play_animation() - if release_on_arrived: - release_player() + release_player() diff --git a/scene/character/reenter_lock.gd b/scene/character/reenter_lock.gd new file mode 100644 index 00000000..b701f5c9 --- /dev/null +++ b/scene/character/reenter_lock.gd @@ -0,0 +1,134 @@ +# ReenterLock.gd +extends Node +class_name PlayerReenterLock + +#### 目前无需全局,仅需跟随 ground +#### 因此无需在 exit 时重置锁,也无需推迟计数 +#### 因为 PlayerReenterLock 生命周期与 ground 一致 + +####### PlayerReenterLock 系统提供了以下特性 ############# +# 可重入性:每个事件可以多次锁定/解锁,通过计数器管理 +# 全局状态追踪:使用静态变量追踪整体锁定状态 [无需启用] +# 生命周期管理:自动处理节点进入/退出场景树的情况 [无需启用] +# 错误保护:防止过度释放,并在出现问题时发出警告 +# 调试支持:可选的调试模式输出详细信息 +# 便捷方法:提供同时锁定/解锁两种状态的方法 +################################################# + +signal freeze_changed(count: int, is_add: bool) +signal hold_changed(count: int, is_add: bool) + +# 实例级别的锁定请求追踪 +var _freeze_requests: int = 0 +var _hold_requests: int = 0 + +# 调试模式 +var debug_mode := GlobalConfig.DEBUG + + +func _exit_tree() -> void: + if _freeze_requests > 0: + if debug_mode: + push_warning( + "[ReenterLock] Remains %d freeze requests on exit_tree. parent=" % _freeze_requests, + get_parent() + ) + if _hold_requests > 0: + if debug_mode: + print( + "[ReenterLock] Remains %d hold requests on exit_tree. parent=" % _hold_requests, + get_parent() + ) + + +func _create_timer(duration: float, callable: Callable): + if duration > 0 and callable: + get_tree().create_timer(duration).timeout.connect(callable) + + +# Freeze 相关方法 +func freeze(duration := 0.0) -> void: + if duration > 0: + _create_timer(duration, release) + _freeze_requests += 1 + if debug_mode: + print("[ReenterLock] Freeze applied: ", _freeze_requests) + freeze_changed.emit(_freeze_requests, true) + + +func release() -> void: + if _freeze_requests <= 0: + push_warning( + ( + "[ReenterLock] Attempting to release more times than frozen! Current local count: %d" + % _freeze_requests + ) + ) + return + _freeze_requests -= 1 + if debug_mode: + print("[ReenterLock] Release applied: ", _freeze_requests) + freeze_changed.emit(_freeze_requests, false) + + +# Hold 相关方法 +func hold(duration := 0.0) -> void: + if duration > 0: + _create_timer(duration, unhold) + _hold_requests += 1 + if debug_mode: + print("[ReenterLock] Hold applied: ", _hold_requests) + hold_changed.emit(_hold_requests, true) + + +func unhold() -> void: + if _hold_requests <= 0: + push_warning( + ( + "[ReenterLock] Attempting to unhold more times than held! Current local count: %d" + % _hold_requests + ) + ) + return + _hold_requests -= 1 + if debug_mode: + print("[ReenterLock] Unhold applied: ", _hold_requests) + hold_changed.emit(_hold_requests, false) + + +# 静态方法:查询当前状态 +func is_frozen() -> bool: + return _freeze_requests > 0 + + +func is_held() -> bool: + return _hold_requests > 0 + + +func get_freeze_count() -> int: + return _freeze_requests + + +func get_hold_count() -> int: + return _hold_requests + + +# 便捷方法:同时锁定移动和输入 +func lock_all(duration := 0.0) -> void: + if duration > 0: + _create_timer(duration, unlock_all) + _hold_requests += 1 + _freeze_requests += 1 + if debug_mode: + prints("[ReenterLock] LockAll applied (hold, freeze): ", _hold_requests, _freeze_requests) + hold_changed.emit(_hold_requests, true) + freeze_changed.emit(_freeze_requests, true) + + +func unlock_all() -> void: + release() + unhold() + + +func _to_string() -> String: + return "[ReenterLock] Freeze: %d, Hold: %d" % [_freeze_requests, _hold_requests] diff --git a/scene/character/reenter_lock.gd.uid b/scene/character/reenter_lock.gd.uid new file mode 100644 index 00000000..a5ab6409 --- /dev/null +++ b/scene/character/reenter_lock.gd.uid @@ -0,0 +1 @@ +uid://diyjjsqnaqm48 diff --git a/scene/entity/closeup.tscn b/scene/entity/closeup.tscn index b9de4f83..83c3df32 100644 --- a/scene/entity/closeup.tscn +++ b/scene/entity/closeup.tscn @@ -46,7 +46,5 @@ shape = SubResource("RectangleShape2D_ogin7") unique_name_in_owner = true script = ExtResource("7_dnubm") radius = 3.0 -delay_arrived = 0.1 action_on_arrived = 4 -delay_after_action = 0.4 metadata/_custom_type_script = "uid://cnt01hiw52bmn" diff --git a/scene/entity/inspectable.gd b/scene/entity/inspectable.gd index 3fe2f56b..56510d3e 100644 --- a/scene/entity/inspectable.gd +++ b/scene/entity/inspectable.gd @@ -93,6 +93,7 @@ func _ready() -> void: if content_centered: content_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER # sign_mark.interacted.connect(_on_interacted) + sign_snapper.action_on_arrived = action_key sign_snapper.arrived.connect(_on_interacted) sign_mark.cancel.connect(_on_cancel) @@ -115,25 +116,21 @@ func _on_interacted() -> void: if STATUS_TRANSITIONING == status: return if tried_times == 0 and first_interact_os_key: - SceneManager.freeze_player(0, action_key) sign_mark.display_sign = false - var tween = await SceneManager.pop_os_with_str(first_interact_os_key) - tween.tween_callback(_do_action) - tween.tween_callback(func(): sign_mark.display_sign = true) - else: - SceneManager.freeze_player(0, action_key) - _do_action() + SceneManager.pop_os_with_str(first_interact_os_key) + await SceneManager.get_player().os_finished + sign_mark.display_sign = true + _do_action() func _do_action() -> void: - if STATUS_TRANSITIONING == status: - return if status == STATUS_NORAML: + SceneManager.freeze_player(0, action_key) + status = STATUS_TRANSITIONING tried_times += 1 sfx.play() SceneManager.focus_node(self) SceneManager.get_camera_marker().tween_zoom(2.0) - status = STATUS_TRANSITIONING var tween = create_tween() tween.tween_interval(0.8) tween.tween_property(container, "modulate:a", 1.0, 0.7) @@ -142,8 +139,6 @@ func _do_action() -> void: sign_mark.interacted.connect(_on_interacted) sign_snapper.arrived.disconnect(_on_interacted) sign_mark.display_sign = false - - SceneManager.freeze_player(0.0, action_key) cover_rect.texture = texture_cover if content_key == "": tip_label.text = tip_cover_without_notes diff --git a/scene/entity/inspectable.tscn b/scene/entity/inspectable.tscn index d43a61f8..ee5fe7f1 100644 --- a/scene/entity/inspectable.tscn +++ b/scene/entity/inspectable.tscn @@ -129,9 +129,6 @@ vertical_alignment = 1 [node name="SignSnapper" type="Marker2D" parent="."] unique_name_in_owner = true script = ExtResource("10_mtbvd") -release_player_on_arrived = false radius = 3.0 -delay_arrived = 0.1 action_on_arrived = 4 -delay_after_action = 0.4 metadata/_custom_type_script = "uid://cnt01hiw52bmn" diff --git a/scene/entity/interactable.gd b/scene/entity/interactable.gd index 9bb0c4bf..96bf414b 100644 --- a/scene/entity/interactable.gd +++ b/scene/entity/interactable.gd @@ -73,9 +73,9 @@ func _ready() -> void: return area2d.body_entered.connect(_reset) area2d.body_exited.connect(_on_cancel) + sign_snapper.action_on_arrived = action_key if enable_snapper: sign_snapper.arrived.connect(_pre_interacted) - sign_snapper.action_on_arrived = action_key else: sign_snapper.enabled = false sign_mark.interacted.connect(_pre_interacted) @@ -146,11 +146,10 @@ func _pre_interacted() -> void: SceneManager.player_action(action_key) if tried_times == 0 and first_interact_os_key: sign_mark.display_sign = false - var tween = await SceneManager.pop_os_with_str(first_interact_os_key) - tween.tween_callback(_on_interacted) - tween.tween_callback(func(): sign_mark.display_sign = true) - else: - _on_interacted() + SceneManager.pop_os_with_str(first_interact_os_key) + await SceneManager.get_player().os_finished + sign_mark.display_sign = true + _on_interacted() func _on_interacted() -> void: diff --git a/scene/entity/interactable.tscn b/scene/entity/interactable.tscn index 49ad04c4..a5804275 100644 --- a/scene/entity/interactable.tscn +++ b/scene/entity/interactable.tscn @@ -50,7 +50,5 @@ shape = SubResource("RectangleShape2D_8d3b4") unique_name_in_owner = true script = ExtResource("9_03eog") radius = 4.0 -delay_arrived = 0.1 action_on_arrived = 4 -delay_after_action = 0.4 metadata/_custom_type_script = "uid://cnt01hiw52bmn" diff --git a/scene/entity/note.gd b/scene/entity/note.gd index 4023fad5..29ac0bfd 100644 --- a/scene/entity/note.gd +++ b/scene/entity/note.gd @@ -120,16 +120,13 @@ func _on_interacted() -> void: func _show_os(): interacting = true - SceneManager.freeze_player(0.0, action) create_tween().tween_property(sign_mark, "modulate:a", 0.0, 0.3) - var tween = await SceneManager.pop_os_with_str(note_key, false, true) + SceneManager.pop_os_with_str(note_key) + SceneManager.player_action(action) + await SceneManager.get_player().os_finished + var tween = create_tween() tween.tween_property(sign_mark, "modulate:a", 1.0, 0.3) - tween.tween_callback(_on_os_finished) - - -func _on_os_finished(): interacting = false - SceneManager.release_player() func _show_balloon(res, title): diff --git a/scene/entity/npc.gd b/scene/entity/npc.gd index f15b15db..57d80787 100644 --- a/scene/entity/npc.gd +++ b/scene/entity/npc.gd @@ -4,6 +4,7 @@ class_name Npc2D extends AnimatedSprite2D signal interacted # <0 means no walk to edge +@export var snap_to_edge := true @export var walk_to_edge_width := 25.0 @export var action_key := 4 @export var enabled := true: @@ -42,6 +43,8 @@ func _ready() -> void: shape.size.x = collision_width_and_x.x area2d.position.x = collision_width_and_x.y sign_snapper.action_on_arrived = action_key + sign_snapper.radius = walk_to_edge_width + sign_snapper.enabled = snap_to_edge if Engine.is_editor_hint(): # editor 直接展示 speaking_sign.visible = true @@ -53,11 +56,9 @@ func _ready() -> void: base_mod = speaking_sign.modulate area2d.body_entered.connect(_on_entered) area2d.body_exited.connect(_on_exited) - if walk_to_edge_width >= 0: - sign_snapper.radius = walk_to_edge_width + if snap_to_edge: sign_snapper.arrived.connect(_on_interacted) else: - sign_snapper.enabled = false sign_mark.interacted.connect(_on_interacted) # sign_mark.cancel.connect(_stop_speaking) sign_mark.toggle_active.connect(_on_toggle_active) @@ -104,7 +105,7 @@ func _on_interacted() -> void: interacted.emit() DialogueManager.show_dialogue_balloon(dialogue_res, dialogue_title) speaking = true - SceneManager.freeze_player(0) + SceneManager.freeze_player(0, action_key) DialogueManager.dialogue_ended.connect(_dialog_end, CONNECT_ONE_SHOT) var tween = create_tween() tween.tween_property(speaking_sign, "modulate", Color.WHITE, 0.5) diff --git a/scene/entity/npc.tscn b/scene/entity/npc.tscn index 0ef251e5..ebf340c6 100644 --- a/scene/entity/npc.tscn +++ b/scene/entity/npc.tscn @@ -123,12 +123,13 @@ animations = [{ [sub_resource type="RectangleShape2D" id="RectangleShape2D_4fuic"] resource_local_to_scene = true -size = Vector2(25, 100) +size = Vector2(35, 100) [node name="Npc" type="AnimatedSprite2D"] light_mask = 5 script = ExtResource("1_jegr2") -collision_width_and_x = Vector2(25, 0) +snap_to_edge = null +collision_width_and_x = Vector2(35, 0) dialogue_title = "" [node name="Sfx" type="AudioStreamPlayer" parent="."] @@ -183,7 +184,5 @@ unique_name_in_owner = true script = ExtResource("8_7lwt5") radius = 20.0 walk_to_edge = true -delay_arrived = 0.1 action_on_arrived = 4 -delay_after_action = 0.4 metadata/_custom_type_script = "uid://cnt01hiw52bmn" diff --git a/scene/entity/pickable.gd b/scene/entity/pickable.gd index c9b58f27..b2c08737 100644 --- a/scene/entity/pickable.gd +++ b/scene/entity/pickable.gd @@ -15,6 +15,7 @@ signal sign_mark_offset_updated enabled = val if is_node_ready(): _check_sign_display() +@export var action_key := 4 # 除了 picked 必然隐藏,其他情况下跟随 enabled 状态 @export var visible_follow_enabled := true @export var collision_width_and_x := Vector2(20.0, 0): @@ -58,6 +59,7 @@ func _ready() -> void: var shape = area2d.get_node("CollisionShape2D").shape shape.size.x = collision_width_and_x.x area2d.position.x = collision_width_and_x.y + sign_snapper.action_on_arrived = action_key if Engine.is_editor_hint(): var animation_player = _get_animation_player() # 更新 hook_animation 的可选项 diff --git a/scene/entity/pickable.tscn b/scene/entity/pickable.tscn index e1c0e6d7..35d34492 100644 --- a/scene/entity/pickable.tscn +++ b/scene/entity/pickable.tscn @@ -13,6 +13,7 @@ size = Vector2(20, 60) [node name="Pickable" type="Sprite2D"] script = ExtResource("1_jk1u0") +action_key = null prop_key = "" [node name="Sfx" type="AudioStreamPlayer" parent="."] @@ -43,7 +44,5 @@ shape = SubResource("RectangleShape2D_k6och") unique_name_in_owner = true script = ExtResource("6_4qt5l") radius = 10.0 -delay_arrived = 0.1 action_on_arrived = 4 -delay_after_action = 0.4 metadata/_custom_type_script = "uid://cnt01hiw52bmn" diff --git a/scene/entity/portal.tscn b/scene/entity/portal.tscn index f8dc18e6..4572a63c 100644 --- a/scene/entity/portal.tscn +++ b/scene/entity/portal.tscn @@ -75,6 +75,4 @@ shape = SubResource("RectangleShape2D_munml") unique_name_in_owner = true script = ExtResource("12_bxihn") radius = 10.0 -delay_arrived = 0.1 -delay_after_action = 0.4 metadata/_custom_type_script = "uid://cnt01hiw52bmn" diff --git a/scene/entity/ux/sign.gd b/scene/entity/ux/sign.gd index bb47f3d0..8e3cf9d9 100644 --- a/scene/entity/ux/sign.gd +++ b/scene/entity/ux/sign.gd @@ -189,8 +189,7 @@ func _unhandled_input(event: InputEvent) -> void: return # if lock_on_player_freezed and SceneManager.is_palyer_freezed_or_locked(): # return - var player = SceneManager.get_player() - if not player or player.action_locked: + if SceneManager.get_lock().is_held(): return if activated: if event.is_action_pressed("interact"): diff --git a/scene/entity/ux/sign_snapper.gd b/scene/entity/ux/sign_snapper.gd index 99df5bc5..72b6f7f8 100644 --- a/scene/entity/ux/sign_snapper.gd +++ b/scene/entity/ux/sign_snapper.gd @@ -5,21 +5,23 @@ class_name SignSnapper signal arrived @export var enabled := true -@export var release_player_on_arrived := true # 仅使用 x 坐标;否则也用 y 进行 walk to @export var use_x_only := true +# 允许小幅调动,0-3px 被忽视,3-5px 被视作 5px +@export var auto_adjust := true # x 左右有效范围 @export_range(0.0, 20.0, 0.1) var radius := 0.0 # 让玩家走到边缘,特别适用于 npc 对话等情景 @export var walk_to_edge := false -# arrived 延时 -@export_range(0.0, 10.0, 0.1) var delay_arrived := 0.0 @export var action_on_arrived := 3 -@export_range(0.0, 10.0, 0.1) var delay_after_action := 0.0 @export_tool_button("debug 检查玩家触发位置") var debug_check_player_pos = _debug_check_player_pos var detacted_sign: Sign +# arrived 延时: delay_arrived-arrived +static var delay_arrived := 0.0 +static var delay_after_action := 0.0 + # 玩家在和 sign 交互时,如果读到节点中有 SignSnapper,则移动到该位置(x 对齐) func _ready(): @@ -49,7 +51,20 @@ func _on_interacted(): target_pos.x -= radius else: target_pos.x += radius - var tween = player.walk_to(target_pos, release_player_on_arrived) + var diff = absf(player_x - target_pos.x) + if auto_adjust: + # 允许小幅调动,0-3px 被忽视,3-5px 被视作 5px + if diff < 3: + target_pos.x = player_x + diff = 0 + elif diff < 5: + target_pos.x = player_x + (5 if target_pos.x > player_x else -5) + diff = 5 + var tween + if diff == 0: + tween = create_tween() + else: + tween = player.walk_to(target_pos) if delay_arrived > 0: tween.tween_interval(delay_arrived) if action_on_arrived != 3: diff --git a/scene/ground/ground.gd b/scene/ground/ground.gd index 5d55347b..cbd2a374 100644 --- a/scene/ground/ground.gd +++ b/scene/ground/ground.gd @@ -32,6 +32,7 @@ var default_portal := "left" # var main_scene := preload("res://scene/main.tscn") as PackedScene @onready var player_line = %PlayerLine2D as Line2D +@onready var reenter_lock = %PlayerReenterLock as PlayerReenterLock @onready var player = %MainPlayer as MainPlayer @onready var directional_light := %DirectionalLight2D as DirectionalLight2D @onready var bg_sprite = %BGSprite2D as Sprite2D diff --git a/scene/ground/ground.tscn b/scene/ground/ground.tscn index a840c9e2..7952b7dd 100644 --- a/scene/ground/ground.tscn +++ b/scene/ground/ground.tscn @@ -1,6 +1,7 @@ -[gd_scene load_steps=8 format=3 uid="uid://dayyx4jerj7io"] +[gd_scene load_steps=9 format=3 uid="uid://dayyx4jerj7io"] [ext_resource type="Script" uid="uid://bee4ot74k4wg2" path="res://scene/ground/ground.gd" id="1_0vrlo"] +[ext_resource type="Script" uid="uid://diyjjsqnaqm48" path="res://scene/character/reenter_lock.gd" id="2_6ggqv"] [ext_resource type="PackedScene" uid="uid://cjhw5ecygrqty" path="res://scene/character/main_player.tscn" id="3_atha7"] [ext_resource type="PackedScene" uid="uid://61pis75a8fdq" path="res://scene/entity/portal.tscn" id="3_t73yw"] [ext_resource type="PackedScene" uid="uid://cqkeegrcdjyg4" path="res://scene/ground/camera/camera_focus_marker.tscn" id="4_mgk0a"] @@ -19,6 +20,11 @@ script = ExtResource("1_0vrlo") [node name="AnimationPlayer" type="AnimationPlayer" parent="."] +[node name="PlayerReenterLock" type="Node" parent="."] +unique_name_in_owner = true +script = ExtResource("2_6ggqv") +metadata/_custom_type_script = "uid://diyjjsqnaqm48" + [node name="BGSprite2D" type="Sprite2D" parent="."] unique_name_in_owner = true z_index = -5 @@ -37,9 +43,10 @@ portal_name = "right" [node name="AmbientLayer" type="Node2D" parent="."] -[node name="MainPlayer" parent="." node_paths=PackedStringArray("camera_marker") instance=ExtResource("3_atha7")] +[node name="MainPlayer" parent="." node_paths=PackedStringArray("reenter_lock", "camera_marker") instance=ExtResource("3_atha7")] unique_name_in_owner = true position = Vector2(41, 88) +reenter_lock = NodePath("../PlayerReenterLock") camera_marker = NodePath("../CameraFocusMarker") [node name="CameraFocusMarker" parent="." node_paths=PackedStringArray("focusing_node") instance=ExtResource("4_mgk0a")] diff --git a/scene/ground/ground_loader.gd b/scene/ground/ground_loader.gd index f2fbde44..e9a0232a 100644 --- a/scene/ground/ground_loader.gd +++ b/scene/ground/ground_loader.gd @@ -20,7 +20,6 @@ var first_entered := true var ground: Ground2D var display_mask_sec = 0.0 - # 场景名字映射到路径 static var GROUND_SCENE_PATH_DICT = { "c01_s05": "res://scene/ground/scene/c01/s05_院长房间.tscn", @@ -41,17 +40,18 @@ static var GROUND_SCENE_PATH_DICT = { "c02_s08": "res://scene/ground/scene/c02/s08_瞎子卧室.tscn", "c02_s09": "res://scene/ground/scene/c02/s09_裂缝.tscn", "c02_s10": "res://scene/ground/scene/c02/s10_空房间.tscn", - "c02_s11": "res://scene/ground/scene/c02/s11_一楼火灾.tscn", # 注:该场景合并在了 c02_s03 院子中 + "c02_s11": "res://scene/ground/scene/c02/s11_一楼火灾.tscn", # 注:该场景合并在了 c02_s03 院子中 "c02_s12": "res://scene/ground/scene/c02/s12_盒子猫.tscn", "c02_s13": "res://scene/ground/scene/c02/s13_盒子猫二楼.tscn", "c02_s14": "res://scene/ground/scene/c02/s14_盒子猫二楼内侧.tscn", - "c02_s15": "res://scene/ground/scene/c02/s15_盒子猫一楼内侧.tscn", - "c02_s16": "res://scene/ground/scene/c02/s16_盒子猫三楼内侧.tscn", - "c02_s17": "res://scene/ground/scene/c02/s17_盒子猫三楼.tscn", - "c02_s18": "res://scene/ground/scene/c02/s18_盒子猫一楼.tscn", + "c02_s15": "res://scene/ground/scene/c02/s15_盒子猫一楼内侧.tscn", + "c02_s16": "res://scene/ground/scene/c02/s16_盒子猫三楼内侧.tscn", + "c02_s17": "res://scene/ground/scene/c02/s17_盒子猫三楼.tscn", + "c02_s18": "res://scene/ground/scene/c02/s18_盒子猫一楼.tscn", } -func _ready() -> void: + +func _ready() -> void: mask_layer.layer = GlobalConfig.CANVAS_LAYER_GROUND_MASK mask.visible = true mask.color.a = 0.0 @@ -100,9 +100,16 @@ func toggle_mask(display: bool, mask_color: Color, wait_time: float) -> Tween: tween.tween_property(mask, "color:a", 0.0, duration).set_trans(Tween.TRANS_CUBIC) return tween + func transition_to_scene( scene_name: String, portal: String, wait_time := 1.4, mask_color := Color.BLACK ) -> void: + if ground: + print("GroundLoader transition_to_scene: pause prev ground.") + ground.process_mode = Node.PROCESS_MODE_DISABLED + if GlobalConfig.DEBUG: + # print reenter lock status + print("GroundLoader transition_to_scene: reenter lock status: ", ground.reenter_lock) var scene_path = GROUND_SCENE_PATH_DICT.get(scene_name) if scene_path: current_scene = scene_name @@ -113,14 +120,39 @@ func transition_to_scene( if wait_time > 0.0: # 转场效果,在 _load_ground_node 之前播放 var tween = toggle_mask(true, mask_color, wait_time) - tween.tween_callback(call_deferred.bind("_do_transition", scene_name)) - tween.tween_callback(toggle_mask.bind(false, mask_color, wait_time)) + tween.tween_callback(_do_transition.call_deferred.bind(scene_name)) + tween.tween_callback(_hide_mask_with_frozen_ground.bind(mask_color, wait_time)) else: _do_transition.call_deferred(scene_name) else: print("Scene not found: " + scene_name) +var _frozen_start_time_ms: int +var _freeze_ground_required := false: + set(val): + _freeze_ground_required = val + if ground: + if val: + print("GroundLoader _freeze_ground_required: frozen") + ground.process_mode = Node.PROCESS_MODE_DISABLED + _frozen_start_time_ms = Time.get_ticks_msec() + else: + ground.process_mode = Node.PROCESS_MODE_INHERIT + print( + "GroundLoader _freeze_ground_required: unfrozen. frozen duration(ms):", + Time.get_ticks_msec() - _frozen_start_time_ms + ) + + +func _hide_mask_with_frozen_ground(mask_color: Color, wait_time: float): + # 锁定 ground 状态 + _freeze_ground_required = true + toggle_mask(false, mask_color, wait_time).tween_callback( + func(): _freeze_ground_required = false + ) + + func _update_archive(): ArchiveManager.archive.current_scene = current_scene ArchiveManager.archive.entrance_portal = entrance_portal @@ -138,6 +170,10 @@ func _do_transition(scene_name: String) -> void: # 因为 ground 在 enter_tree 时会用到 SceneManager 的方法 # 其中间接用到了 GroundLoader 的 ground ground = _load_ground_node(scene_name) + if _freeze_ground_required: + ground.process_mode = Node.PROCESS_MODE_DISABLED + print("GroundLoader _freeze_ground_required: frozen (delayed)") + _frozen_start_time_ms = Time.get_ticks_msec() _add_ground() # 预先加载邻居场景 _post_transition() diff --git a/scene/ground/scene/c01/s05_院长房间.tscn b/scene/ground/scene/c01/s05_院长房间.tscn index 0d550021..47d2835a 100644 --- a/scene/ground/scene/c01/s05_院长房间.tscn +++ b/scene/ground/scene/c01/s05_院长房间.tscn @@ -509,7 +509,7 @@ tracks/6/keys = { "times": PackedFloat32Array(0.08), "transitions": PackedFloat32Array(1), "values": [{ -"args": [Vector2(261, 88), false], +"args": [Vector2(261, 88)], "method": &"walk_to" }] } diff --git a/scene/ground/scene/c01/s06_animation.gd b/scene/ground/scene/c01/s06_animation.gd index 3782526b..c653d35c 100644 --- a/scene/ground/scene/c01/s06_animation.gd +++ b/scene/ground/scene/c01/s06_animation.gd @@ -122,17 +122,17 @@ func game_intro() -> void: func _game_counting_down(_res = null): $"Sfx猫鼠游戏".play() - SceneManager.release_player() + DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_猫鼠游戏BGM开始") + await DialogueManager.dialogue_ended # 重置镜头 SceneManager.focus_player_and_reset_zoom(2.5) - DialogueManager.show_dialogue_balloon( - dialogue_c01, "c01_s06_猫鼠游戏", [GlobalConfig.DIALOG_IGNORE_INPUT] - ) + SceneManager.release_player() + DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_猫鼠游戏倒计时") # 禁止玩家向左移动,同时可以使右侧腾出空间,玩家可以继续向右移动 var player = SceneManager.get_player() as MainPlayer var left = player.global_position.x player.player_movement_rect.position.x = left - get_tree().create_timer(2.5).timeout.connect(_kids_start_run) + get_tree().create_timer(2.0).timeout.connect(_kids_start_run) cat.visible = true cat.play("【墙上黑猫】跑步") cat.get_node("猫咪嘶吼音效").play() @@ -273,9 +273,11 @@ func game_restart(): game_kid.global_position.x = kids_start_run_initial_x[2] ground_loader.toggle_mask(false, Color.BLACK, 1.0) await get_tree().create_timer(1.0).timeout + # 开始跑 SceneManager.release_player() $"Sfx猫鼠游戏".set("parameters/switch_to_clip", "Intro") - await get_tree().create_timer(2.0).timeout + DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_猫鼠游戏倒计时") + await get_tree().create_timer(1.5).timeout _kids_start_run() @@ -286,7 +288,6 @@ func game_succeed(): else: game_kid_limp.pause() cat_shadow.pause() - SceneManager.freeze_player(0) transport_player_to_next_scene(true) diff --git a/scene/ground/scene/c01/s06_孤儿院长廊围墙.tscn b/scene/ground/scene/c01/s06_孤儿院长廊围墙.tscn index 57acd841..a5060884 100644 --- a/scene/ground/scene/c01/s06_孤儿院长廊围墙.tscn +++ b/scene/ground/scene/c01/s06_孤儿院长廊围墙.tscn @@ -13,9 +13,9 @@ [ext_resource type="AudioStream" uid="uid://dlsd8wrx3v31f" path="res://asset/audio/sfx/环境音/序章/02_孤儿院走廊.wav" id="5_6mww0"] [ext_resource type="PackedScene" uid="uid://cpc5037mesjl7" path="res://scene/ground/script/c01/s06_踢球男孩.tscn" id="5_erliv"] [ext_resource type="Texture2D" uid="uid://b08jrwtr3dpaq" path="res://asset/art/scene/c01/s06_孤儿院长廊围墙/bg_树干遮挡.png" id="5_rdmp5"] -[ext_resource type="AudioStream" uid="uid://ciuxwa4jivi3m" path="res://asset/audio/sfx/bgm/猫鼠游戏/Intro阶段.wav" id="6_lxxek"] +[ext_resource type="AudioStream" uid="uid://nvnoy6pb1ogy" path="res://asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part1.wav" id="6_lxxek"] [ext_resource type="SpriteFrames" uid="uid://c6okvaeemoodq" path="res://asset/art/gif/c01_孤儿院围墙/c01_孤儿院围墙_frames.tres" id="7_dsj2r"] -[ext_resource type="AudioStream" uid="uid://woqygpidlpp1" path="res://asset/audio/sfx/bgm/猫鼠游戏/Loop阶段.wav" id="7_phfqg"] +[ext_resource type="AudioStream" uid="uid://blrlxkkkf5w84" path="res://asset/audio/sfx/bgm/猫鼠游戏/mx_追逐part2.wav" id="7_phfqg"] [ext_resource type="Script" uid="uid://rq6w1vuhuq1m" path="res://scene/entity/audio/sfx.gd" id="8_1g8pi"] [ext_resource type="PackedScene" uid="uid://b50n0hvs4yh75" path="res://addons/property-inspector/pro_animation_sprite2d/pro_animated_sprite.tscn" id="8_ouldg"] [ext_resource type="Texture2D" uid="uid://f6xl83h8g5mo" path="res://asset/art/scene/c01/s06_孤儿院长廊围墙/【桌椅】 上层遮挡部分.png" id="11_q3ypm"] @@ -164,7 +164,6 @@ metadata/_custom_type_script = "uid://wapo47a1oddf" position = Vector2(490, 36) stream = ExtResource("5_6mww0") autoplay = true -stream_paused = true bus = &"game_sfx" script = ExtResource("4_qq2uh") loop = true @@ -177,7 +176,7 @@ script = ExtResource("8_1g8pi") mode = "BGM" metadata/_custom_type_script = "uid://rq6w1vuhuq1m" -[node name="BGSprite2D" parent="Ground" index="1"] +[node name="BGSprite2D" parent="Ground" index="2"] position = Vector2(0, -3) texture = ExtResource("2_ow3ya") offset = Vector2(0, -155) @@ -637,7 +636,7 @@ range_layer_max = 2 texture = ExtResource("4_6ffae") offset = Vector2(601.5, -0.5) -[node name="MainPlayer" parent="Ground" index="4"] +[node name="MainPlayer" parent="Ground" index="5"] modulate = Color(0.931897, 0.931897, 0.931897, 1) position = Vector2(1575, 91) character = "小小蝶" @@ -727,7 +726,7 @@ offset = Vector2(0, -159) [node name="PlayerLine2D" parent="Ground/ParallaxForeground" index="2"] points = PackedVector2Array(37, 150, 4000, 150) -[node name="DirectionalLight2D" parent="Ground" index="7"] +[node name="DirectionalLight2D" parent="Ground" index="8"] visible = false [node name="书店外" type="Node2D" parent="Ground"] diff --git a/scene/ground/scene/c01/s11_animation.gd b/scene/ground/scene/c01/s11_animation.gd index 169794d8..7bf0365e 100644 --- a/scene/ground/scene/c01/s11_animation.gd +++ b/scene/ground/scene/c01/s11_animation.gd @@ -27,6 +27,8 @@ func _ready() -> void: func _on_ground_ready() -> void: + # 不显示玩家,锁定玩家移动 + SceneManager.freeze_player(0) main_character = $"../DeployLayer/车夫与吕萍" footstep_sfx = $"黄包车Sfx" chapter_sfx = $chapter_sfx diff --git a/scene/ground/scene/c01/s11_黄包车演出.tscn b/scene/ground/scene/c01/s11_黄包车演出.tscn index 74428198..f4cdf09b 100644 --- a/scene/ground/scene/c01/s11_黄包车演出.tscn +++ b/scene/ground/scene/c01/s11_黄包车演出.tscn @@ -179,7 +179,7 @@ mode = "场景背景音" "感应玩家操作" = false metadata/_custom_type_script = "uid://rq6w1vuhuq1m" -[node name="BGSprite2D" parent="Ground" index="1"] +[node name="BGSprite2D" parent="Ground" index="2"] position = Vector2(-12, 2) texture = ExtResource("8_yajus") offset = Vector2(-4, -627) @@ -538,15 +538,13 @@ position = Vector2(-59, 48) [node name="CollisionShape2D" type="CollisionShape2D" parent="Ground/AmbientLayer/路灯序列2/路灯9/Area2D"] shape = SubResource("RectangleShape2D_jd8t2") -[node name="MainPlayer" parent="Ground" index="4"] +[node name="MainPlayer" parent="Ground" index="5"] visible = false position = Vector2(26, 118) catty_light_energy = 1.0 character = "小小蝶" -action_locked = true -action_freezed = true -[node name="CameraFocusMarker" parent="Ground" index="5" node_paths=PackedStringArray("focusing_node")] +[node name="CameraFocusMarker" parent="Ground" index="6" node_paths=PackedStringArray("focusing_node")] focusing_node = NodePath("../DeployLayer/车夫与吕萍") force_offset = Vector2(50, -48) diff --git a/scene/ground/scene/c02/s02_animation.gd b/scene/ground/scene/c02/s02_animation.gd index fd82fade..cbc5aaf7 100644 --- a/scene/ground/scene/c02/s02_animation.gd +++ b/scene/ground/scene/c02/s02_animation.gd @@ -63,6 +63,14 @@ func _oneshot_wind(): $"冷飕飕Sfx".play() +func _on_wind_finished(): + set_data("first_enter", true) + %MainPlayer.hide_sprite = false + wind_blows.visible = false + # 使用气泡文字 + SceneManager.pop_os_with_str("c02_冷飕飕的", false, true) + + func xiaochan_disappear(): var xc = $"../DeployLayer/Ambush小蝉闪现/小蝉" as AnimatedSprite2D xc.play() @@ -79,14 +87,6 @@ func _on_flyer_exit(arg): SceneManager.pop_debug_dialog_info("程序", "发放 steam 成就") -func _on_wind_finished(): - set_data("first_enter", true) - %MainPlayer.hide_sprite = false - wind_blows.visible = false - # 使用气泡文字 - SceneManager.pop_os_with_str("c02_冷飕飕的", false, true) - - func lumber_interacted(): SceneManager.call_deferred("enable_prop_item", "prop_火柴") SceneManager.get_inspector().quit_and_hidden.connect(_on_inspector_quit, CONNECT_ONE_SHOT) @@ -104,7 +104,6 @@ func _on_blink_finished(blink_sprite): func _on_music_box_exited(_arg): - SceneManager.release_player() if 5 <= ArchiveManager.get_global_value("c02_musicbox_stage"): _display_paper_man(false) # _display_paper_man(true) @@ -127,14 +126,6 @@ func _on_try_exit(): SceneManager.release_player() -func display_music_box(): - # 展示八音盒 - music_box.visible = true - SceneManager.freeze_player(0) - # TODO 打开音效 - SceneManager.pop_debug_dialog_info("音效", "显示八音盒") - - func check_if_show_shoes(): # 不论是否推出,都需要 enable 调整为 false $"../DeployLayer/Ambush推小鞋子".enabled = false diff --git a/scene/ground/scene/c02/s02_过道.tscn b/scene/ground/scene/c02/s02_过道.tscn index 08c16825..4456b16c 100644 --- a/scene/ground/scene/c02/s02_过道.tscn +++ b/scene/ground/scene/c02/s02_过道.tscn @@ -73,7 +73,7 @@ script = ExtResource("5_36l5t") autoplay_group = &"c02_楼道1" metadata/_custom_type_script = "uid://cpejxlfni6n52" -[node name="BGSprite2D" parent="Ground" index="1"] +[node name="BGSprite2D" parent="Ground" index="2"] self_modulate = Color(0.831373, 0.886275, 0.956863, 1) position = Vector2(-1, 0) scale = Vector2(0.5, 0.5) @@ -245,14 +245,14 @@ texture = SubResource("GradientTexture2D_fvldj") position = Vector2(880, 121) texture = SubResource("GradientTexture2D_fvldj") -[node name="MainPlayer" parent="Ground" index="4"] +[node name="MainPlayer" parent="Ground" index="5"] position = Vector2(53, 98) facing_direction = Vector2(1, 0) [node name="PlayerLine2D" parent="Ground/ParallaxForeground" index="2"] points = PackedVector2Array(37, 150, 670, 150) -[node name="DirectionalLight2D" parent="Ground" index="7"] +[node name="DirectionalLight2D" parent="Ground" index="8"] visible = false energy = 0.8 blend_mode = 1 diff --git a/scene/ground/scene/c02/s03_animation.gd b/scene/ground/scene/c02/s03_animation.gd index 9936c652..b38aef61 100644 --- a/scene/ground/scene/c02/s03_animation.gd +++ b/scene/ground/scene/c02/s03_animation.gd @@ -247,7 +247,7 @@ func bully_end(): SceneManager.release_player() # #TODO 小猫玩具微亮 # SceneManager.pop_debug_dialog_info("美术", "手中小猫玩具微亮") - SceneManager.pop_os_with_str("c02_霸凌救小蝉开始", true, true) + SceneManager.pop_os_with_str("c02_霸凌救小蝉开始") # 准备好点火 ArchiveManager.set_global_entry("c02_ready_to_fire", true) GlobalFunctor.c02_fire_count_down_try_start() diff --git a/scene/ground/scene/c02/s03_院子.tscn b/scene/ground/scene/c02/s03_院子.tscn index 69dd7002..afb86306 100644 --- a/scene/ground/scene/c02/s03_院子.tscn +++ b/scene/ground/scene/c02/s03_院子.tscn @@ -304,7 +304,7 @@ script = ExtResource("6_lq23y") autoplay_group = &"c02_楼道2" metadata/_custom_type_script = "uid://cpejxlfni6n52" -[node name="BGSprite2D" parent="Ground" index="1"] +[node name="BGSprite2D" parent="Ground" index="2"] light_mask = 5 texture = ExtResource("3_sqv8l") @@ -496,6 +496,7 @@ hook_os_key = "c02_院子_要下雨" position = Vector2(809, 75) sign_mark_offset = Vector2(0, -16.88) enabled = false +action_key = 4 prop_key = "prop_小鞋子2" [node name="Sprite2D" type="Sprite2D" parent="Ground/DeployLayer/Pickable小鞋子"] @@ -598,7 +599,7 @@ position = Vector2(2037, 67) sprite_frames = ExtResource("4_gd6xp") animation = &"疯子看井" frame_progress = 0.298829 -walk_to_edge_width = -1.0 +snap_to_edge = false action_key = 3 height = 49.11 collision_width_and_x = Vector2(37.08, 0) @@ -943,7 +944,7 @@ energy = 1.2 range_item_cull_mask = 4 texture = SubResource("GradientTexture2D_plfv5") -[node name="MainPlayer" parent="Ground" index="4"] +[node name="MainPlayer" parent="Ground" index="5"] position = Vector2(2128, 93) facing_direction = Vector2(1, 0) @@ -963,7 +964,7 @@ scale = Vector2(1.08, 1.08) [node name="PlayerLine2D" parent="Ground/ParallaxForeground" index="2"] points = PackedVector2Array(37, 150, 2250, 150) -[node name="DirectionalLight2D" parent="Ground" index="7"] +[node name="DirectionalLight2D" parent="Ground" index="8"] visible = false energy = 0.6 blend_mode = 1 diff --git a/scene/ground/scene/c02/s04_animation.gd b/scene/ground/scene/c02/s04_animation.gd index 98fe3e29..1d5b3dd5 100644 --- a/scene/ground/scene/c02/s04_animation.gd +++ b/scene/ground/scene/c02/s04_animation.gd @@ -33,8 +33,8 @@ func _on_little_hand_first_interacted() -> void: # 9 小手交互,吓摔倒 little_hand.enabled = false var duration = 3.0 - SceneManager.pop_os_with_str(tr("c02_小手出现摔倒"), false, false) SceneManager.freeze_player(duration, 9) + SceneManager.pop_os_with_str(tr("c02_小手出现摔倒"), false, false) get_tree().create_timer(1.5).timeout.connect($"Sfx摔倒".play) await get_tree().create_timer(duration).timeout SceneManager.release_player() diff --git a/scene/ground/scene/c02/s04_保卫科.tscn b/scene/ground/scene/c02/s04_保卫科.tscn index 6de7d98f..d69631fb 100644 --- a/scene/ground/scene/c02/s04_保卫科.tscn +++ b/scene/ground/scene/c02/s04_保卫科.tscn @@ -50,7 +50,7 @@ script = ExtResource("5_g8amr") autoplay_group = &"c02_房间里1" metadata/_custom_type_script = "uid://cpejxlfni6n52" -[node name="BGSprite2D" parent="Ground" index="1"] +[node name="BGSprite2D" parent="Ground" index="2"] light_mask = 5 position = Vector2(47, 2) texture = ExtResource("3_66gue") @@ -121,7 +121,7 @@ offset_bottom = -19.0 [node name="小手讨东西" parent="Ground/DeployLayer" index="7" instance=ExtResource("10_a43aq")] position = Vector2(295, -6) -[node name="MainPlayer" parent="Ground" index="4"] +[node name="MainPlayer" parent="Ground" index="5"] position = Vector2(447, 98) facing_direction = Vector2(-1, 0) @@ -133,7 +133,7 @@ texture = ExtResource("6_tio43") [node name="PlayerLine2D" parent="Ground/ParallaxForeground" index="2"] points = PackedVector2Array(70, 150, 495, 150) -[node name="DirectionalLight2D" parent="Ground" index="7"] +[node name="DirectionalLight2D" parent="Ground" index="8"] visible = false energy = 0.9 blend_mode = 1 diff --git a/scene/ground/scene/c02/s06_二楼.tscn b/scene/ground/scene/c02/s06_二楼.tscn index 54e48423..05bf37be 100644 --- a/scene/ground/scene/c02/s06_二楼.tscn +++ b/scene/ground/scene/c02/s06_二楼.tscn @@ -874,7 +874,7 @@ bus = &"game_sfx" script = ExtResource("4_2e08x") metadata/_custom_type_script = "uid://rq6w1vuhuq1m" -[node name="BGSprite2D" parent="Ground" index="1"] +[node name="BGSprite2D" parent="Ground" index="2"] light_mask = 5 position = Vector2(0, -2) texture = ExtResource("3_och2w") @@ -1143,7 +1143,7 @@ texture = ExtResource("37_osg51") collision_width_and_x = Vector2(150, 0) hook_method = "glimpse_hide_out" -[node name="MainPlayer" parent="Ground" index="4"] +[node name="MainPlayer" parent="Ground" index="5"] position = Vector2(63, 95) catty_light_energy = 0.5 facing_direction = Vector2(1, 0) @@ -1156,7 +1156,7 @@ texture = ExtResource("5_26mqt") [node name="PlayerLine2D" parent="Ground/ParallaxForeground" index="2"] points = PackedVector2Array(37, 150, 900, 150) -[node name="DirectionalLight2D" parent="Ground" index="7"] +[node name="DirectionalLight2D" parent="Ground" index="8"] visible = false energy = 0.9 blend_mode = 1 diff --git a/scene/ground/scene/c02/s12_animation.gd b/scene/ground/scene/c02/s12_animation.gd index fa714e35..cb9fae47 100644 --- a/scene/ground/scene/c02/s12_animation.gd +++ b/scene/ground/scene/c02/s12_animation.gd @@ -18,7 +18,7 @@ func _on_ground_ready() -> void: func _intro(): - SceneManager.lock_player() + SceneManager.get_lock().lock_all() # var player = SceneManager.get_player() as MainPlayer var player = %MainPlayer as MainPlayer player.hide_sprite = true @@ -38,5 +38,5 @@ func _intro(): layer.disable_crawl = false anim.visible = false player.hide_sprite = false - SceneManager.unlock_player() + SceneManager.get_lock().unlock_all() SceneManager.pop_center_notification(tr("ui_boxcat_press_s")) diff --git a/scene/ground/scene/c02/s12_盒子猫.tscn b/scene/ground/scene/c02/s12_盒子猫.tscn index 20d068a9..b124d113 100644 --- a/scene/ground/scene/c02/s12_盒子猫.tscn +++ b/scene/ground/scene/c02/s12_盒子猫.tscn @@ -32,12 +32,12 @@ script = ExtResource("5_72mc1") autoplay_group = &"c02_房间里1" metadata/_custom_type_script = "uid://cpejxlfni6n52" -[node name="BGSprite2D" parent="Ground" index="1"] +[node name="BGSprite2D" parent="Ground" index="2"] texture = ExtResource("3_oskpk") offset = Vector2(0, -103.7) [node name="portal_left" parent="Ground/DeployLayer" index="0"] -position = Vector2(152, 56) +position = Vector2(151, 54) target_scene = "c02_s17" target_portal = "1" status = "opened" @@ -50,12 +50,12 @@ position = Vector2(211, 3) sprite_frames = ExtResource("5_ycgng") animation = &"猫钻进盒子" -[node name="MainPlayer" parent="Ground" index="4"] +[node name="MainPlayer" parent="Ground" index="5"] position = Vector2(231, 71) character = "盒子猫" facing_direction = Vector2(1, 0) -[node name="CameraFocusMarker" parent="Ground" index="5"] +[node name="CameraFocusMarker" parent="Ground" index="6"] force_offset = Vector2(-20, 0) [node name="FGSprite2D" parent="Ground/ParallaxForeground/FGParallaxLayer" index="0"] @@ -64,7 +64,7 @@ position = Vector2(3584, -7) [node name="PlayerLine2D" parent="Ground/ParallaxForeground" index="2"] points = PackedVector2Array(37, 150, 400, 150) -[node name="DirectionalLight2D" parent="Ground" index="7"] +[node name="DirectionalLight2D" parent="Ground" index="8"] blend_mode = 1 [node name="盒子猫CanvasLayer" parent="Ground" instance=ExtResource("4_vv3sh")] diff --git a/scene/ground/script/c02/s00_煤油灯.tscn b/scene/ground/script/c02/s00_煤油灯.tscn index 8fa24dc0..cbfcb67b 100644 --- a/scene/ground/script/c02/s00_煤油灯.tscn +++ b/scene/ground/script/c02/s00_煤油灯.tscn @@ -91,7 +91,5 @@ unique_name_in_owner = true unique_name_in_owner = true script = ExtResource("13_l338h") radius = 3.0 -delay_arrived = 0.1 action_on_arrived = 4 -delay_after_action = 0.4 metadata/_custom_type_script = "uid://cnt01hiw52bmn" diff --git a/scene/ground/script/c02/小手讨东西.gd b/scene/ground/script/c02/小手讨东西.gd index 7f49a39a..efd020f9 100644 --- a/scene/ground/script/c02/小手讨东西.gd +++ b/scene/ground/script/c02/小手讨东西.gd @@ -184,7 +184,7 @@ func _on_interacted() -> void: # 7 拿起纸杯 8 监听纸杯 SceneManager.freeze_player(0, 7) await SceneManager.get_player().animation_finished - SceneManager.freeze_player(0, 8) + SceneManager.player_action(8) SceneManager.pop_debug_dialog_info("音效", "纸杯电话童谣") sfx_bgm.play() # 交互时,已经在对话中 diff --git a/scene/ground/script/c02/小手讨东西.tscn b/scene/ground/script/c02/小手讨东西.tscn index 76f0abba..d2c86cdc 100644 --- a/scene/ground/script/c02/小手讨东西.tscn +++ b/scene/ground/script/c02/小手讨东西.tscn @@ -18,7 +18,7 @@ [sub_resource type="RectangleShape2D" id="RectangleShape2D_yatcw"] resource_local_to_scene = true -size = Vector2(10, 70) +size = Vector2(20, 70) [node name="小手讨东西" type="Sprite2D"] texture = ExtResource("1_47cqy") @@ -120,8 +120,6 @@ texture = ExtResource("10_47cqy") [node name="SignSnapper" type="Marker2D" parent="."] unique_name_in_owner = true script = ExtResource("15_lr23o") -release_player_on_arrived = false -delay_arrived = 0.1 +radius = 3.0 action_on_arrived = 4 -delay_after_action = 0.4 metadata/_custom_type_script = "uid://cnt01hiw52bmn"