Skip to content
GitHub Twitter

How to move, rotate and scale a prefab with mask inside

Introduction

If you try to add a mask into a container or prefab and use it in your scene, you will recognize that it is not working as you expect. Because masks in phaser uses global coordinates. So if you need to keep your mask in the scene, synchronize their transforms with your container. In this post, I will give you a small tutorial about achieving that.

Prepare assets

For this example I've made two pictures, the Phaser's logo and simple rectangle mask. You can download it if you want.

Prepare prefab

In my case, the prefab extends the class Container, and contains two pictures which I will set from the game scene.

class Prefab extends Phaser.GameObjects.Container {
    constructor(scene, x, y, spriteName, maskName) {
        super(scene, x, y);

        // add to the scene
        scene.add.existing(this);

        // add a logo sprite, attach to the scene
        this.logoSprite = scene.add.sprite(0, 0, spriteName);
        this.add(this.logoSprite);

        // add a mask, set mask as invisible
        this.maskSprite = scene.add.sprite(this.x, this.y, maskName);
        this.maskSprite.setVisible(false);

        // set the maskSprite as a mask to the logoSprite
        this.mask = this.maskSprite.createBitmapMask();
        this.logoSprite.setMask(this.mask);
    }
}

Synchronize the mask position with the prefab

Now you need just add a function which will update the mask transform properties by the prefab's one.

// update the mask transform by postion of the prefab
updateMaskTransform() {
	this.maskSprite.setPosition(this.x, this.y);
	this.maskSprite.setScale(this.scaleX, this.scaleY);
	this.maskSprite.setRotation(this.rotation);
}

Add the prefabs into the scene and try to animate

class Game extends Phaser.Scene {
	constructor() {
		super('Game');
	}

	// load images
	preload(){
		this.logo = this.load.image('logo', './img/logo.png')
		this.mask = this.load.image('logo_mask', './img/logo_mask.png')
	}

	create() {
		//initialize the prefabs, set position and pictures
		const prefab1 = new Prefab(this, 300, 250, 'logo', 'logo_mask');
		const prefab2 = new Prefab(this, 200, 600, 'logo', 'logo_mask');
		
		// apply function for move, rotate and scale the prefabs
		this.scalePrefabWithMask(prefab1);
		this.rotatePrefabwithMask(prefab1);
		
		this.scalePrefabWithMask(prefab2);
		this.movePrefabwithMask(prefab2);
	}

	rotatePrefabwithMask(prefab) {
		this.tweens.add({
			targets: prefab,
			angle: 360,
			duration: 2000,
			//update the mask's transform every frame
			onUpdate: () => prefab.updateMaskTransform(), 
			repeat: -1,
		});
	}

	scalePrefabWithMask(prefab) {
		prefab.setScale(0.5);
		//update the mask's transform after changing the prefab
		prefab.updateMaskTransform();
	}

	movePrefabwithMask(prefab) {
		this.tweens.add({
			targets: prefab,
			x: 400,
			duration: 2000,
			//update the mask's transform every frame
			onUpdate: () => prefab.updateMaskTransform(),
			yoyo: true,
			repeat: -1,
		});
	}	
}

If you done all steps right, you will see the same result.

That's all! I hope this guide will help you. You can see the full setup in the demo project.