关于 unity-physics
面向 Unity 6.3 LTS 开发者的 3D 物理技能,介绍 Rigidbody、碰撞体与 PhysX 的常用操作,重点说明 FixedUpdate 和碰撞配置。
主要功能
- 01使用力与速度驱动物体
- 02区分碰撞与触发器回调
- 03通过图层管理碰撞关系
- 04使用射线检测地面或视线
- 05用关节连接物理对象
适用场景
- 01实现刚体移动与跳跃
- 02检测角色着地或物体重叠
- 03设置物体间的碰撞规则
- 04制作移动平台或物理连接
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill unity-physics安装后在 Claude Code 中输入/unity-physics确认已加载。
附带文件references/raycasting-and-joints.md
详细介绍
Unity Physics(Rigidbody / PhysX)
使用 Unity 6.3 LTS 内置的 3D 物理系统(PhysX),让物体移动、碰撞并检测彼此。掌握 FixedUpdate 的使用规范、触发器与碰撞规则,以及碰撞层的配置。目标版本为 Unity 6.3 LTS (6000.3)。
Unity 6.3 LTS 重命名:
Rigidbody.velocity现已改为Rigidbody.linearVelocity(旧名称已弃用)。从旧教程中复制的代码会发出警告或无法编译。
适用场景
- 需要让物体产生物理运动(力、速度、重力)、响应碰撞或触发器、设置碰撞层/遮罩、通过射线检测地面或视线,或用关节连接刚体时。
- 场景/预制件包含
Rigidbody和Collider组件时。
不适用场景: 2D 物理(Rigidbody2D、Collider2D)使用的是独立 API——可参考相关概念,但类型不同。跨引擎的手感调优(时间步长、抖动、穿透)→ physics-tuning。读取用于驱动移动的输入 → unity-input-system。
核心工作流
- 为需要模拟的物体添加
Rigidbody;为可能被碰撞的物体添加Collider。发生碰撞时,双方都必须有Collider,且至少一方有Rigidbody。 - 在
FixedUpdate中处理所有物理逻辑。 在Update中读取输入并保存意图,然后在FixedUpdate中施加力/设置linearVelocity/调用MovePosition。 - 通过物理 API 移动物体,而不是操作 Transform。 使用
AddForce、linearVelocity或MovePosition——不要为非运动学Rigidbody赋值transform.position(这会导致物体瞬移并破坏碰撞解析)。 - 选择碰撞或触发器。 实体碰撞会阻挡物体并调用
OnCollisionEnter;勾选了Is Trigger的Collider会允许物体穿过,并调用OnTriggerEnter。 - 使用层管理交互。 将物体放到不同层,并编辑 Layer Collision Matrix(Project Settings → Physics),避免互不相关的物体相互检测。
- 验证设置:使用 Physics Debugger(Window → Analysis → Physics Debugger),并观察是否有抖动;如果快速移动的物体穿过墙壁,请提高 Collision Detection 模式。
模式
1. 在 FixedUpdate 中基于力的移动(含速度上限)
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class Mover : MonoBehaviour
{
[SerializeField] private float accel = 30f, maxSpeed = 8f;
private Rigidbody _rb;
private Vector3 _input; // set from Update / input system
private void Awake() => _rb = GetComponent<Rigidbody>();
private void FixedUpdate()
{
_rb.AddForce(_input * accel, ForceMode.Acceleration); // mass-independent accel
// Unity 6.3 LTS: linearVelocity (was 'velocity'). Clamp horizontal speed.
Vector3 flat = new(_rb.linearVelocity.x, 0, _rb.linearVelocity.z);
if (flat.magnitude > maxSpeed)
{
flat = flat.normalized * maxSpeed;
_rb.linearVelocity = new Vector3(flat.x, _rb.linearVelocity.y, flat.z);
}
}
}
ForceMode:Force(持续施力,受质量影响)、Acceleration(持续施加加速度,不受质量影响)、Impulse(瞬间施力,受质量影响——用于跳跃)、VelocityChange(瞬间改变速度,不受质量影响)。
2. 碰撞与触发器回调
// Solid hit: both have colliders, this one has a (non-kinematic) Rigidbody.
private void OnCollisionEnter(Collision col)
{
Debug.Log($"Hit {col.gameObject.name} at {col.contacts[0].point}");
}
// Overlap: one collider has 'Is Trigger' = true. Requires a Rigidbody on at least one party.
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Pickup")) Destroy(other.gameObject);
}
3. 使用层遮罩进行地面检测
[SerializeField] private LayerMask groundMask; // set to your "Ground" layer in the Inspector
private bool IsGrounded()
{
// Cast a short ray down; only test colliders on groundMask.
return Physics.Raycast(transform.position, Vector3.down, out RaycastHit hit,
1.1f, groundMask);
}
4. 仍能推动其他刚体的运动学平台
// isKinematic Rigidbody: not driven by forces, but MovePosition interpolates and carries
// resting bodies correctly (unlike moving the Transform directly).
private void FixedUpdate() => _rb.MovePosition(_rb.position + Vector3.right * (2f * Time.fixedDeltaTime));
常见问题
- Unity 6.3 LTS 中不存在
Rigidbody.velocity——请使用linearVelocity(angularVelocity保持不变)。 - 对动态 Rigidbody 设置
transform.position——这会使其瞬移并跳过碰撞。请使用MovePosition(运动学/插值)或施加力。如果确实要修改 Transform,物理查询(Raycast、OverlapSphere)会在下一次物理步进前读取到旧位置——在同一帧查询前调用一次Physics.SyncTransforms(),切勿每帧调用。 OnCollisionEnter不会在CharacterController上触发——CharacterController.Move会绕过 Rigidbody 系统;它通过OnControllerColliderHit(ControllerColliderHit)报告命中。不要添加 Rigidbody 来“修复”这个问题——这两者是互斥的移动模式。Physics.Raycast默认忽略触发器——除非传入QueryTriggerInteraction.Collide(或切换全局设置Physics.queriesHitTriggers/项目设置 → Physics → Queries Hit Triggers),否则射线不会报告触发器碰撞体。当射线起点位于目标碰撞体内部时,它也会返回false。- 移动或禁用支撑物后,静止的 Rigidbody 仍会留在原处——低于休眠阈值时,刚体会进入休眠状态。碰撞和
AddForce会自动唤醒它,但通过 Transform 移动静态碰撞体(没有 Rigidbody)时可能不会唤醒,因此地板滑走后,箱子会悬在半空中。请对受影响的刚体调用Rigidbody.WakeUp()。 - 在
Update中施加力——这会导致行为依赖帧率且产生抖动。物理逻辑应放在FixedUpdate中。 - 触发器回调始终不触发——至少一个碰撞体上必须有
Rigidbody,且两个碰撞体都必须启用;两个静态触发器不会报告重叠。 - 快速物体穿过墙壁(隧穿)——提高 Rigidbody 的 Collision Detection 设置,避免使用
Discrete。请注意,Continuous只会检测与静态碰撞体的扫掠(遇到其他动态刚体时会退回到 Discrete);Continuous Dynamic还会检测与其他连续动态刚体的扫掠;Continuous Speculative可处理所有对象,且开销更低。对于子弹,也可以考虑沿轨迹使用SphereCast/Raycast,而不是使用碰撞体。 - 非均匀缩放的
MeshCollider或缩放后的碰撞体可能表现异常;建议使用基本形状碰撞体,并保持缩放均匀。 - 移动刚体上的凹面
MeshCollider——Mesh 碰撞体默认是凹面的,而凹面碰撞体只能是静态或运动学的;两个凹面碰撞体之间不会发生碰撞。对于动态 Rigidbody,请在 MeshCollider 上启用 Convex,或使用基本形状碰撞体构建复合碰撞体。 - 所有物体都与所有物体碰撞——这会造成不必要的开销;请分配图层并精简 Layer Collision Matrix。
参考资料
- 有关射线检测变体(
SphereCast、RaycastAll、OverlapSphere、LayerMask位运算)和关节(FixedJoint、HingeJoint、ConfigurableJoint、可断裂关节),请阅读references/raycasting-and-joints.md。 - 主要文档:Unity 手册中的“Physics”部分,以及
ScriptReference/Rigidbody、ScriptReference/Physics.Raycast。有关新增注意事项,请参阅ScriptReference/CollisionDetectionMode、ScriptReference/Physics-queriesHitTriggers、ScriptReference/MonoBehaviour.OnControllerColliderHit、ScriptReference/Physics.SyncTransforms、ScriptReference/Rigidbody.WakeUp,以及手册页面“Introduction to rigid body physics”(休眠)和“Introduction to Mesh colliders”(凹面与凸面)。
相关技能
physics-tuning——与引擎无关的手感调校:固定时间步长、质量/阻力、CCD、稳定性。unity-csharp-scripting——这些模式所依赖的FixedUpdate/Update分工。unity-navmesh——不由力驱动的 Agent 移动。
评论
支持 Markdown