mcpField
U
unity-physics

unity-physics

github.com/gamedev-skills开发5.4k6.3k 次安装1 天前更新
代码仓库

关于 unity-physics

面向 Unity 6.3 LTS 开发者的 3D 物理技能,介绍 Rigidbody、碰撞体与 PhysX 的常用操作,重点说明 FixedUpdate 和碰撞配置。

主要功能

  1. 01使用力与速度驱动物体
  2. 02区分碰撞与触发器回调
  3. 03通过图层管理碰撞关系
  4. 04使用射线检测地面或视线
  5. 05用关节连接物理对象

适用场景

  1. 01实现刚体移动与跳跃
  2. 02检测角色着地或物体重叠
  3. 03设置物体间的碰撞规则
  4. 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。

核心工作流

  1. 为需要模拟的物体添加 Rigidbody;为可能被碰撞的物体添加 Collider。发生碰撞时,双方都必须有 Collider,且至少一方有 Rigidbody。
  2. 在 FixedUpdate 中处理所有物理逻辑。 在 Update 中读取输入并保存意图,然后在 FixedUpdate 中施加力/设置 linearVelocity/调用 MovePosition。
  3. 通过物理 API 移动物体,而不是操作 Transform。 使用 AddForce、linearVelocity 或 MovePosition——不要为非运动学 Rigidbody 赋值 transform.position(这会导致物体瞬移并破坏碰撞解析)。
  4. 选择碰撞或触发器。 实体碰撞会阻挡物体并调用 OnCollisionEnter;勾选了 Is Trigger 的 Collider 会允许物体穿过,并调用 OnTriggerEnter。
  5. 使用层管理交互。 将物体放到不同层,并编辑 Layer Collision Matrix(Project Settings → Physics),避免互不相关的物体相互检测。
  6. 验证设置:使用 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