如何在Unity中实现类似《半条命2》《传送门》的物体拾取功能
Unity传送门风格物体抓取功能修复方案
现有实现的问题
你当前遇到的两个典型异常效果如下:

核心原因分为三点:
- 挂载逻辑错误:你将抓取脚本挂在了全局
Destination锚点对象上,触发逻辑时操作的是锚点本身而非目标抓取物体,导致所有绑定了锚点的物体同时响应 - 无瞄准检测:没有对玩家准星指向的物体做射线检测,按下F键直接全局触发逻辑,没有筛选目标
- 缩放继承异常:直接将抓取物体设为锚点的子物体,当锚点或上层节点有非1缩放时,子物体会继承缩放导致模型变形
修复实现步骤
1. 前置准备
- 删除挂在
Destination空对象上的原有脚本 - 给所有可抓取物体添加
Pickable自定义标签 - 确保所有可抓取物体都带有
Rigidbody组件 - 将
Destination空对象设为玩家主相机的子物体,放在相机前方2-3米位置,锚点和所有上层节点的缩放全部设为(1,1,1)
2. 修改后的脚本
这个脚本挂在玩家主相机上即可:
using UnityEngine; public class PickUp : MonoBehaviour { // 抓取物体的放置锚点,拖拽你的Destination对象到这里 public Transform holdAnchor; // 最大可抓取距离 public float maxPickDistance = 3.5f; // 当前持有的物体刚体 private Rigidbody heldObjectRb; private void Update() { // 按F键切换抓取/放下状态 if (Input.GetKeyDown(KeyCode.F)) { if (heldObjectRb == null) { TryPickUp(); } else { DropObject(); } } // 抓取状态下持续将物体移动到锚点位置 if (heldObjectRb != null) { heldObjectRb.MovePosition(holdAnchor.position); } } // 尝试抓取准星指向的可拾取物体 private void TryPickUp() { Ray pickRay = new Ray(transform.position, transform.forward); if (Physics.Raycast(pickRay, out RaycastHit hitInfo, maxPickDistance)) { // 仅对带Pickable标签且有刚体的物体生效 if (hitInfo.collider.CompareTag("Pickable") && hitInfo.rigidbody != null) { heldObjectRb = hitInfo.rigidbody; heldObjectRb.useGravity = false; heldObjectRb.freezeRotation = true; } } } // 放下当前持有的物体 private void DropObject() { heldObjectRb.useGravity = true; heldObjectRb.freezeRotation = false; // 给物体一个向前的初速度,模拟投掷效果 heldObjectRb.velocity = transform.forward * 6f; heldObjectRb = null; } }
3. 参数配置
- 将相机下挂的
Destination对象拖拽到脚本的holdAnchor字段 - 可根据需求调整
maxPickDistance参数修改最大抓取距离 - 如果抓取时物体有明显晃动,可将可抓取物体刚体组件的
Drag参数调整到10左右
内容的提问来源于stack exchange,提问作者Rainor
相关产品推荐
相关产品推荐

