Unity学习90天 - 第4天 - 认识物理系统基础并实现物体碰撞反弹

那么接下来就让我来了解了解什么是 Unity 的物理系统,认识 Rigidbody 和 Collider,搞清楚触发器和碰撞器的区别,并且在此

一、什么是物理系统?

Unity 内置了一套 PhysX 物理引擎,可以模拟真实世界的物理行为:重力、碰撞、摩擦、弹力......

物理系统的两个核心组件:

组件 作用 类比
Rigidbody 让物体受物理规律控制 给物体装上"物理大脑"
Collider 定义物体的碰撞形状 给物体装上"身体轮廓"

只有 Collider 没有 Rigidbody → 静止障碍物(墙壁、地板) 有 Rigidbody 有 Collider → 会动的物体(小球、角色、箱子)

基础上实现一个碰到墙壁就会反弹的小球。

二、Rigidbody --- 物理大脑

1. 什么是 Rigidbody?

Rigidbody(刚体)是让 Unity 接管物体运动的组件。挂上它之后,物体就会受重力、力、碰撞等物理影响,不再需要你手动改位置。

2. Inspector 参数详解

参数 说明 建议值
Mass 质量(kg),影响碰撞力度 默认 1
Drag 空气阻力,越大减速越快 0 = 无阻力
Angular Drag 旋转阻力 默认 0.05
Use Gravity 是否受重力 地面物体勾选
Is Kinematic 开启后不受物理力影响,只能用代码控制 需要手动控制时开启
Constraints 冻结某个轴的位移或旋转 防止物体乱转时用

3. 常用 API

cs 复制代码
// --- 获取组件 ---
private Rigidbody rb;
void Awake()
{
    rb = GetComponent<Rigidbody>();
}

// --- 施加力(最常用) ---
rb.AddForce(Vector3.forward * 10f);                       // 普通力(持续加速)
rb.AddForce(Vector3.up * 5f, ForceMode.Impulse);          // 瞬间冲量(跳跃用)
rb.AddForce(Vector3.right * 3f, ForceMode.VelocityChange);// 直接改速度(不考虑质量)

// --- 速度控制 ---
rb.velocity = new Vector3(0, 0, 5f);  // 直接设置速度
rb.velocity = Vector3.zero;           // 立刻停止

// --- 物理移动(比直接改position更稳定)---
rb.MovePosition(rb.position + dir * speed * Time.fixedDeltaTime);

4. ForceMode 四种模式对比

ForceMode 说明 适合场景
Force 持续力,受质量影响 引擎推力、风力
Impulse 瞬间冲量,受质量影响 跳跃、爆炸
Acceleration 持续加速,不受质量影响 重力系统
VelocityChange 直接改速度,不受质量影响 急停、传送带

三、Collider --- 碰撞体轮廓

1. 什么是 Collider?

就像你走路撞到墙:

  • = 带 Rigidbody 的物体(小球)
  • = 带 Collider 的物体
  • 撞上去的感觉 = 物理碰撞

你伸手穿过一束红外线:

  • 红外线是 Trigger(触发器)
  • 你感觉没东西挡着,但红外线"知道"你穿过了

Collider(碰撞器)定义了物体在物理世界中的形状边界,决定了"哪里能碰到"。

(这里展示的是胶囊体)

2. Collider 的六种类型

Unity 提供了 6 种基础 Collider,分别对应不同形状:

| 类型 | 适用场景 | 形状 | 特点 |
| Box Collider | 箱子、门、墙、建筑 | 方形 | 最常用,效率高 |
| Sphere Collider | 球、圆形物体、炮弹 | 球形 | 圆滚滚的东西 |
| Capsule Collider | 角色、柱子、管道 | 胶囊形 | Unity 角色默认用这个 |
| Mesh Collider | 复杂形状的物体 | 任意形状 | 最精确但最慢 |
| Wheel Collider | 车辆轮子 | 特殊圆形 | 专用于汽车 |

Terrain Collider 地形 地形高度图 配合 Terrain 地形

原则:能用简单形状就不要用 Mesh Collider,性能差很多!

Capsule Collider 胶囊体 Sphere Collider 球体 Box Collider 方体

3. 添加方式

复制代码
Inspector → Add Component → 搜索 Collider → 选择对应类型

4.基本属性

属性 含义 常用值
Center 碰撞体中心点(相对于物体坐标) (0, 0, 0)
Size 碰撞体长宽高(米) (1, 1, 1)
Material 物理材质(弹性、摩擦力) 可选
Is Trigger 是否为触发器 ❌ 否

5.代码创建 Box Collider

cs 复制代码
// 方式1:组件方式(推荐)
BoxCollider box = gameObject.AddComponent<BoxCollider>();

// 设置中心点
box.center = new Vector3(0, 0.5f, 0);

// 设置大小
box.size = new Vector3(2f, 1f, 1f);

// 获取已有的 BoxCollider
BoxCollider existingBox = GetComponent<BoxCollider>();

四、触发器与碰撞器 --- 最容易搞混的概念

1. 一句话区分

cs 复制代码
Is Trigger = false(默认)→ 碰撞器 → 有物理阻挡,会反弹  → 触发 OnCollision
Is Trigger = true         → 触发器 → 可以穿过,无阻挡    → 触发 OnTrigger

2. 直观类比

| 属性 | Is Trigger = false (默认) | Is Trigger = true |
| 物理效果 | 有碰撞,会被挡住 | 无碰撞,直接穿过去 |
| 回调函数 | OnCollision... | OnTrigger... |

用途 真实物理碰撞 检测、拾取、传送

3.何时用哪个?

场景 用碰撞器 ❌ 用触发器 ✅
撞墙反弹
踩到地砖扣血
拾取金币
进入传送门
检测是否在安全区

4. 碰撞生效的必要条件

  • 两个物体都有 Collider
  • 至少一个物体有 Rigidbody
  • 两个都不是 Is Trigger(碰撞)
  • 或至少一个是 Is Trigger(触发)

缺任何一个条件 → 不触发回调!

4.1 对比总结表
对比项 碰撞器(Collision) 触发器(Trigger)
Is Trigger false true
物理阻挡 ✅ 有 ❌ 无,可穿过
回调前缀 OnCollision OnTrigger
参数类型 Collision Collider
能获取碰撞点 col.contacts ❌ 没有
典型用途 墙壁、地板、弹跳 道具拾取、区域检测
4.2 回调函数对比:
阶段 碰撞器回调 触发器回调
刚接触 OnCollisionEnter(Collision) OnTriggerEnter(Collider)
持续接触 OnCollisionStay(Collision) OnTriggerStay(Collider)
离开 OnCollisionExit(Collision) OnTriggerExit(Collider)

那么我们来试一试碰撞和触发的函数吧!

碰撞器回调:

首先是我们的碰撞回调函数:

  • OnCollisionEnter(Collision):碰到另一个碰撞器时调用(触发一次)
  • OnCollisionStay(Collision):与碰撞器持续接触时,每帧调用
  • OnCollisionExit(Collision):碰撞器分离时调用(触发一次)

那么我们就先搭建一个场景吧,不需要太多东西,只需要一个地板和一个物体,名字自取。

弄好之后我们新建脚本CollisionDemo脚本,把脚本放在物体身上配置好碰撞体和刚体后我们就开始写脚本啦。

首先我们使用OnCollisionEnter()方法在我们两个碰撞体第一次碰撞时候调用:

通过Debug将我们碰撞到的对象的名字打印在控制台

cs 复制代码
    void OnCollisionEnter(Collision collision)
    {
        Debug.Log($"[碰撞-进入] 碰到了: {collision.gameObject.name}");
    }

再用OnCollisionStay()方法在两个碰撞体持续接触时调用:

一样将名字打印在控制台

cs 复制代码
void OnCollisionStay(Collision collision)
{
    Debug.Log($"[碰撞-持续] 还贴着: {collider.gameObeject.name}");
}

最后是我们的一个OnCollisionExit()方法在我们两个碰撞体分离后调用:

cs 复制代码
void CollisionExit(Collision collision)
{
    Debug.Log($"[碰撞-退出] 离开了: {collision.gameObject.name}");
}

那么在运行后就可以在我们控制台发现我们获取到了我们平面Plane,因为我创建后没用修改名字所以就叫Plane。

触发器回调:

接着将我们的触发器回调函数:

  • OnTriggerEnter(Collider):刚接触触发区域时调用(触发一次)

  • OnTriggerStay(Collider):待在触发区域内时,每帧调用

  • OnTriggerExit(Collider):从触发区域分离时调用(触发一次)

接着用我们的上一个场景,但是需要吧我们物体碰撞器的Is Tirgger勾上,为了防止下落我们还需要勾上刚体的Is Kinematic,好那么完成后我们开始编写。

首先我们使用OnTriggerEnter()方法在我们第一次进入触发区域的时候调用:

cs 复制代码
void OnTirggerEnter(Collisoin other)
{
    Debug.Log($"[触发-进入] 进入区域,碰到了: {other.gameObject.name}");
}

再用OnTriggerStay()方法在持续待在触发区域时调用:

cs 复制代码
    void OnTriggerStay(Collider other)
    {
        Debug.Log($"[触发-持续] 还待在区域内: {other.gameObject.name}");
    }

最后是我们的一个OnTriggerExit()方法在退出触发区域后调用:

cs 复制代码
void OnTriggerExit(Collision other)
{
    Debug.Log($"[触发-退出] 离开了区域: {other.gameObject.name}")
}

那么写完后运行展示!可以看到我们也成功完成了我们触发器的回调函数,如果大家跟着我做到这里那么应该就已经算是明白了我们的刚体、碰撞器、触发器!

五、物理碰撞弹射实现

最后我们来实现我们今天的任务物理碰撞弹射吧!这个非常的简单。

首先我们先设置我们的刚体和一个碰撞弹射的速度

然后我们需要在初始化时需要获取刚体

最后在我们的碰撞方法中写上我们的一个逻辑,首先获取我们碰撞面的一个朝向,

再用AddForce((normal * shootForce)力向量,(ForceMode.Impulse)发力方式)来实现把球弹射出去

完整代码

cs 复制代码
using UnityEngine;

public class CollisionDemo : MonoBehaviour
{
    [Header("弹射力度")]
    public float shootForce = 15f;

    private Rigidbody rb;

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

    void OnCollisionEnter(Collision collision)
    {


        Debug.Log($"[碰撞-进入] 碰到了: {collision.gameObject.name}");


        // 获取碰撞面的朝向(法线方向)
        Vector3 normal = collision.contacts[0].normal;

        // 沿法线方向施加速度,把球弹射出去
        // ForceMode.Impulse = 瞬时冲击力(适合弹射)
        rb.AddForce(normal * shootForce, ForceMode.Impulse);


    }
}

运行成果展示:

如果想要做的更好就需要规定一下到底谁才能来踢这个球,踢多少的力合适。

今天的内容就到这里! 接下来我将连续更新90天的Untiy教程从基础到一个网络部分,有兴趣的朋友们可以收藏关注,谢谢!如果有疑问,评论区见。

相关推荐
艾莉丝努力练剑2 小时前
【Linux线程】Linux系统多线程(五):<线程同步与互斥>线程互斥
linux·运维·服务器·c语言·c++·学习·ubuntu
亚空间仓鼠2 小时前
Python学习日志(二):基础语法
windows·python·学习
南無忘码至尊2 小时前
Unity学习90天 - 第4天 - 学习预制体 Prefab + 实例化并实现按鼠标生成子弹
学习·unity·游戏引擎
AnalogElectronic2 小时前
PHP学习02,PHP + jQuery + HTML + MySQL+nginx 做一个多用户云笔记项目
学习·php·jquery
SteveSenna2 小时前
aubo i5+pika realsense+ACT训练完整流程
人工智能·学习·算法·机器人
鱼鳞_2 小时前
Java学习笔记_Day30(File)
笔记·学习
AIHR数智引擎2 小时前
AI时代,德鲁克依然是答案——只是问题变了
大数据·人工智能·学习·职场和发展·机器人·求职招聘
talen_hx2962 小时前
emqx的Keep alive
java·笔记·学习
醇氧2 小时前
用 CC Switch (cc-sw) 配置 Claude Code 接入 阿里云百炼 (Dashscope)
人工智能·学习·阿里云·ai·云计算