为什么碰撞不能正确生效?

发现个很奇怪的情况,碰撞检测的原理到底是怎样的,试了很久都不明白,真心求大佬解答。

项目中使用的是 基于Box2D的2D物理系统
我启用了
PhysicsSystem2D.instance.debugDrawFlags = EPhysics2DDrawFlags.Shape;
进行Debug
并且开启了碰撞回调
   let collider = this.getComponent(Collider2D);
        if (collider) {
            collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
        }

然后出现下图的这种情况。当发送碰撞的时候我会在控制台打印日志

检测到碰撞 控制台打印了信息

两个box明显重叠了,但没有碰撞 控制台没有打印了信息

将上面没有发送碰撞的放在一起,当僵尸同时接触两种碰撞 控制台打印了信息

预制体设置如下

相关代码

import { _decorator, Collider2D, Component, Contact2DType, Enum, EPhysics2DDrawFlags, IPhysics2DContact, Node, PhysicsSystem2D, Sprite, tween } from 'cc';
import { EnemisType } from '../EnumClass';
import { PeaBullet } from '../Plants/PeaBullet';
import { Plant } from '../Plants/Plant';
const { ccclass, property } = _decorator;

@ccclass('XiaoBing')
export class XiaoBing extends Component {
    @property({ type: Enum(EnemisType) })
    public EnemisType: EnemisType;
    @property(Number)
    public HP: number = 10;
    @property(Number)
    public Speed: number = 10;
    private currHp: number;
    private halfLife: boolean = true;
    private stop: boolean = false;
    protected onLoad(): void {
        this.currHp = this.HP;
        PhysicsSystem2D.instance.debugDrawFlags = 
    EPhysics2DDrawFlags.Shape;
    
    }
    start() {
        let collider = this.getComponent(Collider2D);
        if (collider) {
            collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
        }
    }

    onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
        // 只在两个碰撞体开始接触时被调用一次
        // 获取碰撞体所属节点的名字
        let otherNode = otherCollider.node;
        const otherNodeName = otherCollider.node.name;
        console.log('Collided with:', otherNodeName);
        // 判断碰撞体所属节点上是否挂载了某个脚本
        if (otherNode.getComponent(PeaBullet)) {
            console.log('遇到子弹');
            let peaBullet = otherNode.getComponent(PeaBullet);
            peaBullet.destroyBullet();
            this.subHP(peaBullet.attVal);
        } else if (otherNode.getComponent(Plant)) {
            console.log('遇到植物');
            let plant = otherNode.getComponent(Plant);
            this.eatPlant(plant);


        } else {
            console.log('Collided with an unknown object');
        }

    }
    eatPlant(plant: Plant) {
        
    }

    update(deltaTime: number) {
        if (!this.stop) {
            let pos = this.node.getPosition();
            this.node.setPosition(pos.x - this.Speed * deltaTime, pos.y, 0);
        }
    }

    subHP(attVal: number) {
        this.currHp -= attVal;
        if (this.HP / 2 == Math.round(this.currHp) && this.halfLife) {
            this.halfLife = false;
            this.halfLifeAnim();
        }

        if (this.currHp == 0) {
            this.deadAnim();
        }
    }
    halfLifeAnim() {

    }
    deadAnim() {

    }
}

碰撞分组没勾上?

是项目设置那个吗? 肯定是勾上了

begin是一开始碰撞的时候触发一次,后面就没有再触发了,如果要碰撞的时候一直触发要监听onCollisionStay这个

begin最少也会触发一次吧,我这是某些情况完全不触发。也换过其他监听了,一样没用

感觉可能是组件加错了

我也遇到了,我写贪吃蛇游戏,head 和 food 都是设置了刚体和碰撞的box,但是有时候碰撞就是不生效。请问楼主解决了吗

因为他用box2d物理系统又用setposition设置位置(box2d最好用刚体组件上的linear velocity设置速度否则设置了allowsleep会休眠,不过他这种情况还是用builtin碰撞系统更合适)

感谢大哥,用刚体的linear velocity果然就可以了。顺便想问问builtin碰撞系统是什么,我查了资料上面说是Cocos3d系统里面的

项目设置的功能裁剪里面有一个2d碰撞系统有两个可以选择,一个是box2d(带刚体,性能低)另一个就是builtin也叫内置2d物理系统(不带刚体,性能高)

:wave:谢谢大哥,我切换内置2d物理系统后,之前的方法也可以了。

大哥,还想问一个问题,我碰撞后调用food销毁,food都会过一会才消失,有办法立刻消失吗 :man_kneeling:

    onContactBegin(selfCollider: Collider2D, otherCollider: Collider2D) {
        if (this.isDead) return;
        this.isDead = true;
        // 碰到食物后,销毁食物节点
        this.node?.destroy?.();
    }

改成这个试试

setTimeout(this.node.destroy.bind(this))

这个方法也不行,本来food和head的碰撞触发了food的碰撞回答和head的碰撞回调,我将它们更改为1个,将食物消失放在了head的碰撞回调当中,解决了这个问题