Untiy基础学习(十四)核心系统—物理系统之碰撞检测代码篇 刚体,碰撞体,材质

目录

一、碰撞器(Collider)与触发器(Trigger)

二、碰撞检测条件

三、碰撞事件与触发器事件,可以理解为特殊的生命周期函数。

四、讲讲如何选择

​编辑

五、总结

一、碰撞/触发事件函数对照表

二、Collider 与 Collision 参数属性对照表

1. Collider 类参数(用于触发器事件)

2. Collision 类参数(用于碰撞事件)

三、结构体参数展开

1. ContactPoint(碰撞接触点)

2. Bounds(包围盒)

          前面两篇文章中,我们详细的了解了,Rigidbody刚体,以及各种碰撞器相关的内容。同时我们也清楚了碰撞的条件:两个物体都必须有碰撞器,并且至少一个物体上面存在刚体。并回答了两个问题:如何让两个物体碰撞时产生不同的碰撞效果(设置他们的物理材质,两个物体身上的物理材质都要设置)触发器的作用是什么(让两个物体碰撞没有物理效果 只进行碰撞处理)

        所以今天我们来看看有哪些和代码相关的内容以及前情回顾:

一、碰撞器(Collider)与触发器(Trigger)


碰撞器
作用:检测物体间的物理碰撞,并产生物理反馈(如反弹)。
组件:Box Collider、Sphere Collider、Capsule Collider等。
静态物体:无Rigidbody的碰撞器(如地面),用于阻挡动态物体。

触发器
启用方式:勾选Collider组件的Is Trigger。
行为:物体穿透时触发事件,无物理反馈(如收集金币)。

二、碰撞检测条件


必要条件:
两个物体均需附加Collider组件。
至少一个物体附加Rigidbody组件(动态物体)。
触发检测时,至少一个物体勾选Is Trigger。

三、碰撞事件与触发器事件,可以理解为特殊的生命周期函数。


碰撞事件(需关闭Is Trigger):
OnCollisionEnter(Collision other):碰撞开始时调用。
OnCollisionStay(Collision other):碰撞持续中每帧调用。
OnCollisionExit(Collision other):碰撞结束时调用。

相关参数Collision介绍:

Collision 类型参数存储了碰撞的详细信息,可通过其属性获取碰撞对象的关键数据:

other.gameObject
作用:获取碰撞到的另一物体的 GameObject 引用。
用途:用于判断碰撞对象身份(如标签、名称)、操作对方物体(如销毁、施加力)。

if (other.gameObject.CompareTag("Enemy")) {
    Destroy(other.gameObject); // 销毁敌人
}

other.contactOffset

contactOffset 是一个 距离阈值,表示两个碰撞器之间生成接触点的最小间隔。
默认值:0.01 米(在 Unity 的 Project Settings > Physics 中可全局修改)。
单位:世界坐标系中的米(meters)。

当两个碰撞器的距离 小于等于 contactOffset 时,物理引擎会开始生成接触点(即触发碰撞事件)。
若距离 大于 contactOffset,则不会触发碰撞事件。

other.contacts
作用:获取碰撞接触点的数组(ContactPoint[])。这是一个结构体数组
用途:计算碰撞位置或生成特效。 

Vector3 firstContactPoint = other.contacts[0].point; // 第一个接触点坐标
Instantiate(explosionEffect, firstContactPoint, Quaternion.identity);

ContactPoint 结构体的核心属性
point(坐标点)
类型:Vector3
作用:碰撞接触点的世界坐标系坐标。
用途:在精确位置生成特效(如火花、弹痕)或计算受力点。

normal(法线方向)
类型:Vector3
作用:碰撞接触点的法线方向(垂直于碰撞表面的方向)。
用途:计算反弹方向、滑动行为或伤害方向判定。

separation(分离距离)
类型:float
作用:两个碰撞器在接触点的分离距离(负数表示穿透深度)。
用途:检测碰撞的剧烈程度(如穿透深度过大时触发特殊逻辑)。

thisCollider 与 otherCollider
类型:Collider
作用:
thisCollider:当前脚本所在物体的碰撞器。
otherCollider:对方物体的碰撞器。
用途:区分碰撞器来源(如区分玩家身体的不同部位碰撞)。

other.impulse
作用:获取碰撞的冲量(Vector3 类型)。
用途:计算碰撞力度(如伤害值)。

float damage = other.impulse.magnitude * 0.1f;
health -= damage;

other.collider
存在替代方案:通过 other.gameObject.GetComponent<Collider>() 获取碰撞器。 

Collider collider = other.gameObject.GetComponent<Collider>();
if (collider != null) {
    collider.enabled = false; // 禁用对方碰撞器
}

触发器事件(需启用Is Trigger):
OnTriggerEnter(Collider other):进入触发器时调用。
OnTriggerStay(Collider other):停留在触发器内时每帧调用。
OnTriggerExit(Collider other):离开触发器时调用。

相关参数Collider的介绍

other.gameObject 和上面一样
作用:获取触发器的所属 GameObject。
用途:检测触发对象身份或操作触发物体。

if (other.gameObject.name == "HealthPack") {
    playerHealth += 20;
    Destroy(other.gameObject); // 拾取血包
}

other.bounds
作用:获取触发器的包围盒(Bounds 类型)。
用途:计算触发器的尺寸或位置。

Vector3 triggerCenter = other.bounds.center; // 触发器中心坐标

other.isTrigger
作用:检查该碰撞器是否作为触发器使用。
用途:避免误判非触发器物体。

if (other.isTrigger) {
    Debug.Log("触发了一个触发器对象");
}

两个实例脚本:

(1)模拟子弹碰撞到一个物体上面:

private void OnCollisionEnter(Collision other) {
    if (other.gameObject.CompareTag("Enemy")) {
        // 获取敌人脚本并造成伤害
        Enemy enemy = other.gameObject.GetComponent<Enemy>();
        if (enemy != null) {
            enemy.TakeDamage(10);
        }
        
        // 在接触点生成爆炸特效
        ContactPoint contact = other.contacts[0];
        Instantiate(explosionPrefab, contact.point, Quaternion.identity);
        
        // 销毁子弹自身
        Destroy(gameObject);
    }
}

 (2)进入可以的传送区域

private void OnTriggerEnter(Collider other) {
    if (other.CompareTag("Player")) {
        // 获取玩家坐标并传送
        Vector3 teleportPosition = new Vector3(0, 5, 0);
        other.transform.position = teleportPosition;
        
        // 播放音效
        AudioSource.PlayClipAtPoint(teleportSound, transform.position);
    }
}

四、讲讲如何选择

1.只要挂载的对象 能和别的物体产生碰撞或者触发 那么这六个函数就都能够被响应
2.6个函数不是说我们都要写 我们一般是根据需求来进行选择书写
3.如果是一个异形物体 刚体在父对象上 如果你想通过子对象上挂脚本检测碰撞是行不通的 必须挂载到这个刚体父对象上才行
4.要明确 物理碰撞和触发器响应的区别

在下面可以决定哪些对象的碰撞情况,在 Unity 中,Layer Collision Matrix(层碰撞矩阵) 是一个用于控制不同层级(Layer)之间碰撞检测是否生效的核心工具。它的作用是通过选择性启用或禁用特定层之间的碰撞,优化物理计算性能,并实现特定交互逻辑。注意,最好对称的,

五、总结

一、碰撞/触发事件函数对照表

函数名类型触发条件参数类型用途
OnCollisionEnter碰撞事件两物体碰撞开始Collision处理碰撞开始逻辑(如伤害、音效)
OnCollisionStay碰撞事件两物体碰撞持续中每帧Collision处理持续接触逻辑(如摩擦音效)
OnCollisionExit碰撞事件两物体碰撞结束Collision处理碰撞结束逻辑(如状态重置)
OnTriggerEnter触发器事件物体进入触发器范围Collider处理触发开始逻辑(如拾取道具、传送)
OnTriggerStay触发器事件物体停留在触发器内每帧Collider处理持续触发逻辑(如持续治疗、区域伤害)
OnTriggerExit触发器事件物体离开触发器范围Collider处理触发结束逻辑(如离开区域提示)

二、Collider 与 Collision 参数属性对照表

1. Collider 类参数(用于触发器事件)
属性/方法类型作用示例
gameObjectGameObject获取触发器的所属对象if (other.gameObject.CompareTag("Player")) { ... }
boundsBounds获取触发器的包围盒(包含中心、尺寸等)Vector3 center = other.bounds.center;
isTriggerbool检查该碰撞器是否作为触发器if (other.isTrigger) { Debug.Log("触发的是触发器"); }
contactOffsetfloat控制接触点生成的距离阈值(可全局或单独设置)GetComponent<Collider>().contactOffset = 0.05f;
attachedRigidbodyRigidbody获取该碰撞器关联的刚体(若有)Rigidbody rb = other.attachedRigidbody;
2. Collision 类参数(用于碰撞事件)
属性/方法类型作用示例
gameObjectGameObject获取碰撞到的对方对象if (collision.gameObject.name == "Wall")) { ... }
contactsContactPoint[]碰撞接触点数组(包含坐标、法线等)Vector3 point = collision.contacts[0].point;
impulseVector3碰撞的冲量(力度和方向)float force = collision.impulse.magnitude;
collider (已过时)Collider对方碰撞器(建议改用 gameObject.GetComponent<Collider>()Collider col = collision.gameObject.GetComponent<Collider>();

三、结构体参数展开

1. ContactPoint(碰撞接触点)
属性类型作用
pointVector3接触点的世界坐标(用于特效生成)
normalVector3接触点法线方向(用于反弹计算)
separationfloat两碰撞器的分离距离(负数表示穿透深度)
thisColliderCollider当前脚本所在物体的碰撞器
otherColliderCollider对方物体的碰撞器
2. Bounds(包围盒)
属性类型作用
centerVector3包围盒中心坐标
sizeVector3包围盒尺寸(长宽高)
extentsVector3包围盒半尺寸(size / 2
min/maxVector3包围盒最小/最大角坐标


补充:关于刚体加力的介绍

1、首先要获取到刚体组件:在脚本中通过 GetComponent<Rigidbody>() 获取刚体组件,这是后续操作的基础。

Rigidbody rb = GetComponent<Rigidbody>();

2、力的应用方法

方法坐标系参数说明代码示例作用说明
AddForce世界坐标系Vector3方向,ForceMode模式rb.AddForce(Vector3.forward * 1000);施加力使物体沿世界坐标系方向移动。
AddRelativeForce自身坐标系Vector3方向,ForceMode模式rb.AddRelativeForce(Vector3.forward * 1000);施加力使物体沿自身朝向移动。
AddTorque世界坐标系Vector3旋转轴,ForceMode模式rb.AddTorque(Vector3.up * 1000);施加扭矩使物体绕世界坐标轴旋转。
AddRelativeTorque自身坐标系Vector3旋转轴,ForceMode模式rb.AddRelativeTorque(Vector3.up * 1000);施加扭矩使物体绕自身坐标轴旋转。
AddExplosionForce世界坐标系float爆炸力,Vector3爆炸中心,float爆炸半径rb.AddExplosionForce(10, Vector3.zero, 10);模拟爆炸效果,影响范围内所有刚体。

示例们:

(1)AddForce(世界坐标系)

// 示例:在世界坐标系Z轴方向施加持续力(如推动箱子)
void ApplyWorldForce()
{
    rb.AddForce(Vector3.forward * 50, ForceMode.Force);
//参数:Vector3.forward * 50 表示向世界坐标系正前方施加50牛顿的力。
//模式:ForceMode.Force 表示持续施加力(与质量相关)。
}


(2)AddRelativeForce(自身坐标系)

// 示例:沿物体自身前方施加力(如飞机推进)
void ApplyLocalForce()
{
    rb.AddRelativeForce(Vector3.forward * 50, ForceMode.Force);
/*
参数:Vector3.forward 相对于物体自身朝向。
应用场景:控制载具或角色移动。
*/
}


(3)AddTorque(世界坐标系旋转)

// 示例:绕世界坐标系Y轴旋转(如旋转门)
void ApplyWorldTorque()
{
    rb.AddTorque(Vector3.up * 10, ForceMode.Force);
//参数:Vector3.up 表示绕世界坐标系Y轴旋转。
}


(4)AddRelativeTorque(自身坐标系旋转)

// 示例:绕物体自身Y轴旋转(如陀螺仪)
void ApplyLocalTorque()
{
    rb.AddRelativeTorque(Vector3.up * 10, ForceMode.Force);
//参数:Vector3.up 相对于物体自身坐标系。
}


(5)AddExplosionForce(爆炸力) 

// 示例:在原点位置产生爆炸效果
void ApplyExplosion()
{
    float explosionForce = 1000;
    Vector3 explosionCenter = new Vector3(0, 0, 0);
    float explosionRadius = 10;
    rb.AddExplosionForce(explosionForce, explosionCenter, explosionRadius);
/*
参数:

explosionForce:爆炸强度。

explosionCenter:爆炸中心点。

explosionRadius:爆炸影响半径。

*/
}

3、直接控制速度

属性/方法参数说明代码示例作用说明
velocityVector3速度向量rb.velocity = Vector3.forward * 10;直接设置刚体的速度(世界坐标系)。
// 示例:直接设置物体速度为水平向右10m/s
void SetVelocity()
{
//注意:直接修改速度会覆盖物理引擎计算,适用于瞬移或精确控制。
    rb.velocity = new Vector3(10, 0, 0);
}

 

 4、力的模式(ForceMode)

模式计算公式适用场景代码示例
Force持续力,F = m * a持续推动(如火箭推进)rb.AddForce(Vector3.up, ForceMode.Force);
Impulse瞬间冲量,F * Δt = m * v瞬间施加力(如跳跃、射击)rb.AddForce(Vector3.up * 100, ForceMode.Impulse);
Acceleration忽略质量,a直接应用质量无关的加速效果rb.AddForce(Vector3.up, ForceMode.Acceleration);
VelocityChange忽略质量,直接改变速度瞬间改变速度(如传送)rb.AddForce(Vector3.up * 10, ForceMode.VelocityChange);

就这样 结束! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FAREWELL00075

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值