Initial WhaleTown V2 frontend
This commit is contained in:
103
scenes/characters/CafeCompanionTarget.gd
Normal file
103
scenes/characters/CafeCompanionTarget.gd
Normal file
@@ -0,0 +1,103 @@
|
||||
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
|
||||
Reference in New Issue
Block a user