Initial WhaleTown V2 frontend
This commit is contained in:
176
scenes/Maps/WorkZone.gd
Normal file
176
scenes/Maps/WorkZone.gd
Normal file
@@ -0,0 +1,176 @@
|
||||
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)
|
||||
|
||||
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:
|
||||
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 = PLAYER_COLLISION_LAYER
|
||||
if not _mallEntranceArea.body_entered.is_connected(_on_mall_entrance_body_entered):
|
||||
_mallEntranceArea.body_entered.connect(_on_mall_entrance_body_entered)
|
||||
|
||||
func _on_object_interacted(data: Dictionary) -> void:
|
||||
var buildingId := str(data.get("buildingId", ""))
|
||||
if buildingId.is_empty():
|
||||
return
|
||||
if buildingId == "whale_super_mall":
|
||||
return
|
||||
if buildingId == "virtual_whale_recruitment_board":
|
||||
_open_course_board()
|
||||
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:
|
||||
if body != player or not _mallCanEnter:
|
||||
return
|
||||
_enter_mall()
|
||||
|
||||
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")
|
||||
Reference in New Issue
Block a user