Files
whale-town-front-v2/scenes/Maps/WorkZone.gd
2026-07-22 00:45:59 +08:00

196 lines
6.9 KiB
GDScript

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")