'Phaser 3 - Groups of Dynamic Sprites Not Colliding

I can’t get two groups of dynamic sprites or a dynamic sprite and a group of dynamic sprites to collide. I can get each to collide with groups of static sprites that make up the level, but not the dynamic ones.

If I setup a collider for the sprites themselves instead of the group, they work fine. Not sure what’s going on.

Here is a link to my code. Could someone take a look?

https://github.com/deusprogrammer/mega-man-clone/blob/master/src/scripts/scenes/mainScene.ts



Solution 1:[1]

The reason why the collisions doesn't work, is the physics - body of the group of enemies, seems to be interfering with, physics objects of the objects inside of the group.

Just replace the line 19 this.enemyGroup = this.physics.add.group(); (from the linked file) mainScene.ts, with this line this.enemyGroup = this.add.group(); and the collisions should work.

That line will only create a "simple" phaser group, without a physics body.

Here a running demo:
(I stripped your code, down to only essentials)

    class MegaMan extends Phaser.Physics.Arcade.Sprite {
        constructor(scene, x, y) {
            super(scene, x, y, 'megaman');
            scene.add.existing(this);
            scene.physics.add.existing(this);

            this.bulletGroup = scene.physics.add.staticGroup();

            this.scale *= 2;
            this.body.setSize(22, 22);
            this.setOrigin(0.5, 0.5);

            this.setCollideWorldBounds(true).setInteractive();

            this.controls = {
                up: this.scene.input.keyboard.addKey('W'),
                down: this.scene.input.keyboard.addKey('S'),
                left: this.scene.input.keyboard.addKey('A'),
                right: this.scene.input.keyboard.addKey('D'),
                jump: this.scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE),
                shoot: this.scene.input.keyboard.addKey('J')
            };
        }

        update() {
            super.update();

            // Controls
            if (this.controls.right.isDown) {
                this.setVelocityX(150);
            } else if (this.controls.left.isDown) {
                this.setVelocityX(-150);
            } else {
                this.setVelocityX(0);
            }

            // If player is jumping
            if (this.controls.jump.isDown && this.body.touching.down) {
                this.setVelocityY(-400);
            }

            if (this.controls.shoot.isDown && !this.isShooting) {
                this.isShooting = true;

                let megaBusterShot = this.scene.physics.add.sprite(this.x + 32, this.y, 'wood1');
                this.bulletGroup.add(megaBusterShot);

                megaBusterShot.body.allowGravity = false;
                megaBusterShot
                    .refreshBody()
                    .setVelocityX(this.flipX ? 300 : -300);

                setTimeout(() => {
                    this.isShooting = false;
                }, 200);
            }

        }

        onHit() {
            console.log("OUCH");
        }
    }

    class MetHat extends Phaser.Physics.Arcade.Sprite {


        constructor(scene, x, y) {
            super(scene, x, y, 'methat');
            scene.add.existing(this);
            scene.physics.add.existing(this);

            this.scale *= 1.5;

            this.state = "idle";

            this.setCollideWorldBounds(true);
            this.setInteractive();
            this.refreshBody();
        }

        onCollision() {

            if (this.body.touching.left) {
                this.body.velocity.x = 200;
            } else if (this.body.touching.right) {
                this.body.velocity.x = -200;
            }
        }

        onHit(weapon) {
            this.destroy();
        }

        update() {
            if (this.scene.game.loop.frame % 500 === 0 && this.body.touching.down && this.state === 'idle') {

                this.state = 'standing';

                // Make him start walking shortly after standing up
                setTimeout(() => {
                    this.state = 'walking';
                    this.setVelocityX(-200);
                }, 200);

                // Make him idle again after 10 seconds.
                setTimeout(() => {
                    this.state = 'idle';
                    this.setVelocityX(0);
                }, 3000);
            }

        }
    }

    
let assetMap = {
    "W1": {},
  "W2": {},
    "W3": {
        name: "wood3",
        file: "https://github.com/deusprogrammer/mega-man-clone/raw/master/src/assets/img/wood3.png",
    },
    "W4": {
        name: "wood4",
        file: "https://github.com/deusprogrammer/mega-man-clone/raw/master/src/assets/img/wood4.png",
    },
}

    const levels = {
        level1: {
            tilemap: [
              
                ["W3", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "W3"],
                ["W3", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "W3"],
                ["W3", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "W3"],
                ["W3", "  ", "  ", "  ", "  ", "W4", "W4", "  ", "  ", "  ", "  ", "W3"],
                ["W3", "  ", "  ", "  ", "  ", "W4", "W4", "  ", "  ", "  ", "  ", "W3"],
                ["W4", "W4", "W4", "W4", "W4", "W4", "W4", "W4", "W4", "W4", "W4", "W4"],
              
            ],
            blocksX: 12,
            blocksY: 6,
            nextLevel: 'level2'
        }
    }

    class Level extends Phaser.GameObjects.GameObject {

        constructor(scene, levelConfig) {
            super(scene, 'level');
            this.levelConfig = levelConfig;

            scene.add.existing(this);
            scene.physics.add.existing(this);

            this.blocks = this.scene.physics.add.staticGroup();

            for (let y = 0; y < this.levelConfig.blocksY; y++) {
                for (let x = 0; x < this.levelConfig.blocksX; x++) {
                    let asset = assetMap[this.levelConfig.tilemap[y][x]];

                    if (!asset) {
                        continue;
                    }

                    let block = scene.physics.add.staticSprite(x * 32, y * 32, 'floor');
                    block.scale *= 2;
                    block.setOrigin(0, 0)
                        .setPushable(false)
                        .setImmovable(true)
                        .setGravity(0)
                        .refreshBody();
                    this.blocks.add(block);
                }
            }
        }
    }

    class MainScene extends Phaser.Scene {

        constructor() {
            super({ key: 'MainScene' });
        }

        preload(){
            let graphics;
            graphics = this.make.graphics({x: 0, y: 0});
            graphics.fillStyle(0xffffff, 1);
            graphics.fillRect(0, 0, 22, 22);
            graphics.generateTexture('megaman', 22, 22);

            graphics.fillStyle(0xff0000, 1);
            graphics.fillRect(0, 0, 22, 22);
            graphics.generateTexture('methat', 22, 22);

            graphics.fillStyle(0xcdcdcd, 1);
            graphics.fillRect(0, 0, 16, 16);
            graphics.generateTexture('floor', 16, 16);
            
        }

        create() {
            this.player = new MegaMan(this, 60, 0);
            this.level = new Level(this, levels['level1']);

            this.enemyGroup = this.add.group();
            this.enemyGroup.add(new MetHat(this, 300, 0));

            // Doesn't work?  Why?
            this.physics.add.collider(this.player, this.enemyGroup, () => {

                this.player.onHit();
            });
            this.physics.add.collider(this.player.bulletGroup, this.enemyGroup, (megaBusterShot, obj2) => {
                let enemy = obj2;
                megaBusterShot.destroy();
                enemy.onHit(megaBusterShot);
            });

            // Works
            this.physics.add.collider(this.player.bulletGroup, this.level.blocks, (megaBusterShot) => {
                megaBusterShot.destroy();
            });
            this.physics.add.collider(this.enemyGroup, this.level.blocks, (obj) => {
                let enemy = obj;
                enemy.onCollision();
            });

            this.physics.add.collider(this.player, this.level.blocks);
        }

        update() {
            this.player.update();
            this.enemyGroup.children.each((enemy) => {
                enemy.update();
            })
        }
    }

    const config = {
        type: Phaser.AUTO,
        backgroundColor: '#0000000',
        scene: [MainScene],
        width: 400,
        height: 248,
        physics: {
            default: 'arcade',
            arcade: {
                debug: true,
                gravity: { y: 600 }
            }
        }
    }

    const game = new Phaser.Game(config)
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>

I had a similar problem (https://stackoverflow.com/a/70944607/1679286), seems to be a problem with nesten Objects, that have physics bodies.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1