mcpField
U
unity-physics

unity-physics

github.com/nice-wolf-studio开发4071 次安装7 周前更新
代码仓库

关于 unity-physics

面向 Unity 开发者的物理系统参考技能,整理 3D 与 2D 物理、刚体、碰撞体、射线检测、关节及常见实现模式。

主要功能

  1. 013D 与 2D 物理概览
  2. 02刚体配置与力的施加
  3. 03碰撞体、触发器与碰撞回调
  4. 04射线、形状投射与重叠查询
  5. 05关节类型与常见用途

适用场景

  1. 01选择合适的刚体移动方式
  2. 02排查触发器事件未触发
  3. 03为高速物体配置碰撞检测
  4. 04使用非分配查询减少 GC

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/nice-wolf-studio/unity-claude-skills --skill unity-physics

安装后在 Claude Code 中输入/unity-physics确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
character-controller.md
physics2d-api.md
physics3d-api.md

详细介绍

Unity Physics

物理系统概览

Unity 针对不同项目需求提供了不同的物理引擎集成:

  • 3D 物理(PhysX):适用于面向 3D 对象项目的 Nvidia PhysX 引擎集成
  • 2D 物理(Box2D):经过优化的 2D 物理系统,配备专用组件
  • 两种系统都会模拟重力、碰撞、力和约束
物理时序

物理系统通过 FixedUpdate 以固定时间步运行,与渲染帧率分开:

void FixedUpdate()
{
    // All physics code belongs here, not in Update()
    rb.AddForce(Vector3.forward * speed);
}

关键时序规则:

  • FixedUpdate 按固定间隔运行(默认 0.02s / 50Hz)
  • 每帧可能调用多次 FixedUpdate,也可能一次都不调用
  • Time.fixedDeltaTime 控制时间间隔
  • 使用 Update 处理输入,使用 FixedUpdate 施加物理力
模拟模式

Physics.simulationMode 控制物理引擎何时执行步进:

  • FixedUpdate(默认):每个固定时间步自动进行模拟
  • Update:每帧模拟一次
  • Script:通过 Physics.Simulate() 手动控制

Rigidbody 配置

Rigidbody 组件会让 GameObject 受物理引擎控制。刚体不会在物理力作用下变形或改变形状。

关键属性
属性描述默认值
mass质量,单位为 kg;会影响力的相互作用1
linearDamping对线性速度的阻力0
angularDamping对角速度的阻力0.05
useGravity此刚体是否受重力影响true
isKinematic若为 true,则不受物理力驱动false
interpolation平滑物理步进之间的视觉抖动None
collisionDetectionMode碰撞检测算法Discrete
移动方法
Rigidbody rb = GetComponent<Rigidbody>();

// Apply continuous force (call in FixedUpdate)
rb.AddForce(Vector3.forward * 10f);
rb.AddForce(Vector3.up * 5f, ForceMode.Impulse);

// Apply torque
rb.AddTorque(Vector3.up * 2f);

// Apply force at a world position (creates both force and torque)
rb.AddForceAtPosition(Vector3.forward * 10f, hitPoint);

// Kinematic movement (use for isKinematic=true bodies)
rb.MovePosition(rb.position + direction * speed * Time.fixedDeltaTime);
rb.MoveRotation(targetRotation);
ForceMode 选项
模式描述
ForceMode.Force持续施加力,会使用质量(默认)
ForceMode.Acceleration持续施加力,不考虑质量
ForceMode.Impulse瞬时施加力,会使用质量
ForceMode.VelocityChange瞬时施加力,不考虑质量
休眠状态

当 Rigidbody 的能量低于休眠阈值时,物理引擎会停止计算它。可使用 rb.Sleep() 和 rb.WakeUp() 手动控制。

缩放警告

Unity 假定 1 个世界单位 = 1 米。缩放不正确会导致不真实的物理行为。请保持 GameObject 的比例符合现实。


碰撞体与触发器

碰撞体是定义 GameObject 物理边界的不可见形状,无需与可视网格匹配。

碰撞体类别
类别描述
静态碰撞体仅有碰撞体,没有 Rigidbody。用于不可移动的几何体(墙壁、地板)。
动态 Rigidbody 碰撞体碰撞体 + Rigidbody(isKinematic=false)。完全参与模拟。
运动学 Rigidbody 碰撞体碰撞体 + Rigidbody(isKinematic=true)。通过脚本移动。
碰撞体形状
  • 基本形状:BoxCollider、SphereCollider、CapsuleCollider——效率高,可自动缩放
  • 复合形状:在子 GameObject 上组合多个基本形状,构成复杂形状
  • MeshCollider:与精确网格几何形状匹配;开销较大,请谨慎使用
  • WheelCollider:基于射线检测,内置车辆物理
  • TerrainCollider:与地形高度图匹配
触发器碰撞体

触发器会检测重叠的碰撞体,但不会产生物理碰撞响应:

// Set via Inspector: Collider > Is Trigger = true
// Or via script:
GetComponent<BoxCollider>().isTrigger = true;

触发器事件的要求:

  • 至少有一个 GameObject 必须带有 Rigidbody
  • 碰撞体必须启用 isTrigger
  • 每个重叠对都需要各自的 Rigidbody,才能单独检测
物理材质

碰撞体支持 PhysicsMaterial,可调整摩擦力和弹性属性,以控制表面交互。


射线检测

射线检测会投射不可见的射线,以检测场景中的碰撞体。

Physics.Raycast
// Basic: check if anything is ahead
Vector3 fwd = transform.TransformDirection(Vector3.forward);
if (Physics.Raycast(transform.position, fwd, 10))
    Debug.Log("Something ahead!");

// With hit info
RaycastHit hit;
if (Physics.Raycast(transform.position, -Vector3.up, out hit, 100.0f))
    Debug.Log("Distance to ground: " + hit.distance);

// With layer mask
int layerMask = 1 << LayerMask.NameToLayer("Enemies");
if (Physics.Raycast(origin, direction, out hit, maxDist, layerMask))
    Debug.Log("Hit enemy: " + hit.collider.gameObject.name);

// Mouse-to-world raycast
Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
if (Physics.Raycast(ray, out hit, 100))
    Debug.DrawLine(ray.origin, hit.point);
RaycastHit 属性
属性类型说明
pointVector3世界空间中的命中位置
normalVector3命中点处的表面法线
distancefloat与射线起点的距离
colliderCollider被命中的碰撞体
transformTransform被命中对象的 Transform
其他投射方法
方法说明
Physics.RaycastAll()返回射线上的所有交点
Physics.RaycastNonAlloc()填充预分配缓冲区(不分配 GC 内存)
Physics.SphereCast()沿指定方向扫掠球体
Physics.BoxCast()沿指定方向扫掠盒体
Physics.CapsuleCast()沿指定方向扫掠胶囊体
Physics.Linecast()检查两点之间是否存在碰撞体
重叠查询(无方向,区域检查)
方法说明
Physics.OverlapSphere()查找球体范围内的所有碰撞体
Physics.OverlapBox()查找盒体范围内的所有碰撞体
Physics.OverlapCapsule()查找胶囊体范围内的所有碰撞体
Physics.CheckSphere()如果有任何碰撞体与球体重叠,则返回 true
Physics.CheckBox()如果有任何碰撞体与盒体重叠,则返回 true
Physics.CheckCapsule()如果有任何碰撞体与胶囊体重叠,则返回 true
QueryTriggerInteraction

控制投射/重叠查询是否检测触发器碰撞体:

  • QueryTriggerInteraction.UseGlobal -- 使用 Physics.queriesHitTriggers
  • QueryTriggerInteraction.Collide -- 始终检测触发器
  • QueryTriggerInteraction.Ignore -- 从不检测触发器

碰撞检测

碰撞检测模式
模式说明使用场景
Discrete在每个物理步结束时检查碰撞。效率高。大多数对象的默认模式
Continuous在整个物理步内检查碰撞。可防止穿透。快速移动的对象撞击静态几何体
Continuous Dynamic对静态和动态碰撞体都进行连续检测快速移动的对象撞击其他快速移动的对象
Continuous Speculative使用推测性接触进行预测性 CCD运动学刚体、通用 CCD
碰撞回调
void OnCollisionEnter(Collision other) {  // First frame of contact
    if (other.gameObject.CompareTag("Player"))
        Debug.Log("Player hit this object");
}
void OnCollisionStay(Collision other) { }  // Every physics frame while touching
void OnCollisionExit(Collision other) { }  // Contact ended
触发器回调
void OnTriggerEnter(Collider other) {  // Entered trigger volume
    if (other.CompareTag("Player"))
        Debug.Log("Player entered trigger zone");
}
void OnTriggerStay(Collider other) {   // Each frame inside trigger
    other.attachedRigidbody?.AddForce(Vector3.up * 12f, ForceMode.Acceleration);
}
void OnTriggerExit(Collider other) { } // Left trigger volume
碰撞矩阵
对象对碰撞事件触发器事件
静态 + 动态是--
静态 + 运动学否--
静态 + 静态否--
动态 + 动态是--
动态 + 运动学是--
运动学 + 运动学否--
触发器 + 动态/运动学--是
静态触发器 + 动态/运动学--是

碰撞事件要求至少有一个动态(非运动学)Rigidbody。物理引擎只会对带有 Rigidbody 或 ArticulationBody 组件的 GameObject 施加力。


关节

关节用于将 Rigidbody 组件彼此连接,或连接到空间中的固定点。

关节类型说明使用场景
FixedJoint将两个刚体锁定在一起(通过弹簧实现)连接对象、可断开的连接
HingeJoint绕单一轴旋转门、摆锤、链条
SpringJoint保持距离的弹性连接蹦极绳、系绳
CharacterJoint带角度约束的球窝关节布娃娃(髋部、肩部)
ConfigurableJoint完全可自定义的约束各种特殊连接
关节属性
  • Connected Body:另一个 Rigidbody(null = 固定到世界)
  • Anchor / Connected Anchor:局部空间中的连接点
  • Break Force / Break Torque:用于断开关节的阈值
  • Enable Preprocessing:稳定关节模拟

对于要求精确关节运动的工业/机器人应用,请使用 ArticulationBody,而不是常规关节。


2D 物理差异

Unity 的 2D 物理使用独立的引擎,针对 2D 工作流进行了优化。

方面3D2D
引擎PhysXBox2D
刚体RigidbodyRigidbody2D
碰撞体ColliderCollider2D
物理类PhysicsPhysics2D
向量Vector3Vector2
旋转四元数(3 个轴)float(仅 Z 轴)
重力Vector3Vector2
力模式ForceModeForceMode2D
Rigidbody2D 刚体类型
类型说明
Dynamic完全模拟,会对力和重力做出响应
Kinematic通过脚本移动,可检测碰撞,但不受力影响
Static不可移动,用于关卡几何体
2D 碰撞体类型

BoxCollider2D、CircleCollider2D、CapsuleCollider2D、PolygonCollider2D、EdgeCollider2D、CompositeCollider2D、TilemapCollider2D

2D 专属功能
  • Effectors 2D:用于力交互的 Area、Buoyancy、Platform、Point、Surface effectors
  • Constant Force 2D:施加持续的力 / 扭矩
  • Physics Material 2D:摩擦和弹跳属性
  • LowLevelPhysics2D API:独立的底层物理路径

完整的 2D API 详情请参阅参考文件 references/physics2d-api.md。


常见模式

使用 Rigidbody 移动玩家
public class PlayerMovement : MonoBehaviour
{
    public float moveSpeed = 5f;
    public float jumpForce = 7f;

    private Rigidbody rb;
    private bool jumpRequested;

    void Awake()
    {
        rb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        // Capture input in Update (legacy Input Manager; see unity-input for new Input System)
        if (Input.GetButtonDown("Jump"))
            jumpRequested = true;
    }

    void FixedUpdate()
    {
        // Apply physics in FixedUpdate (legacy Input; see unity-input)
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Vector3 move = new Vector3(h, 0f, v) * moveSpeed;
        rb.linearVelocity = new Vector3(move.x, rb.linearVelocity.y, move.z);

        if (jumpRequested)
        {
            rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
            jumpRequested = false;
        }
    }
}
使用 SphereCast 检查是否接地
// Cache collider reference in Awake() -- avoid GetComponent in hot paths
private CapsuleCollider capsule;
void Awake() => capsule = GetComponent<CapsuleCollider>();

public bool IsGrounded()
{
    float radius = 0.3f;
    return Physics.SphereCast(transform.position, radius, Vector3.down,
        out _, (capsule.height / 2f) - radius + 0.1f,
        LayerMask.GetMask("Ground"));
}
使用触发器的悬浮垫
public class HoverPad : MonoBehaviour
{
    public float hoverForce = 12f;

    void OnTriggerStay(Collider other)
    {
        if (other.attachedRigidbody != null)
            other.attachedRigidbody.AddForce(Vector3.up * hoverForce, ForceMode.Acceleration);
    }
}
非分配型射线检测(零 GC)
private readonly RaycastHit[] hits = new RaycastHit[10];

void DetectEnemies()
{
    int count = Physics.RaycastNonAlloc(transform.position, transform.forward,
        hits, 50f, LayerMask.GetMask("Enemies"));
    for (int i = 0; i < count; i++)
        Debug.Log("Hit: " + hits[i].collider.name);
}

反模式

不要使用 Update 施加物理力
// BAD: Forces applied at variable frame rate cause inconsistent behavior
void Update()
{
    rb.AddForce(Vector3.forward * 10f); // WRONG
}

// GOOD: Use FixedUpdate for physics
void FixedUpdate()
{
    rb.AddForce(Vector3.forward * 10f); // CORRECT
}
不要使用 Transform 移动 Rigidbody
// BAD: Bypasses physics, breaks collision detection
transform.position += Vector3.forward * speed * Time.deltaTime; // WRONG

// GOOD: Use Rigidbody methods
rb.MovePosition(rb.position + Vector3.forward * speed * Time.fixedDeltaTime); // CORRECT
// Or apply forces:
rb.AddForce(Vector3.forward * speed);
基元足以满足需求时,不要使用 MeshCollider

在简单的盒状对象上使用 MeshCollider 很浪费。改用 BoxCollider,开销低得多,而且对于简单形状同样准确。仅在复杂的凹形几何体上使用 MeshCollider。

不要在物理回调中分配内存
// BAD: GC allocation every collision
void OnCollisionEnter(Collision other) {
    var enemies = GameObject.FindGameObjectsWithTag("Enemy"); // WRONG
}
// GOOD: Cache in Start(), reuse in callbacks
不要在射线检测中忽略图层蒙版
Physics.Raycast(origin, direction, out hit);                        // BAD: hits everything
Physics.Raycast(origin, direction, out hit, 100f,
    LayerMask.GetMask("Ground", "Obstacles"));                      // GOOD: filtered

核心 API 速查

类别主要成员
Physics(静态)Raycast、RaycastAll、RaycastNonAlloc、SphereCast、BoxCast、CapsuleCast、Linecast、OverlapSphere、OverlapBox、CheckSphere、CheckBox、ClosestPoint、ComputePenetration、Simulate、SyncTransforms
Physics 属性gravity、defaultContactOffset、bounceThreshold、sleepThreshold、defaultSolverIterations、queriesHitTriggers、queriesHitBackfaces、simulationMode
Rigidbodymass、linearDamping、angularDamping、useGravity、isKinematic、linearVelocity、angularVelocity、interpolation、collisionDetectionMode、AddForce()、AddTorque()、MovePosition()、MoveRotation()、Sleep()、WakeUp()
回调OnCollisionEnter(Collision)、OnCollisionStay、OnCollisionExit、OnTriggerEnter(Collider)、OnTriggerStay、OnTriggerExit

完整的方法签名、参数和重载请参阅 references/physics3d-api.md。 完整的 2D 物理 API 请参阅 references/physics2d-api.md。


CharacterController

对于非物理驱动的角色移动(FPS 控制器、NPC),请使用 CharacterController 而不是 Rigidbody。它无需进行物理模拟即可处理斜坡、台阶和碰撞滑动。完整的 API、模式以及 CharacterController 与 Rigidbody 的比较,请参阅 references/character-controller.md。

相关技能

  • unity-foundations —— GameObject 层级、组件、变换、图层
  • unity-scripting —— MonoBehaviour 生命周期(Update 与 FixedUpdate)、协程
  • unity-2d —— 2D 游戏开发模式、精灵渲染

Additional Resources

评论

支持 Markdown