Search code examples
javascriptcanvasphaser-frameworkpixi.js

How to create mask for a whole container in Phaser 3?


I am trying to create a planet with a background, sphere shadow and a mask, it was pretty straightforward to implement this in Phaser 2, but now it has a bunch of tricky parts for me

Once I update the mask property of my container, nothing is displayed at all. I have already tried several Masks groups, but couldn't succeeded...

In other words: I need to "put" the rectangle background inside of a sphere by using a circle mask

What am I doing wrong? Is there any other better way to do this maybe?

so here is the method I use:

init({ x, y, size, sprite, id }) {
    const container = this.scene.add.container(x, y);

    const width = (1200 / 300) * 200;
    const height = 200;

    const earthBMD = this.scene.textures.createCanvas(`earthBMD${id}`, width, height);
    earthBMD.draw(0, 0, this.scene.textures.get(`map-${size}-${sprite}`).getSourceImage());
    const planet = this.scene.add.sprite(0, 0, earthBMD).setOrigin(0.5).setAngle(-15);

    const shadow = this.scene.add.sprite(0, 0, 'sphere').setOrigin(0.5, 0.5).setScale(0.5);

    const mask = this.scene.make.graphics(0, 0).fillStyle(1000000, 0.5).fillCircle(0, 0, 150);

    container.add([planet, mask, shadow]);
    container.mask = new Phaser.Display.Masks.GeometryMask(this.scene, mask);

    return container;
}

Solution

  • Should be pretty easy to create the desired effect (atleast with this basic GameObjects). I'm not sure where your init function is inside. If it is in a Scene, you just have to remove the scene from this.scene...., than it should work. (and that would be the underlining issue)

    p.s.: don't add the mask to the container, like in this line container.add([planet, mask, shadow]); except you want the mask Image/Shape to be rendered on the canvas.

    here a stripped down example:

    document.body.style = 'margin:0;';
    
    var config = {
        type: Phaser.CANVAS,
        width: 536,
        height: 183,
        scene: {
            create
        },
        banner: false
    }; 
    
    function create () {
    
        const container = this.add.container(0, 0);
    
        const width = config.width;
        const height = config.height;
    
        let g = this.make.graphics({add:false});
        
        g.fillStyle(0xffff00)
        g.fillRect(10,10, 150, 150);
        
        g.generateTexture('map', 150, 150);
    
      
        const planet = this.add.sprite(50, 10, 'map')
          .setOrigin(0)
    
        const mask = this.make.graphics({add:false})
          .fillStyle(1000000, 0.5)
          .fillCircle(0, 0, 200);
        
    
        container.add([planet]);
    
        container.mask = new Phaser.Display.Masks.GeometryMask(this, mask);
    
    }
    
    new Phaser.Game(config);
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>

    P.s.: the officials examples are pretty good. Checkout these examples