extends Node enum VIBE { NORAML, MYSTERY, DANGEROUS, TOUCHING, } @export var first_entered = true func _ready(): process_mode = Node.PROCESS_MODE_ALWAYS # get_tree().node_added.connect("_on_node_added") #### Ground and Loader #### func get_ground_loader() -> GroundLoader: return get_node_or_null("/root/Main/GroundLoader") as GroundLoader # restart scene in debug launch... func is_restarting() -> bool: var ground = get_ground() if ground: return ground.restarting return false func get_ground() -> Ground2D: var loader = get_ground_loader() if loader: return loader.ground return get_tree().current_scene.get_node_or_null("Ground") func get_camera_marker() -> CameraFocusMarker: var ground = get_ground() if ground: return ground.camera_focus_marker return null func get_player() -> MainPlayer: var ground = get_ground() if ground: return ground.player return null func focus_node(node: Node2D, duration := 0.0) -> void: var marker = get_camera_marker() if marker: marker.focus_node(node, duration) func focus_player_and_reset_zoom(duration := 1.2) -> void: var marker = get_camera_marker() if marker: # marker.force_offset = Vector2.ZERO marker.tween_zoom(1.0, duration) # 运镜更平滑一些 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 unlock_player(): var player = get_player() if player: player.action_locked = false # func is_palyer_operational() -> bool: # var player = get_player() as MainPlayer # if not player: # return true # return player.operational # func set_player_operational(val := true): # var player = get_player() as MainPlayer # if player: # player.operational = val # 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(): var player = get_player() if player: player.release_player() 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 camera_marker.limit_right = rect.position.x + rect.size.x camera_marker.limit_top = rect.position.y camera_marker.limit_bottom = rect.position.y + rect.size.y func set_player_boundary(rect: Rect2) -> void: var player = get_player() if player: player.player_movement_rect = rect else: printerr("Player node not found") var balloon_node func pop_debug_dialog_info(character: String, content: String): if GlobalConfig.DEBUG: if not is_instance_valid(balloon_node): balloon_node = preload("res://scene/dialog/balloon_debug.tscn").instantiate() var title = "title" var body = "~ " + title + "\n" body += character + ": " + content + "\n" body += "=> END" var res = DialogueManager.create_resource_from_text(body) DialogueManager.show_dialogue_balloon_scene(balloon_node, res, title) #### Prop #### func get_prop_hud() -> PropHud: return get_node_or_null("/root/Main/UILayer/PropHUD") as PropHud func toggle_hud_display(display_hud: bool): var prop_hud = get_prop_hud() as PropHud if prop_hud: if display_hud: prop_hud.display_hud() else: prop_hud.hide_hud() else: printerr("toggle_hud_display: PropHud node not found") func checkout_prop_inventory(inv): var prop_hud = get_prop_hud() as PropHud if prop_hud: prop_hud.checkout_inventory(inv) else: printerr("checkout_prop_inventory: PropHud node not found") func get_current_prop(must_selected: bool) -> String: var prop_hud = get_prop_hud() if prop_hud and (not must_selected or prop_hud.selected): return prop_hud.inventory.current_item_key() return "" func has_prop(prop_key: String) -> bool: var prop_hud = get_prop_hud() if prop_hud: return prop_hud.inventory.enabled_items.has(prop_key) return false # 静默增加 prop,一般用于提前保存数据,确保数据一致性(防止在 await 时退出等导致丢数据) func enable_prop_item_silently(prop_key: String) -> void: var prop_hud = get_prop_hud() if prop_hud: prop_hud.enable_prop_item(prop_key, false) else: printerr("enable_prop_item_silently: PropHud node not found") func enable_prop_item(prop_key: String) -> void: var prop_hud = get_prop_hud() if prop_hud: prop_hud.enable_prop_item(prop_key) else: printerr("enable_prop_item PropHud node not found") func enable_important_item(prop_key: String) -> void: var prop_hud = get_prop_hud() if prop_hud: prop_hud.inventory.enable_important_item(prop_key) SceneManager.pop_center_notification(tr("ui_important_item_update")) else: printerr("enable_important_item PropHud node not found") func disable_prop_item(prop_key: String) -> void: var prop_hud = get_prop_hud() if prop_hud: prop_hud.disable_prop_item(prop_key) else: printerr("disable_prop_item PropHud node not found") func pop_os_with_str(translation_key: String, auto_freeze := true, auto_release := true) -> Tween: 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) else: printerr("Player node not found") return create_tween() func pop_notification(msg: String, number := 1) -> void: var notification_node = get_node_or_null("/root/Main/UILayer/Notification") if notification_node: notification_node.show_notification(msg, number) elif GlobalConfig.DEBUG: # debug 模式,新建一个 var n = _create_debug_notification() n.call_deferred("show_notification", msg, number) else: printerr("pop_notification: Notification node not found") func pop_center_notification(msg: String) -> void: var notification_node = get_node_or_null("/root/Main/UILayer/Notification") if notification_node: notification_node.show_center_notification(msg) elif GlobalConfig.DEBUG: # debug 模式,新建一个 var n = _create_debug_notification() n.call_deferred("show_center_notification", msg) else: printerr("pop_center_notification: Notification node not found") func pop_center_texture(texture: Texture2D, duration := 3.5) -> void: var notification_node = get_node_or_null("/root/Main/UILayer/Notification") if notification_node: notification_node.show_center_texture(texture, duration) elif GlobalConfig.DEBUG: # debug 模式,新建一个 var n = _create_debug_notification() n.call_deferred("show_center_texture", texture) else: printerr("pop_center_texture: Notification node not found") # debug 模式,新建一个 notification node func _create_debug_notification() -> Notification: if not GlobalConfig.DEBUG: return null var main = get_node_or_null("/root/Main") if not main: main = Control.new() main.set_anchors_preset(Control.PRESET_FULL_RECT) main.name = "Main" get_tree().root.call_deferred("add_child", main) var n = preload("res://scene/notification/notification.tscn").instantiate() main.add_child(n) return n func pop_dialog( character: String, content: String, character_color := "orange", content_color := "white", duration := 2.5 ) -> void: var dialog_node = get_node_or_null("/root/Main/UILayer/Dialog") if dialog_node: dialog_node.append_dialog(character, content, character_color, content_color, duration) else: printerr("Dialog node not found") # func pop_note(note: String, note_color := "white", duration := 2.5) -> void: # var dialog_node = get_node_or_null("/root/Main/UILayer/Dialog") # if dialog_node: # dialog_node.append_note(note, note_color, duration) # else: # printerr("Dialog node not found") func get_inspector() -> PropInspector: return get_node_or_null("/root/Main/PropInspector") as PropInspector func checkout_index_page(transition := true): ArchiveManager.save_all() if transition: var ground = get_ground() if ground: var tween = create_tween() tween.tween_property(ground, "modulate:a", 0.0, 1.0) tween.tween_callback(_jump_back_to_index_and_quit_main) else: _jump_back_to_index_and_quit_main() else: _jump_back_to_index_and_quit_main() var packed_index_page := preload("res://scene/index_page.tscn") func _jump_back_to_index_and_quit_main(): # 技术问题:DialogueManager 中 do SceneManager.checkout_index_page()时,checkout scene 原本 /root/Main 节点未被删除 # * 原本除 standalone 的节点外,只有 /root/Main (current_scene) # * checkout 后,/root 下同时存在 Index 页面节点与 Main 节点 # * 导致 Camera 仍旧在 Main 下,仍旧可以切换道具,但是玩家不能移动(玩家 Input 失效) # * 手动 queue_free 原 Main 节点可行 # * 阅读 SceneTree 的 cpp 源码,change_scene_to_packed 看似无异常 # 问题出现在 Ground 中 get_node("/root").add_child(main) # 需要再指定 current_scene: get_tree().current_scene = main get_tree().change_scene_to_packed(packed_index_page) # var main = get_node_or_null("/root/Main") # if main: # main.queue_free() var prop_bag = preload("res://scene/prop/prop_bag.tscn") func show_bag(): get_node("/root/Main").add_child(prop_bag.instantiate()) func quit_game(): ArchiveManager.save_all() get_tree().quit()