unity-physics

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Unity Physics (Rigidbody / PhysX)

Unity 物理系统(Rigidbody / PhysX)

Make objects move, collide, and detect each other with Unity 6's built-in 3D physics (PhysX). Get the
FixedUpdate
discipline, trigger-vs-collision rules, and collision layers right. Targets Unity 6 (6000.0 LTS).
Unity 6 rename:
Rigidbody.velocity
is now
Rigidbody.linearVelocity
(the old name is deprecated). Code copied from older tutorials will warn or fail to compile.
借助Unity 6内置的3D物理系统(PhysX),让物体实现移动、碰撞与相互检测。掌握
FixedUpdate
的使用规范、触发器与碰撞的规则,以及碰撞层的设置。本文针对 Unity 6(6000.0 LTS) 版本。
Unity 6 命名变更:
Rigidbody.velocity
现已更名为
Rigidbody.linearVelocity
(旧名称已被弃用)。从旧教程复制的代码会触发警告或无法编译。

When to use

使用场景

  • Use when giving an object physical motion (forces, velocity, gravity), responding to collisions or triggers, setting up collision layers/masks, raycasting for ground checks or line-of-sight, or connecting bodies with joints.
  • Use when scenes/prefabs contain
    Rigidbody
    +
    Collider
    components.
When not to use: 2D physics (
Rigidbody2D
,
Collider2D
) is a separate API — adapt the concepts but the types differ. Cross-engine feel tuning (timestep, jitter, tunnelling) →
physics-tuning
. Reading input that drives movement →
unity-input-system
.
  • 适用于为物体添加物理运动(力、速度、重力)、响应碰撞或触发器、设置碰撞层/遮罩、通过射线投射进行地面检测或视野检测,或使用关节连接物体的场景。
  • 适用于场景/预制件包含
    Rigidbody
    +
    Collider
    组件的情况。
不适用于: 2D物理系统(
Rigidbody2D
Collider2D
)是独立的API——概念可借鉴但类型不同。跨引擎的手感调优(时间步长、抖动、穿模)请参考
physics-tuning
。驱动移动的输入读取请参考
unity-input-system

Core workflow

核心工作流程

  1. Add a
    Rigidbody
    to anything that should be simulated; add a
    Collider
    to anything that should be hit. A collision needs a
    Collider
    on both, and at least one
    Rigidbody
    .
  2. Do all physics in
    FixedUpdate
    .
    Read input in
    Update
    , store intent, then apply forces / set
    linearVelocity
    / call
    MovePosition
    in
    FixedUpdate
    .
  3. Move bodies through the physics API, not the Transform. Use
    AddForce
    ,
    linearVelocity
    , or
    MovePosition
    — never assign
    transform.position
    to a non-kinematic Rigidbody (it teleports and breaks collision resolution).
  4. Pick collision vs trigger. A solid collision blocks and calls
    OnCollisionEnter
    ; a
    Collider
    with
    Is Trigger
    checked passes through and calls
    OnTriggerEnter
    .
  5. Organise interactions with layers. Put objects on layers and edit the Layer Collision Matrix (Project Settings → Physics) so unrelated things don't test against each other.
  6. Verify with the Physics Debugger (Window → Analysis → Physics Debugger) and by watching for jitter; if fast objects pass through walls, raise Collision Detection mode.
  1. 为需要物理模拟的物体添加
    Rigidbody
    组件
    ;为需要被碰撞检测的物体添加
    Collider
    组件。碰撞需要双方都有
    Collider
    ,且至少一方带有
    Rigidbody
  2. 所有物理操作都在
    FixedUpdate
    中执行
    。在
    Update
    中读取输入、存储意图,然后在
    FixedUpdate
    中施加力 / 设置
    linearVelocity
    / 调用
    MovePosition
  3. 通过物理API移动物体,而非直接修改Transform。使用
    AddForce
    linearVelocity
    MovePosition
    ——绝不要为非运动学刚体直接赋值
    transform.position
    (这会导致物体瞬移并破坏碰撞检测)。
  4. 选择碰撞或触发模式。实体碰撞会阻挡物体并调用
    OnCollisionEnter
    ;勾选
    Is Trigger
    Collider
    会允许物体穿过并调用
    OnTriggerEnter
  5. 通过层管理交互。将物体分配到不同层,编辑层碰撞矩阵(项目设置 → 物理),让无关物体不进行碰撞检测。
  6. 验证效果:使用物理调试器(窗口 → 分析 → 物理调试器)并观察是否有抖动;如果快速移动的物体穿过墙体,提高碰撞检测模式等级。

Patterns

实现模式

1. Force-based movement in
FixedUpdate
(with a speed clamp)

1. 在
FixedUpdate
中基于力的移动(带速度限制)

csharp
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: 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
(continuous, mass-scaled),
Acceleration
(continuous, ignores mass),
Impulse
(instant, mass-scaled — jumps),
VelocityChange
(instant, ignores mass).
csharp
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: 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. Collision vs trigger callbacks

2. 碰撞与触发回调

csharp
// 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);
}
csharp
// 实体碰撞:双方都有碰撞器,当前物体带有(非运动学)Rigidbody。
private void OnCollisionEnter(Collision col)
{
    Debug.Log($"Hit {col.gameObject.name} at {col.contacts[0].point}");
}

// 重叠检测:其中一个碰撞器的'Is Trigger'设为true。至少一方需要带有Rigidbody。
private void OnTriggerEnter(Collider other)
{
    if (other.CompareTag("Pickup")) Destroy(other.gameObject);
}

3. Ground check with a layer-masked raycast

3. 使用层遮罩的射线投射地面检测

csharp
[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);
}
csharp
[SerializeField] private LayerMask groundMask;   // 在检视面板中设置为你的"Ground"层

private bool IsGrounded()
{
    // 向下投射短射线;仅检测groundMask层上的碰撞器。
    return Physics.Raycast(transform.position, Vector3.down, out RaycastHit hit,
                           1.1f, groundMask);
}

4. Kinematic platform that still pushes bodies

4. 仍能推动物体的运动学平台

csharp
// 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));
csharp
// 运动学Rigidbody:不由力驱动,但MovePosition会进行插值并正确带动静止在其上的物体
// (不同于直接移动Transform)。
private void FixedUpdate() => _rb.MovePosition(_rb.position + Vector3.right * (2f * Time.fixedDeltaTime));

Pitfalls

常见陷阱

  • Rigidbody.velocity
    doesn't exist in Unity 6
    — use
    linearVelocity
    (and
    angularVelocity
    is unchanged).
  • Setting
    transform.position
    on a dynamic Rigidbody
    — teleports it, skips collision. Use
    MovePosition
    (kinematic/interpolated) or apply forces.
  • Applying forces in
    Update
    — frame-rate-dependent and jittery. Physics goes in
    FixedUpdate
    .
  • Trigger callbacks never fire — triggers need a
    Rigidbody
    on at least one of the two colliders, and both colliders enabled; two static triggers don't report overlaps.
  • Fast objects pass through walls (tunnelling) — set the Rigidbody's Collision Detection to
    Continuous
    (or
    Continuous Dynamic
    ) for bullets/fast movers.
  • Non-uniform-scaled
    MeshCollider
    s or scaled colliders
    misbehave; prefer primitive colliders and keep scale uniform.
  • Everything collides with everything — wasted cost; assign layers and prune the Layer Collision Matrix.
  • Unity 6中不存在
    Rigidbody.velocity
    ——请使用
    linearVelocity
    angularVelocity
    保持不变)。
  • 为动态Rigidbody设置
    transform.position
    ——会导致物体瞬移,跳过碰撞检测。请使用
    MovePosition
    (运动学/插值模式)或施加力。
  • Update
    中施加力
    ——帧率依赖且会产生抖动。物理操作应放在
    FixedUpdate
    中。
  • 触发回调从未触发——触发器需要至少一方带有
    Rigidbody
    ,且双方碰撞器都启用;两个静态触发器不会报告重叠。
  • 快速移动的物体穿过墙体(穿模)——将刚体的碰撞检测模式设置为
    Continuous
    (或
    Continuous Dynamic
    ),适用于子弹/快速移动的物体。
  • 非均匀缩放的
    MeshCollider
    或缩放后的碰撞器
    会出现异常行为;优先使用基础碰撞器并保持缩放均匀。
  • 所有物体都相互碰撞——会浪费性能;分配层并精简层碰撞矩阵。

References

参考资料

  • For raycast variants (
    SphereCast
    ,
    RaycastAll
    ,
    OverlapSphere
    ,
    LayerMask
    bit math) and joints (
    FixedJoint
    ,
    HingeJoint
    ,
    ConfigurableJoint
    , breakable joints), read
    references/raycasting-and-joints.md
    .
  • Primary docs: Unity Manual "Physics" section and
    ScriptReference/Rigidbody
    ,
    ScriptReference/Physics.Raycast
    .
  • 关于射线投射变体(
    SphereCast
    RaycastAll
    OverlapSphere
    LayerMask
    位运算)和关节(
    FixedJoint
    HingeJoint
    ConfigurableJoint
    、可断裂关节),请阅读
    references/raycasting-and-joints.md
  • 主要文档:Unity手册“物理”章节以及
    ScriptReference/Rigidbody
    ScriptReference/Physics.Raycast

Related skills

相关技能

  • physics-tuning
    — engine-agnostic feel: fixed timestep, mass/drag, CCD, stability.
  • unity-csharp-scripting
    — the
    FixedUpdate
    /
    Update
    split these patterns rely on.
  • unity-navmesh
    — agent movement that is not force-driven.
  • physics-tuning
    ——引擎无关的手感调优:固定时间步长、质量/阻力、CCD、稳定性。
  • unity-csharp-scripting
    ——这些模式依赖的
    FixedUpdate
    /
    Update
    拆分机制。
  • unity-navmesh
    ——非基于力驱动的Agent移动。