From bbb0c5db148117e52d966ae0cfbbeef462002fc8 Mon Sep 17 00:00:00 2001 From: yvmou_ Date: Fri, 9 Oct 2026 15:17:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=89=20Q=20=E6=8A=95=E6=8E=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .workbuddy/memory/2026-10-09.md | 5 +++++ character/player/player_pickup.gd | 30 ++++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/.workbuddy/memory/2026-10-09.md b/.workbuddy/memory/2026-10-09.md index 232f1fc..08a16f1 100644 --- a/.workbuddy/memory/2026-10-09.md +++ b/.workbuddy/memory/2026-10-09.md @@ -26,3 +26,8 @@ - 加了 `Input.mouse_mode != MOUSE_MODE_CAPTURED` 早退,并在 `player.gd` 重新锁定鼠标那一支补 `get_viewport().set_input_as_handled()`,避免「点一下重新锁定鼠标」顺带抓起物体(两种分支执行顺序下都成立)。 - `physics_step()` 与 `has_object()` 改用 `is_instance_valid()` —— 防止拖拽途中物体被 destroy 时取属性报错。 - `_drop()` 保留线速度(松手有惯性 / 可甩出);想要「就地放下」需补 `set_linear_velocity(Vector3.ZERO)`。 + +### 按 Q 投掷 +- `player_pickup.gd` 接入 `throw_carry`(Q 键)→ `_throw()`:取 `-_hold_pos.global_transform.basis.z` 作投掷方向(持握点挂在摄像机下且仅有平移,其 basis 即视线朝向,故无需再注入摄像机),`set_linear_velocity(dir * throw_speed)` 后置 `_current = null`。 +- 新增导出参数 `throw_speed: float = 12.0`。 +- 备选手感(注释里留了行):改用 `apply_central_impulse` 则重物飞得慢。 diff --git a/character/player/player_pickup.gd b/character/player/player_pickup.gd index c73ef77..d20ad90 100644 --- a/character/player/player_pickup.gd +++ b/character/player/player_pickup.gd @@ -1,13 +1,16 @@ class_name PlayerPickup extends Node -## 拾取组件:**按住左键拖拽,松手放下**。 -## 按下时用射线抓起正前方的 RigidBody3D,按住期间持续吸在 InteractionPos 前, -## 松开左键即放开。只管「抓 / 拖 / 放」,不碰移动与视角。 +## 拾取组件:**按住左键拖拽,松手放下,按 Q 朝准心方向甩出去**。 +## 按下左键时用射线抓起正前方的 RigidBody3D,按住期间持续吸在 InteractionPos 前; +## 松开左键即原地放开,按 Q 则沿视线方向把手上的物体甩出去。 +## 只管「抓 / 拖 / 放 / 甩」,不碰移动与视角。 ## ## 接法:Player 下挂一个普通 Node,脚本挂上去;由 Player._ready() 注入射线与持握点。 ## 拖拽力度:物体被拉向持握点的速度系数。越大跟手越紧,但过大容易来回抖。 @export var pick_power: float = 10.0 +## 投掷初速度(米/秒):按 Q 甩出去时给物体的速度大小。 +@export var throw_speed: float = 12.0 var _current: RigidBody3D = null var _ray: RayCast3D @@ -21,16 +24,18 @@ 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() 每物理帧持续吸住。 + # 长按拖拽:按下抓起,松开放下;拖拽途中按 Q 可以把手上的东西甩出去。 + # 按住期间不需要任何输入处理 —— 物体靠 physics_step() 每物理帧持续吸住。 if event.is_action_pressed("carry"): _grab() elif event.is_action_released("carry"): _drop() + elif event.is_action_pressed("throw_carry"): + _throw() ## 每物理帧由 Player 调用一次,排在 move_and_slide() 之后。 @@ -60,6 +65,19 @@ func _drop() -> void: _current = null +## 按 Q 投掷:沿视线方向把物体甩出去,随后立刻松手。 +func _throw() -> void: + if not is_instance_valid(_current) or not is_instance_valid(_hold_pos): + return + # 持握点挂在摄像机下、且只有平移没有旋转,所以它的 basis 就是视线朝向, + # 其 -Z 即「准心正前方」。这样不必再给组件注入一台摄像机。 + var dir := -_hold_pos.global_transform.basis.z + _current.set_linear_velocity(dir * throw_speed) + # 想让手感更「物理」(重物飞得慢、轻物飞得远)可以换成给冲量: + # _current.apply_central_impulse(dir * throw_speed) + _current = null + + ## 当前是否抓着东西。调试用,也方便以后加「搬运时不能开枪」这类规则。 func has_object() -> bool: return is_instance_valid(_current)