如何阻止两个Dynamic模式Rigidbody2D对象碰撞时互相推挤?
解决Dynamic Rigidbody2D互相推挤的问题
以下是几种可行的解决方案,根据你的需求选择最适合的:
方案1:通过碰撞层矩阵过滤物理交互
这是最直接高效的方法,完全避免玩家与敌人之间的物理推挤:
- 给玩家、敌人、战斗层对象分别创建独立的Layer(比如
Player、Enemy、Combat)。 - 打开
Edit > Project Settings > Physics2D,找到Layer Collision Matrix:- 取消
Player层和Enemy层之间的「Physics」勾选(如果需要检测两者接触,保留「Trigger」勾选即可)。这样两者碰撞时不会产生任何物理冲量,自然不会互相推挤。 - 确保
Player、Enemy层与Combat层的「Physics」勾选保持开启,让战斗层对象击中时能正常传递力。
- 取消
- 如果需要检测玩家和敌人的接触(比如进入攻击范围),可以将其中一个Collider设为Trigger,用
OnTriggerEnter2D处理接触逻辑,既无推挤又能检测接触。
方案2:脚本控制刚体速度,抵消推挤力
如果不想修改碰撞矩阵,可通过脚本在碰撞时恢复刚体原有速度:
给玩家和敌人都添加以下脚本,并设置对应的Tag(Player/Enemy):
using UnityEngine; public class PreventCrossPush : MonoBehaviour { private Rigidbody2D _rb; private Vector2 _lastValidVelocity; void Awake() { _rb = GetComponent<Rigidbody2D>(); } void FixedUpdate() { // 每一帧记录当前速度,用于碰撞后恢复 _lastValidVelocity = _rb.velocity; } void OnCollisionStay2D(Collision2D other) { // 只处理玩家与敌人之间的碰撞 if (other.gameObject.CompareTag("Player") || other.gameObject.CompareTag("Enemy")) { // 恢复碰撞前的速度,抵消推挤产生的力 _rb.velocity = _lastValidVelocity; } } }
- 原理是在物理更新前记录刚体速度,当和玩家/敌人碰撞时,强制重置回碰撞前的状态,避免互相推挤导致的位移。
- 战斗层对象因Tag不符,碰撞时不会触发速度重置,能正常推动目标。
方案3:精准抵消非战斗层的碰撞冲量
更精细的控制方式,直接在碰撞时过滤非战斗层的力:
using UnityEngine; public class FilterCombatForce : MonoBehaviour { private Rigidbody2D _rb; private int _combatLayer; void Awake() { _rb = GetComponent<Rigidbody2D>(); _combatLayer = LayerMask.NameToLayer("Combat"); } void OnCollisionEnter2D(Collision2D other) { // 仅允许战斗层对象传递力,其他碰撞直接清除冲量 if (other.gameObject.layer != _combatLayer) { // 抵消碰撞产生的冲量,也可直接重置速度 _rb.AddForce(-other.impulse / Time.fixedDeltaTime, ForceMode2D.Impulse); } } }
- 这个方法直接针对碰撞冲量进行抵消,只保留战斗层对象的受力效果,适合需要保留部分物理交互但过滤推挤的场景。
内容的提问来源于stack exchange,提问作者Filippo Murolo




