Unity 2D游戏中实现玩家仅侧面碰撞地面时弹跳的方法
解决Unity 2D中玩家仅侧面碰地面弹跳的问题
首先说下现有脚本的核心问题:
- 把碰撞接触点的坐标当成法线用了,这完全错了!应该取
contact.normal而不是contact.point - 只判断第一个接触点,碰到多个接触点的情况会误判
- 力的方向计算没必要绕一圈,直接用法线的反方向更合理
下面是修正后的方案,同时兼顾避免碰撞卡顿:
一、核心修正思路
- 正确判断侧面碰撞:地面的顶部法线是
Vector2.up,所以当碰撞法线和up的点积绝对值小于某个阈值(比如0.7)时,判定为侧面碰撞 - 遍历所有接触点:确保不会因为单个接触点的偏差导致误判
- 优化刚体设置:给玩家刚体开启
Continuous碰撞检测,避免高速移动时穿模卡顿;同时关闭物理材质的弹性,完全用脚本控制弹跳
二、修正后的完整脚本
using UnityEngine; public class BouncySideGround : MonoBehaviour { public float bounceForce = 10f; // 顶部碰撞的阈值,越接近1越严格,0.7适合大多数Tilemap场景 [Range(0f, 1f)] public float topCollisionThreshold = 0.7f; private void OnCollisionEnter2D(Collision2D collision) { if (!collision.gameObject.CompareTag("Player")) return; Rigidbody2D playerRb = collision.gameObject.GetComponent<Rigidbody2D>(); if (playerRb == null) return; bool isSideCollision = false; Vector2 averageNormal = Vector2.zero; // 遍历所有接触点,计算平均法线,避免单个点的误差 foreach (ContactPoint2D contact in collision.contacts) { averageNormal += contact.normal; // 只要有一个接触点的法线不是顶部方向,就判定为侧面碰撞 if (Mathf.Abs(Vector2.Dot(contact.normal, Vector2.up)) < topCollisionThreshold) { isSideCollision = true; break; } } if (isSideCollision) { averageNormal.Normalize(); // 用法线的反方向作为弹跳方向,确保力的方向正确背离地面 Vector2 bounceDirection = -averageNormal; // 施加冲量力,同时保留玩家原有的垂直速度,避免卡顿 playerRb.AddForce(bounceDirection * bounceForce, ForceMode2D.Impulse); } } }
三、额外优化(避免碰撞卡顿)
- 给玩家的
Rigidbody2D设置:- 碰撞检测模式改为
Continuous - 取消勾选
Use Auto Mass,手动设置合适的质量(比如1)
- 碰撞检测模式改为
- 地面的
Composite Collider 2D勾选Used By Composite,确保Tilemap的碰撞是连续的 - 移除玩家和地面上的所有
Physics Material 2D,避免物理材质的弹性干扰脚本逻辑
这样设置后,玩家站在地面顶部时不会触发弹跳,只有从侧面撞到地面才会被弹开,同时碰撞卡顿的问题也能得到缓解。
内容的提问来源于stack exchange,提问作者Nikola Savić
相关产品推荐
相关产品推荐

