class_name WorkZone extends Node2D # ============================================================================ # WorkZone.gd - 打工区场景控制器 # ============================================================================ # 承载赛博打工区概念地图,负责玩家出生点和相机边界配置。 # ============================================================================ const CAMERA_ZOOM: Vector2 = Vector2(2.0, 2.0) const CAMERA_LIMIT_LEFT: int = -1280 const CAMERA_LIMIT_TOP: int = -960 const CAMERA_LIMIT_RIGHT: int = 1280 const CAMERA_LIMIT_BOTTOM: int = 960 const MALL_PANEL_SCENE: PackedScene = preload("res://scenes/ui/mall/MallPanel.tscn") const COURSE_BOARD_PANEL_SCENE: PackedScene = preload("res://scenes/ui/CourseBoardPanel.tscn") const MALL_ENTRANCE_POSITION: Vector2 = Vector2(-4, -418) const MALL_ENTRANCE_SIZE: Vector2 = Vector2(112, 34) const MALL_EXIT_POSITION: Vector2 = Vector2(-4, -310) const MALL_EXIT_REOPEN_COOLDOWN: float = 0.45 const PLAYER_COLLISION_LAYER: int = 1 @onready var player: PlayerController = $YSortWorld/Characters/Players/Player @onready var playerCamera: Camera2D = $YSortWorld/Characters/Players/Player/Camera2D @onready var uiLayer: CanvasLayer = $UILayer var _mallPanel: Control var _courseBoardPanel: Control var _mallEntranceArea: Area2D var _isInsideMall: bool = false var _mallCanEnter: bool = true func _ready() -> void: _apply_spawn_point() _configure_camera() _ensure_mall_panel() _ensure_course_board_panel() _ensure_mall_entrance_area() EventSystem.connect_event(EventNames.OBJECT_INTERACTED, _on_object_interacted, self) EventSystem.connect_event(EventNames.MALL_CLOSED, _on_mall_closed, self) _discover_destination() _report_task_map_visit() func _report_task_map_visit() -> void: var taskManager := get_node_or_null("/root/TaskManager") if taskManager != null and taskManager.has_method("report_activity"): taskManager.call("report_activity", "map_visited", "work_zone") func _discover_destination() -> void: var destination_id := SceneManager.get_next_destination_id() if destination_id.is_empty(): destination_id = "work_entrance" var socialManager := get_node_or_null("/root/SocialManager") if socialManager != null and socialManager.has_method("discover_destination"): socialManager.call("discover_destination", destination_id) func _exit_tree() -> void: EventSystem.disconnect_event(EventNames.OBJECT_INTERACTED, _on_object_interacted, self) EventSystem.disconnect_event(EventNames.MALL_CLOSED, _on_mall_closed, self) func _apply_spawn_point() -> void: if player.has_scene_position_override: return var spawnName: String = SceneManager.get_next_spawn_name() var markerName: String = spawnName if not spawnName.is_empty() else "DefaultSpawn" var marker := $Markers.get_node_or_null(markerName) as Marker2D if marker == null: marker = $Markers/DefaultSpawn player.global_position = marker.global_position func _configure_camera() -> void: playerCamera.zoom = CAMERA_ZOOM playerCamera.position_smoothing_enabled = true playerCamera.limit_left = CAMERA_LIMIT_LEFT playerCamera.limit_top = CAMERA_LIMIT_TOP playerCamera.limit_right = CAMERA_LIMIT_RIGHT playerCamera.limit_bottom = CAMERA_LIMIT_BOTTOM playerCamera.limit_smoothed = true func _ensure_mall_panel() -> void: var existingPanel := uiLayer.get_node_or_null("MallPanel") as Control if existingPanel != null: _mallPanel = existingPanel return _mallPanel = MALL_PANEL_SCENE.instantiate() as Control _mallPanel.name = "MallPanel" uiLayer.add_child(_mallPanel) func _ensure_course_board_panel() -> void: var existingPanel := uiLayer.get_node_or_null("CourseBoardPanel") as Control if existingPanel != null: _courseBoardPanel = existingPanel return _courseBoardPanel = COURSE_BOARD_PANEL_SCENE.instantiate() as Control _courseBoardPanel.name = "CourseBoardPanel" uiLayer.add_child(_courseBoardPanel) func _ensure_mall_entrance_area() -> void: var areas := get_node_or_null("InteractionAreas") as Node2D if areas == null: areas = Node2D.new() areas.name = "InteractionAreas" add_child(areas) var entrance := areas.get_node_or_null("MallEntranceArea") as WorkZoneBuildingArea if entrance == null: entrance = WorkZoneBuildingArea.new() entrance.name = "MallEntranceArea" areas.add_child(entrance) entrance.buildingId = "whale_super_mall" entrance.buildingTitle = "鲸鱼商城" entrance.buildingRole = "mall" entrance.position = MALL_ENTRANCE_POSITION var shape := entrance.get_node_or_null("CollisionShape2D") as CollisionShape2D if shape == null: shape = CollisionShape2D.new() shape.name = "CollisionShape2D" entrance.add_child(shape) var rectangle := shape.shape as RectangleShape2D if rectangle == null: rectangle = RectangleShape2D.new() shape.shape = rectangle shape.position = Vector2.ZERO rectangle.size = MALL_ENTRANCE_SIZE _setup_mall_entrance_trigger(entrance) func _setup_mall_entrance_trigger(entrance: Area2D) -> void: _mallEntranceArea = entrance _mallEntranceArea.collision_mask = 0 func _on_object_interacted(data: Dictionary) -> void: var buildingId := str(data.get("buildingId", "")) if buildingId.is_empty(): return if buildingId == "whale_super_mall": _enter_mall() return if buildingId == "virtual_whale_recruitment_board": _open_course_board() return if buildingId == "whale_job_center": var taskBook := get_node_or_null("/root/TaskBookPanel") if taskBook != null and taskBook.has_method("show_panel"): taskBook.call("show_panel") return if not [ "whale_job_center", "ai_service_station", "whale_coin_exchange", "virtual_whale_recruitment_board", ].has(buildingId): return var title := str(data.get("title", buildingId)) var role := str(data.get("role", "")) print("WorkZone interaction ready: %s (%s)" % [title, role]) func _open_course_board() -> void: if is_instance_valid(_courseBoardPanel) and _courseBoardPanel.has_method("show_panel"): _courseBoardPanel.call("show_panel") func _on_mall_entrance_body_entered(body: Node2D) -> void: return func _enter_mall() -> void: if _isInsideMall: return _isInsideMall = true _set_player_mall_transition_state(true) if is_instance_valid(_mallPanel) and _mallPanel.has_method("show_panel"): _mallPanel.call("show_panel") func _on_mall_closed(_data: Dictionary = {}) -> void: if not _isInsideMall: return _isInsideMall = false _mallCanEnter = false player.global_position = MALL_EXIT_POSITION if player.has_method("_reset_movement_input_state"): player.call("_reset_movement_input_state") _set_player_mall_transition_state(false) await get_tree().create_timer(MALL_EXIT_REOPEN_COOLDOWN).timeout _mallCanEnter = true func _set_player_mall_transition_state(isInsideMall: bool) -> void: if not is_instance_valid(player): return player.visible = not isInsideMall player.set_physics_process(not isInsideMall) player.velocity = Vector2.ZERO if player.has_method("_reset_movement_input_state"): player.call("_reset_movement_input_state")