修改为长按拖拽

This commit is contained in:
2026-10-09 15:14:23 +08:00
parent 66d87d48d6
commit 3920b88041
4 changed files with 34 additions and 13 deletions
+3
View File
@@ -53,6 +53,9 @@ func _unhandled_input(event: InputEvent) -> void:
elif event is InputEventMouseButton and event.pressed \
and Input.mouse_mode != Input.MOUSE_MODE_CAPTURED:
set_mouse_captured(true)
# 吃掉这一下点击:它的意义只是「把鼠标锁回游戏」,
# 不该顺带触发拾取 —— 否则重新聚焦时会凭空抓起一个物体。
get_viewport().set_input_as_handled()
func set_mouse_captured(captured: bool) -> void:
+2 -2
View File
@@ -33,11 +33,11 @@ shape = SubResource("CapsuleShape3D_rkbax")
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0)
[node name="Camera" type="Camera3D" parent="CameraRig" unique_id=52294557]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.6066488, -0.11179829)
transform = Transform3D(5, 0, 0, 0, 5, 0, 0, 0, 5, 0, -0.6916404, -0.11179829)
[node name="InteractionRay" type="RayCast3D" parent="CameraRig/Camera" unique_id=388601766]
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, 0, 0)
target_position = Vector3(0, 0.45, 0)
target_position = Vector3(0, 0.5, 0)
[node name="InteractionPos" type="Marker3D" parent="CameraRig/Camera" unique_id=816323614]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.44393378)
+22 -11
View File
@@ -1,11 +1,12 @@
class_name PlayerPickup
extends Node
## 拾取组件:射线看中的 RigidBody3D 会被吸附到 InteractionPos 前。
## 只管「拿 / 放 / 拖」,不碰移动与视角。
## 拾取组件:**按住左键拖拽,松手放下**。
## 按下时用射线抓起正前方的 RigidBody3D,按住期间持续吸在 InteractionPos 前,
## 松开左键即放开。只管「抓 / 拖 / 放」,不碰移动与视角。
##
## 接法:Player 下挂一个普通 Node,脚本挂上去;由 Player._ready() 注入射线与持握点。
## 拖拽力度:物体被拉向持握点的速度系数
## 拖拽力度:物体被拉向持握点的速度系数。越大跟手越紧,但过大容易来回抖。
@export var pick_power: float = 10.0
var _current: RigidBody3D = null
@@ -20,24 +21,31 @@ func setup(ray: RayCast3D, hold_pos: Marker3D) -> void:
func _unhandled_input(event: InputEvent) -> void:
# 只有鼠标锁进游戏(真正在玩)时才响应拖拽。
# 否则「点一下把鼠标锁回来」的那次点击会顺带抓起一个物体。
if Input.mouse_mode != Input.MOUSE_MODE_CAPTURED:
return
# 长按拖拽:按下抓起,松开放下。
# 中间不需要任何输入处理 —— 物体靠 physics_step() 每物理帧持续吸住。
if event.is_action_pressed("carry"):
if _current == null:
_pick()
else:
_release()
_grab()
elif event.is_action_released("carry"):
_drop()
## 每物理帧由 Player 调用一次,排在 move_and_slide() 之后。
## 用速度把物体拽向持握点,而不是直接改 global_position ——
## 这样它仍会和场景里其他刚体正常碰撞,不会被硬塞进墙里。
func physics_step() -> void:
if _current == null or _hold_pos == null:
# 用 is_instance_valid 而不是 `== null`:物体可能在拖拽途中被 destroy,
# 那种情况下引用不是 null 而是「已被释放」,直接取 global_position 会报错。
if not is_instance_valid(_current) or not is_instance_valid(_hold_pos):
return
var to_hold := _hold_pos.global_position - _current.global_position
_current.set_linear_velocity(to_hold * pick_power)
func _pick() -> void:
func _grab() -> void:
if _ray == null:
return
var collider := _ray.get_collider()
@@ -45,10 +53,13 @@ func _pick() -> void:
_current = collider as RigidBody3D
func _release() -> void:
func _drop() -> void:
# 故意不清零线速度:松手时保留拖动惯性,甩出去的手感更自然。
# 想要「就地放下、不再滑出去」的话,这里补一句:
# if is_instance_valid(_current): _current.set_linear_velocity(Vector3.ZERO)
_current = null
## 当前是否抓着东西。调试用,也方便以后加「搬运时不能开枪」这类规则。
func has_object() -> bool:
return _current != null
return is_instance_valid(_current)