2D游戏开发过程中碰撞检测是最基础也最核心的功能之一——小到角色踩平台、子弹打敌人大到复杂的场景交互都离不开碰撞逻辑。很多新手入门时会遇到“碰撞不触发”“穿透”“手感奇怪”等问题今天就从基础到实战把Unity 2D碰撞的核心知识点、实操步骤和常见坑点一次性讲透。一、核心原理Unity 2D的碰撞检测依赖底层Box2D物理引擎核心逻辑是判断两个物体是否相交。简单来说碰撞要生效必须满足两个核心条件两个物体都有Collider2D碰撞体且至少一个物体有Rigidbody2D刚体——这是新手最容易踩的第一个坑记牢这句话能解决80%的基础碰撞问题。二、核心组件详解掌握Collider2D碰撞体和Rigidbody2D刚体的属性和用法碰撞逻辑就掌握了一半。2.1 Collider2D碰撞体碰撞体是不可见的其形状不需要和精灵Sprite完全一致粗略近似反而能提升性能复杂形状建议用多个简单碰撞体组合。1常用碰撞体类型及适用场景。Box Collider 2D盒型碰撞体最常用、性能最优形状是轴对齐矩形适合矩形物体如平台、墙壁、宝箱、简单角色使用率最高。Circle Collider 2D圆形碰撞体形状是圆形适合圆形物体如子弹、小球、敌人头部碰撞检测计算简单手感流畅。Polygon Collider 2D多边形碰撞体可自定义顶点能贴合不规则精灵如复杂角色、异形道具但计算开销比盒型、圆形高不建议大量使用能用多个盒型组合替代就尽量替代。Edge Collider 2D边缘碰撞体只有边缘没有内部适合场景边界、地面轮廓如不规则地形的边缘不适合用于需要“阻挡”的物体。2Is Trigger触发器这是碰撞体最核心的属性决定了碰撞的两种模式Is Trigger false默认碰撞模式真实物理碰撞两个物体碰撞后会相互阻挡如角色撞墙、小球撞地面会触发OnCollision系列回调函数。Is Trigger true触发器模式无物理阻挡物体可以互相穿透仅用于“检测是否接触”如角色进入传送门、拾取道具会触发OnTrigger系列回调函数不产生物理作用力。注意触发器模式下依然需要至少一个物体有Rigidbody2D否则无法触发回调函数。2.2 Rigidbody2D刚体刚体是碰撞生效的“开关”没有刚体即使两个物体都有碰撞体也无法触发碰撞事件静态碰撞体除外。Body Type刚体类型决定物体的物理行为重点区分Dynamic动态完全受物理引擎控制会受力的影响可以和所有类型的碰撞体交互是最常用的类型也是触发碰撞事件的核心条件之一至少一个物体为Dynamic。Kinematic运动学不受物理引擎控制只能通过脚本控制移动不会受重力影响和Dynamic物体碰撞时会触发对方的碰撞事件但自身不会被推动。Static静态静止不动不受物理引擎控制如地面、墙壁性能最优物理引擎会对其进行优化适合场景中固定不变的物体。注意两个Static物体不会触发碰撞事件Static和Kinematic物体也不会触发碰撞事件。2.3 Physics Material 2D2D物理材质用于模拟不同材质的碰撞效果如冰面的光滑、橡胶的弹性核心属性是Friction摩擦力和Bounciness弹力冰面Friction设为0无摩擦力物体滑动更远Bounciness设为0无弹力。橡胶Friction设为0.5中等摩擦力Bounciness设为0.8高弹力。三、实战案例结合实际开发场景讲解两种最常用的碰撞逻辑物理碰撞阻挡反馈和触发器检测穿透检测代码可直接复制使用。案例1物理碰撞角色撞墙、落地反馈场景2D平台游戏主角Dynamic刚体碰撞地面、墙壁时播放音效、禁止穿墙落地时标记为“地面状态”。步骤1给物体添加组件主角PlayerSprite Renderer精灵 Box Collider 2DIs Triggerfalse Rigidbody2DBody TypeDynamicGravity Scale1Freeze Rotation Z勾选。地面Ground、墙壁WallSprite Renderer Box Collider 2DIs Triggerfalse无需添加Rigidbody2D默认是Static碰撞体。步骤2编写碰撞回调代码挂载到Player上using UnityEngine; public class PlayerCollision : MonoBehaviour { // 碰撞音效可在Inspector中赋值 public AudioClip collisionSound; // 是否在地面上用于跳跃判断 private bool isOnGround false; // 碰撞开始时触发只调用一次 private void OnCollisionEnter2D(Collision2D other) { // 判断碰撞的是地面根据标签判断需给地面设置标签Ground if (other.gameObject.CompareTag(Ground)) { isOnGround true; Debug.Log(落地成功可跳跃); // 播放落地音效 PlayCollisionSound(); } // 判断碰撞的是墙壁标签Wall else if (other.gameObject.CompareTag(Wall)) { Debug.Log(撞到墙壁无法穿过); PlayCollisionSound(); } } // 碰撞持续时触发每帧调用 private void OnCollisionStay2D(Collision2D other) { // 例如角色在地面上时播放站立动画 if (other.gameObject.CompareTag(Ground)) { // 这里可添加动画逻辑如anim.SetBool(IsGrounded, true); } } // 碰撞结束时触发只调用一次 private void OnCollisionExit2D(Collision2D other) { if (other.gameObject.CompareTag(Ground)) { isOnGround false; Debug.Log(离开地面不可跳跃); // 动画逻辑anim.SetBool(IsGrounded, false); } } // 播放碰撞音效 private void PlayCollisionSound() { if (collisionSound ! null) { AudioSource.PlayClipAtPoint(collisionSound, transform.position); } } }案例2触发器检测拾取道具、传送门场景主角进入道具范围自动拾取道具道具消失进入传送门自动切换场景。步骤1给物体添加组件主角Player和案例1一致Dynamic刚体Box Collider 2D。道具ItemSprite Renderer Circle Collider 2DIs Triggertrue Rigidbody2DBody TypeKinematic避免被重力影响。传送门PortalSprite Renderer Box Collider 2DIs Triggertrue Rigidbody2DBody TypeKinematic。步骤2编写触发器回调代码挂载到道具和传送门上using UnityEngine; using UnityEngine.SceneManagement; // 道具拾取脚本挂载到Item上 public class ItemPickup : MonoBehaviour { // 拾取音效 public AudioClip pickupSound; // 进入触发器时触发 private void OnTriggerEnter2D(Collider2D other) { // 判断进入的是主角标签Player if (other.CompareTag(Player)) { // 拾取逻辑加分、解锁道具等 Debug.Log(拾取道具得分10); // 播放拾取音效 if (pickupSound ! null) { AudioSource.PlayClipAtPoint(pickupSound, transform.position); } // 销毁道具消失效果 Destroy(gameObject); } } } // 传送门脚本挂载到Portal上 public class Portal : MonoBehaviour { // 目标场景名称在Inspector中输入 public string targetScene; private void OnTriggerEnter2D(Collider2D other) { if (other.CompareTag(Player)) { Debug.Log(进入传送门切换场景); // 切换场景需在Build Settings中添加目标场景 SceneManager.LoadScene(targetScene); } } }四、常见碰撞问题及解决方案避坑重点问题1碰撞不触发两个物体直接穿透排查顺序优先级从高到低是否两个物体都有Collider2D是否有一个物体的Collider2D被禁用Enabledfalse是否至少一个物体有Rigidbody2D且Rigidbody2D的Body Type不是Static两个物体的Layer是否被屏蔽检查路径Edit → Project Settings → Physics2D → Layer Collision Matrix确保两个物体所在Layer的交叉处是勾选状态未勾选则无法碰撞。物体移动速度过快将Rigidbody2D的Collision Detection改为Continuous解决帧间穿透问题。是否误将Collider2D设为Is Triggertrue触发器模式下不会有物理阻挡会直接穿透。问题2碰撞回调函数OnCollisionXXX、OnTriggerXXX不执行排查要点函数名是否拼写错误大小写、后缀2D不能漏如OnCollisionEnter2D不能写成OnCollisionEnter。脚本是否挂载到正确的物体上回调函数必须挂载在参与碰撞的物体上不能挂载在父物体上除非父物体也有碰撞体和刚体。碰撞模式和回调函数是否匹配Is Triggerfalse对应OnCollisionXXXIs Triggertrue对应OnTriggerXXX不能混用。两个物体是否都是Kinematic刚体两个Kinematic刚体碰撞不会触发OnCollisionXXX回调触发器模式除外。是否使用了复合碰撞体复合碰撞体父物体刚体子物体碰撞体的回调会同时触发在父物体和子物体上需确保脚本挂载正确。问题3物体碰撞后旋转异常如角色撞墙后翻转解决方案勾选Rigidbody2D的Freeze Rotation Z冻结Z轴旋转固定物体角度。问题4静态碰撞体移动后碰撞失效原因物理引擎对静态碰撞体进行了优化认为其不会移动移动后会导致物理计算异常甚至碰撞失效。解决方案将静态碰撞体的Rigidbody2D设为Kinematic运动学通过脚本控制移动而非直接修改Transform.position。问题5Polygon Collider 2D碰撞不准确原因顶点数量过少或顶点位置未贴合精灵形状或两个Polygon Collider 2D碰撞默认无法相互碰撞。解决方案1. 调整Polygon Collider 2D的顶点贴合精灵轮廓2. 将其中一个碰撞体改为Box Collider 2D3. 勾选Polygon Collider 2D的Convex凸面属性使其可与其他多边形碰撞体碰撞。五、进阶优化碰撞性能提升技巧当场景中碰撞体数量较多如大量敌人、子弹容易出现帧率下降可通过以下方法优化优先使用简单碰撞体能用Box、Circle就不用Polygon复杂形状用多个简单碰撞体组合复合碰撞体降低计算开销。合理使用Layer通过Layer Collision Matrix屏蔽不需要碰撞的Layer如敌人和敌人之间不需要碰撞减少碰撞检测次数。控制碰撞体大小碰撞体不要过大避免不必要的碰撞检测如角色的碰撞体只覆盖身体不要覆盖整个精灵。优化碰撞检测模式仅对快速移动的物体子弹、主角启用Continuous碰撞检测其他物体用默认的Discrete模式减少CPU消耗。禁用闲置碰撞体场景中未激活的物体如隐藏的道具、敌人禁用其Collider2D避免无效检测。六、总结Unity 2D碰撞的核心逻辑很简单Collider2D定义边界Rigidbody2D提供物理属性根据Is Trigger选择碰撞模式。