3、2D 物理系统入门:Rigidbody 2D组件、Collider 2D组件、物理材质、重力与碰撞检测

好,咱们今天来聊聊2D物理系统。说实话,这是很多新手觉得「玄学」的地方——明明代码没写错,角色就是穿墙了,或者跳起来像踩了棉花。别急,我带你把这些组件一个一个捋清楚。

3.1 Rigidbody 2D:让物体动起来的核心

Rigidbody 2D,说白了就是给游戏对象加上「物理身份」。没有它,你的精灵就是个静态图片;加上它,Unity的物理引擎就开始接管了。

关键属性

  • Body Type:有三种模式——Dynamic(动态)、Kinematic(运动学)、Static(静态)。我个人习惯把玩家和怪物设成Dynamic,把移动平台设成Kinematic,墙壁和地面设成Static。
  • Gravity Scale:重力倍数。设为0就是失重状态,我做过一个太空跳跃的小游戏,就把这个值调成了0.3。
  • Linear Drag / Angular Drag:线性阻力和角阻力。数值越大,物体停得越快。嗯,这里要注意,阻力太大角色会像在泥浆里走路。

避坑指南:我曾经犯过一个低级错误——把玩家的Rigidbody 2D的Body Type设成了Static,结果角色怎么按键盘都不动。后来排查了半天才发现,Static物体是不受力和速度影响的。记住:要移动,就用Dynamic或Kinematic。

3.2 Collider 2D:碰撞的「边界」

Collider 2D定义了物体的碰撞形状。没有它,两个Rigidbody 2D就会互相穿透,像幽灵一样。

常用类型

  • Box Collider 2D:矩形碰撞体,适合墙壁、箱子、平台。
  • Circle Collider 2D:圆形碰撞体,适合球类、角色头部。
  • Polygon Collider 2D:多边形碰撞体,适合不规则形状。我建议慎用,因为顶点太多会消耗性能。
  • Edge Collider 2D:边缘碰撞体,适合悬崖、斜坡边缘。

你想想看,如果一个角色明明是个圆形,你却用Box Collider,那它卡在墙角时就会显得很别扭。所以选对形状很重要。

小技巧:在Inspector面板里,点击Collider组件上的「Edit Collider」按钮,可以手动拖拽调整碰撞体的大小和偏移。我经常用这个功能来微调,让碰撞体比实际图片小一圈,这样玩家操作时手感会更「宽容」。

3.3 物理材质:控制摩擦与弹性

物理材质(Physics Material 2D)决定了物体表面的物理特性。说白了,就是让冰面更滑,让橡胶更有弹性。

两个核心参数

参数 作用 取值范围
Friction 摩擦力,值越大越难滑动 0 ~ 1
Bounciness 弹性,值越大反弹越高 0 ~ 1

创建方法很简单:在Project窗口右键 → Create → Physics Material 2D。然后拖拽到Collider组件的Material槽里。

我记得有一次做弹球游戏,把Bounciness设成了1,结果球弹起来越弹越高,根本停不下来。后来才意识到,现实中没有完美的弹性,设成0.8左右比较合理。

3.4 重力:让世界有「重量」

重力在Unity 2D中默认是向下的,数值是-9.81。你可以通过Edit → Project Settings → Physics 2D来调整全局重力。

常见调整场景

  • 平台跳跃游戏:重力设大一点(比如-15),跳跃感更干脆。
  • 水下关卡:重力设小一点(比如-3),配合高阻力,模拟水的浮力。
  • 太空主题:重力设为0,所有物体漂浮。

注意:每个Rigidbody 2D的Gravity Scale是乘数,不是绝对值。比如全局重力是-9.81,某个物体的Gravity Scale是0.5,那它受到的重力就是-4.905。我曾经在调整跳跃手感时,同时改了全局和单个物体的重力,结果角色飞出了屏幕——嗯,从那以后我学会了先调全局,再微调单个物体。

3.5 碰撞检测:OnCollisionEnter 与 OnTriggerEnter

碰撞检测是物理系统的「眼睛」。Unity提供了两种检测方式:

1. 物理碰撞(Collision)

两个物体发生碰撞后,会互相弹开。常用回调函数:

void OnCollisionEnter2D(Collision2D collision)
{
    // 碰撞发生时调用一次
    Debug.Log("撞到了:" + collision.gameObject.name);
}

void OnCollisionStay2D(Collision2D collision)
{
    // 碰撞持续期间每帧调用
}

void OnCollisionExit2D(Collision2D collision)
{
    // 碰撞结束时调用
}

2. 触发器(Trigger)

勾选Collider组件上的「Is Trigger」后,物体可以穿透,但会触发事件。适合检测区域、收集物品、陷阱等。

void OnTriggerEnter2D(Collider2D other)
{
    // 进入触发器时调用
    if (other.CompareTag("Coin"))
    {
        Destroy(other.gameObject);
        score++;
    }
}

核心区别:Collision需要两个物体都有Rigidbody 2D(至少一个是Dynamic),而Trigger只需要一个Collider 2D勾选了Is Trigger。我建议:需要物理反馈的用Collision,只需要逻辑判断的用Trigger。

3.6 实战:搭建一个简单的物理场景

咱们动手试试。创建一个2D场景,放一个地面(Sprite + Box Collider 2D),再放一个球(Sprite + Circle Collider 2D + Rigidbody 2D)。

运行一下,球会掉下来,落在地面上。嗯,这就是最基础的物理模拟。

接下来,给球添加一个物理材质,把Bounciness设为0.6。再运行,球会弹跳几下才停。如果你把地面的Friction设为0,球落地后会滑出去很远。

我个人习惯在调试物理时,打开Scene视图的「Gizmos」开关,这样能看到碰撞体的绿色线框。如果线框和精灵对不上,就手动调整一下。

3.7 常见问题与避坑

  • 物体穿透:速度太快,碰撞检测来不及响应。解决方案:把Rigidbody 2D的Collision Detection设为Continuous。
  • 角色抖动:刚体被频繁修改位置。解决方案:用AddForce或velocity来控制移动,而不是直接修改transform.position。
  • 触发器不触发:检查是否勾选了Is Trigger,以及两个物体中至少有一个有Rigidbody 2D。

我的经验:如果你发现物理表现和预期不符,先检查物体的Layer Collision Matrix(Edit → Project Settings → Physics 2D → Layer Collision Matrix)。我曾经花了两个小时找bug,最后发现是玩家层和敌人层忘了勾选碰撞——嗯,这种低级错误,犯过一次就记住了。

好了,2D物理系统的基础就这些。下一章咱们会深入聊「碰撞检测的进阶用法」,包括射线检测和区域检测。到时候你会发现,物理系统远比你想象的强大。