Phaser 3(游戏框架):collider回调被调用,但somethimes对象仍然穿过其他对象,而不是碰撞

Phaser 3 (Game framework): collider callback is called, but somethimes object still passes through other object, instead of colliding

我正在制作一个小型 flappy-bird-like-game 演示。一切似乎都很好,但我有一个小 problem/question.

我设置了一个 collider 函数,回调按预期工作,当“两个”对象发生碰撞时,但有一个奇怪的行为:

但是回调总是执行。

蓝色箭头标记正方形通过的地方
绿色箭头标记方块未通过的地方

我不确定这是不是因为我使用的矩形 (它们有时) 会导致问题,或者因为我的嵌套物理设置。 我什至尝试用精灵替换白色矩形,但这仍然产生相同的结果 result/error。

For my demo: I could probablly just destroy the object and restart the level on collision, but I still would like to understand why this is happening? And how I can prevent this, inconsistant behavior.
I'm probably missing something, but couldn't find it, and I don't want to rebuild the application again.

所以我的问题是:为什么会这样?我该如何防止这种情况?

代码如下:

const width = 400;
const height = 200;

const spacing = width / 4;

const levelSpeed = width / 4;
const flySpeed = width / 4;

var GameScene = {
    create (){

    let player = this.add.rectangle(width / 4, height / 2, 20, 20, 0xffffff);
    this.physics.add.existing(player);

    this.input.keyboard.on('keydown-SPACE', (event) => {
        if(player.body.velocity.y >= -flySpeed/2){
            player.body.setVelocityY(-flySpeed);
        }
    });

    player.body.onWorldBounds = true;
    player.body.setCollideWorldBounds(true );

    this.physics.world.on("worldbounds", function (body) {
      console.info('GAME OVER');
      player.y = height / 2;
      player.body.setVelocity(0);
    });

    this.pipes = [];

    for(let idx = 1; idx <= 10; idx++) {
        let obstacle = this.createObstacle(spacing * idx, Phaser.Math.Between(-height/3, 0));
        this.add.existing(obstacle);
        this.pipes.push(obstacle);
        
        this.physics.add.collider(obstacle.list[0], player)
        this.physics.add.collider(obstacle.list[1], player, _ => console.info(2))
    }
},

update(){
    this.pipes.forEach((item) => {
        if(item.x <= 0){
            item.body.x = spacing * 10;
        } 
    })
},
extend: {
    createObstacle (x, y){

        let topPipe = (new Phaser.GameObjects.Rectangle(this, 0, 0 , 20 , height / 2 ,0xff0000)).setOrigin(0);
        let bottomPipe = (new Phaser.GameObjects.Rectangle(this, 0, height/2 + 75, 20 , height / 2 ,0xff0000)).setOrigin(0);

        this.physics.add.existing(topPipe);
        this.physics.add.existing(bottomPipe);
        
        topPipe.body.setImmovable(true);
        topPipe.body.allowGravity = false;

        bottomPipe.body.setImmovable(true);
        bottomPipe.body.allowGravity = false;

        let obstacle = new Phaser.GameObjects.Container(this, x, y, [
            topPipe,
            bottomPipe
        ]);

        this.physics.add.existing(obstacle);

        obstacle.body.velocity.x = - levelSpeed;
        obstacle.body.allowGravity = false;

        return obstacle;
    }
}
};



var config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width,
    height,
    scene: [GameScene],
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: flySpeed },
            debug: true
        },
    }
};

var game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>

目前我只能假设,当物理对象嵌套时,物理对象似乎无法正常工作。

也许我错了, 但是因为我在没有 nested physics - objects 的情况下再次重写了代码并且它似乎工作,我认为我的假设是正确的。 我不应该过度设计我的代码。

If someone has more insides, please let me know/share. I still not 100% sure, if this is the real reason, for the strange behavior.

重写代码:

const width = 400;
const height = 200;

const spacing = width / 4;

const levelSpeed = width / 4;
const flySpeed = width / 4;

var GameScene = {
    create (){

    let player = this.add.rectangle(width / 4, height / 2, 20, 20, 0xffffff);
    this.physics.add.existing(player);

    this.input.keyboard.on('keydown-SPACE', (event) => {
        if(player.body.velocity.y >= -flySpeed/2){
            player.body.setVelocityY(-flySpeed);
        }
    });

    player.body.onWorldBounds = true;
    player.body.setCollideWorldBounds(true );

    this.physics.world.on("worldbounds", function (body) {
      console.info('GAME OVER');
      player.x = width / 4;
      player.y = height / 2;
      player.body.setVelocity(0);
    });

    this.pipes = [];

    for(let idx = 1; idx <= 10; idx++) {
        let obstacle = this.createObstacle(spacing * idx, Phaser.Math.Between(-height/3, 0));
        this.add.existing(obstacle[0]);
        this.add.existing(obstacle[1]);
        this.pipes.push(...obstacle);
        
        this.physics.add.collider(obstacle[0], player)
        this.physics.add.collider(obstacle[1], player, _ => console.info(2))
    }
},

update(){
    this.pipes.forEach((item) => {
        if(item.x <= 0){
            item.body.x = spacing * 10;
        } 
        item.body.velocity.x = - levelSpeed;
    })
},
extend: {
    createObstacle (x, y){

        let topPipe = (new Phaser.GameObjects.Rectangle(this, x, -20 , 20 , height / 2 ,0xff0000)).setOrigin(0);
        let bottomPipe = (new Phaser.GameObjects.Rectangle(this, x, height/2 + 75, 20 , height / 2 ,0xff0000)).setOrigin(0);

        this.physics.add.existing(topPipe);
        this.physics.add.existing(bottomPipe);
        
        topPipe.body.setImmovable(true);
        topPipe.body.allowGravity = false;
        topPipe.body.velocity.x = - levelSpeed;

        bottomPipe.body.setImmovable(true);
        bottomPipe.body.allowGravity = false;
        bottomPipe.body.velocity.x = - levelSpeed;

        return [topPipe, bottomPipe];
    }
}
};



var config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width,
    height,
    scene: [GameScene],
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: flySpeed },
            debug: true
        },
    }
};

var game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>