104 lines
3.7 KiB
GDScript
104 lines
3.7 KiB
GDScript
extends Area2D
|
|
class_name CafeCompanionTarget
|
|
|
|
# ============================================================================
|
|
# CafeCompanionTarget.gd - 咖啡店陪伴机器人点击组件
|
|
# ============================================================================
|
|
# 挂在咖啡店 NPC 或被雇佣玩家节点下,负责把鼠标点击转成
|
|
# “选择陪伴机器人”事件;真正聊天必须由付费时长购买后开启。
|
|
# ============================================================================
|
|
|
|
@export var servicePointId: String = ""
|
|
@export var companionId: String = ""
|
|
@export var companionType: String = "npc"
|
|
@export var personaName: String = ""
|
|
@export var ownerUserId: String = ""
|
|
@export var employmentEndsAt: String = ""
|
|
@export var selfTarget: bool = false
|
|
|
|
var _lastClickMsec: int = 0
|
|
|
|
func _ready() -> void:
|
|
input_pickable = true
|
|
set_process_unhandled_input(true)
|
|
|
|
func _input_event(_viewport: Viewport, event: InputEvent, _shapeIdx: int) -> void:
|
|
if not (event is InputEventMouseButton):
|
|
return
|
|
var mouseEvent := event as InputEventMouseButton
|
|
if mouseEvent.button_index != MOUSE_BUTTON_LEFT or not mouseEvent.pressed:
|
|
return
|
|
|
|
get_viewport().set_input_as_handled()
|
|
_try_emit_target_selected()
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
if not (event is InputEventMouseButton):
|
|
return
|
|
var mouseEvent := event as InputEventMouseButton
|
|
if mouseEvent.button_index != MOUSE_BUTTON_LEFT or not mouseEvent.pressed:
|
|
return
|
|
if not _contains_global_point(get_global_mouse_position()):
|
|
return
|
|
|
|
get_viewport().set_input_as_handled()
|
|
_try_emit_target_selected()
|
|
|
|
func _try_emit_target_selected() -> void:
|
|
var now := Time.get_ticks_msec()
|
|
if _lastClickMsec > 0 and now - _lastClickMsec < 120:
|
|
return
|
|
_lastClickMsec = now
|
|
_emit_target_selected()
|
|
|
|
func _emit_target_selected() -> void:
|
|
var eventSystem := get_node_or_null("/root/EventSystem")
|
|
if eventSystem == null:
|
|
return
|
|
|
|
var payload := {
|
|
"cafe_id": "whale_cafe",
|
|
"service_point_id": servicePointId,
|
|
"companion_id": companionId,
|
|
"companion_type": companionType,
|
|
"persona_name": _resolved_persona_name(),
|
|
"owner_user_id": ownerUserId,
|
|
"employment_ends_at": employmentEndsAt,
|
|
"target_path": str(get_parent().get_path()) if get_parent() != null else "",
|
|
}
|
|
eventSystem.call("emit_event", EventNames.CAFE_COMPANION_SELF_SELECTED if selfTarget else EventNames.CAFE_COMPANION_SELECTED, payload)
|
|
|
|
func _resolved_persona_name() -> String:
|
|
var normalizedName := personaName.strip_edges()
|
|
if not normalizedName.is_empty():
|
|
return normalizedName
|
|
var parent := get_parent()
|
|
if parent != null and parent.get("npcName") != null:
|
|
return str(parent.get("npcName")).strip_edges()
|
|
return companionId
|
|
|
|
func _contains_global_point(globalPoint: Vector2) -> bool:
|
|
for child in get_children():
|
|
var shapeNode := child as CollisionShape2D
|
|
if shapeNode == null or shapeNode.disabled or shapeNode.shape == null:
|
|
continue
|
|
if _shape_contains_point(shapeNode, globalPoint):
|
|
return true
|
|
return false
|
|
|
|
func _shape_contains_point(shapeNode: CollisionShape2D, globalPoint: Vector2) -> bool:
|
|
var localPoint := shapeNode.to_local(globalPoint)
|
|
var shape := shapeNode.shape
|
|
if shape is RectangleShape2D:
|
|
var rectangle := shape as RectangleShape2D
|
|
return Rect2(rectangle.size * -0.5, rectangle.size).has_point(localPoint)
|
|
if shape is CircleShape2D:
|
|
var circle := shape as CircleShape2D
|
|
return localPoint.length() <= circle.radius
|
|
if shape is CapsuleShape2D:
|
|
var capsule := shape as CapsuleShape2D
|
|
var halfHeight: float = maxf(0.0, capsule.height * 0.5 - capsule.radius)
|
|
var clampedY: float = clampf(localPoint.y, -halfHeight, halfHeight)
|
|
return Vector2(localPoint.x, localPoint.y - clampedY).length() <= capsule.radius
|
|
return false
|