手掌指针

This commit is contained in:
2026-10-09 15:28:00 +08:00
parent bbb0c5db14
commit bc88fef43a
8 changed files with 246 additions and 3 deletions
+26
View File
@@ -12,9 +12,17 @@ extends Node
## 投掷初速度(米/秒):按 Q 甩出去时给物体的速度大小。
@export var throw_speed: float = 12.0
## 交互状态变化时发出。
## hovering = 准心正指着可拖拽的刚体(还没抓);holding = 正抓着东西。
## Player 接住这个信号去切准心外观。只在两者之一变化时发,避免每帧刷 UI。
signal interact_state_changed(hovering: bool, holding: bool)
var _current: RigidBody3D = null
var _ray: RayCast3D
var _hold_pos: Marker3D
## 上一次发出的状态,用来只在「变化那一刻」发信号。
var _hovering: bool = false
var _holding: bool = false
## 由 Player 在 _ready() 注入依赖。
@@ -42,6 +50,7 @@ func _unhandled_input(event: InputEvent) -> void:
## 用速度把物体拽向持握点,而不是直接改 global_position ——
## 这样它仍会和场景里其他刚体正常碰撞,不会被硬塞进墙里。
func physics_step() -> void:
_update_interact_state()
# 用 is_instance_valid 而不是 `== null`:物体可能在拖拽途中被 destroy,
# 那种情况下引用不是 null 而是「已被释放」,直接取 global_position 会报错。
if not is_instance_valid(_current) or not is_instance_valid(_hold_pos):
@@ -50,6 +59,23 @@ func physics_step() -> void:
_current.set_linear_velocity(to_hold * pick_power)
## 检测「指着可拖拽物 / 正抓着东西」这两个状态,**只在变化时**发信号。
## 每帧都发会让 UI 无谓重绘,所以这里自己记着上一次的结果。
func _update_interact_state() -> void:
if _ray == null:
return
# 主动刷新一次:RayCast3D 的结果通常滞后于本帧的 move_and_slide,
# 不强制更新的话,跑动中瞄到物体要慢一帧才亮。
_ray.force_raycast_update()
var hovering := _ray.get_collider() is RigidBody3D
var holding := is_instance_valid(_current)
if hovering == _hovering and holding == _holding:
return
_hovering = hovering
_holding = holding
interact_state_changed.emit(_hovering, _holding)
func _grab() -> void:
if _ray == null:
return