Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mask behaviour when there are nested containers. #3673

Closed
kanthi0802 opened this issue May 18, 2018 · 29 comments
Closed

Mask behaviour when there are nested containers. #3673

kanthi0802 opened this issue May 18, 2018 · 29 comments

Comments

@kanthi0802
Copy link

kanthi0802 commented May 18, 2018

Hi,

We have a component kind of List. It basically extends Container and creates children which are also of type Containers. Each of these children contain a background image and some text objects to display data, they are aligned vertically in the parent list container. Now the issue is when we are trying to apply mask to the parent container , the text children in second level containers are not being rendered at all. Only the background image is rendered.

Further more input events seems to be working on the game objects which are masked .


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@RollinSafary
Copy link

even if you have sprite in container mask isn't working

var config = {
    type: Phaser.WEBGL,
    parent: 'phaser-example',
    width: 640,
    height: 480,
    scene: {
        preload: preload,
        create: create,
        update: update
    }
};

var loadBar;
var t = 0.0;
var text;
var game = new Phaser.Game(config);

function preload() {

    this.load.image('swirl', 'assets/pics/color-wheel-swirl.png');
    this.load.image('checker', 'assets/pics/checker.png');
    this.load.bitmapFont('gothic', 'assets/fonts/bitmap/gothic.png', 'assets/fonts/bitmap/gothic.xml');
}

function create() {
    var container = this.add.container()
    loadBar = this.add.graphics();

	var checker = this.make.image({
		x: game.config.width / 2,
		y: game.config.height / 2,
		key: 'checker',
		add: true
	});


    var swirl = this.make.sprite({
    	x: game.config.width / 2, 
    	y: game.config.height / 2, 
    	key: 'swirl',
    	add: true
    });
    container.add(swirl)

    loadBar.x = game.config.width / 2;
    loadBar.y = game.config.height / 2;

    swirl.mask = new Phaser.Display.Masks.BitmapMask(this, loadBar);
    text = this.add.dynamicBitmapText(game.config.width / 2 - 20, game.config.height / 2 - 15, 'gothic', '0%', 32);

}

function update()
{
    var step = Math.abs(Math.sin(t)) * 400;

    loadBar.clear();
    loadBar.lineStyle(40, 0, 1);
    loadBar.beginPath();
    loadBar.arc(0, 0, 100, 0, Phaser.Math.DegToRad(-step), false);
    loadBar.strokePath();
    loadBar.closePath();

    t += 0.01;

    text.setText((step / 400 * 100).toFixed(0) + '%')
}

@photonstorm
Copy link
Collaborator

From the docs:

 * Containers can have masks set on them and can be used as a mask too. However, Container children cannot be masked.
 * The masks do not 'stack up'. Only a Container on the root of the display list will use its mask.

@kanthi0802
Copy link
Author

Hi Rich ,
Thank you :) I've gone through the docs prior to opening this issue. However what i do not understand is, if the mask does not apply to the children in the container at all, it should not to any of the children.

But as i explained above , I can see the mask being applied ( as intended ) to the Image objects nested in the containers, but the text objects are not even being rendered at all.

Also from #3491 , I see a quote mentioning
"When we add Containers you can apply a mask at the root level (i.e. the Container itself can have a mask, which will impact all children)". By this I understand that mask also gets applied to the children in a Container. Please correct me if i'm wrong.

@photonstorm
Copy link
Collaborator

My comment was directed at the post above by @RollinSafary which clearly has a child of a container with a mask enabled on it, which isn't going to work.

It doesn't entirely surprise me that a container within a container doesn't pick-up the parent mask properly, but I'll need to spend time creating some tests to see it happening.

Also, there's no way the input system can tell if an object is masked from view or not, so you're absolutely going to have to deal with that situation yourself, regardless of the outcome of the main part of this issue.

@kanthi0802
Copy link
Author

kanthi0802 commented May 23, 2018

Hi Rich ,
If you require a code example i'm happy to provide it. Please let me know. Currently we have project considerably complex that runs on Phaser V2 . We are planning to migrate it to V3. We see some hurdles like blurred text mentioned in 3528, which I'd hope will be fixed with ScaleManager implementation. The mask in Phaser V2 did work as per our needs in the example mentioned above. These are the only things currently stopping us from migrating to V3. Rest all works pretty awesome . Cheers 👍

@photonstorm
Copy link
Collaborator

Masks in v2 were all geometry based, do you see the same thing happen with containers with a geometry mask? (and yes, if you have a demo that'd be extremely useful)

@kanthi0802
Copy link
Author

Hi Rich,
I've come up with an example. Please check it here. The mask applied to the container is Geometry mask. When run on mobile device under CANVAS render mode the mask does not even apply at all and the FPS drops to ~20 also when used BitmapText instead of Text it does not render BitmapText Objects at all.

@barvynkoa
Copy link

Disappointing... I decided to move my games to phaser 3 and I've also found this. When I have global parent container (I'm using it for scaling all game objects) and want some child to be masked - seems I can't do that. The heart is broken :(

@RollinSafary
Copy link

@flahhi it's resolvable, you can extend from Phaser.GameObjects.Container and by overriding setScale() method get what you wish ) Children that you have added in group (in v2) you can push to any array in your class to have reference on them, and add them to scene, so giving mask will work and setScale() after override too
I'm understanding that it's not the expected way to resolve the problem, but it's one of ways )

@kanthi0802
Copy link
Author

@RollinSafary I did't quite understand what you said.

@kanthi0802
Copy link
Author

@photonstorm . Hi Rich. Any update on this :) ?

@phaserjs phaserjs deleted a comment from dondon67 May 31, 2018
@photonstorm
Copy link
Collaborator

No, not yet. Like I said, I need to spend time creating examples to reproduce this, because yours was far too large for what is needed for debugging. Example code should be isolated and as tiny as possible.

@barvynkoa
Copy link

Here is an example with an additional container and the mask doesn't work because not supported, like Rich said.
https://jsfiddle.net/6j62op87/1/
So, I'm trying to found the solution.
@RollinSafary Thanks for your answer! But I'm afraid I don't catch the idea. Would you be so kind to provide an example?

@photonstorm , @kanthi0802 if you guys have time, please check the example, maybe it helps with debugging

Also, I found one more weird thing. Here is another example:
https://jsfiddle.net/06mctd8w/1/
Without strokeRect mask has "painting" effect 😄

And here is the basics how the mask works :
https://jsfiddle.net/ptksfckj/1/
Added it here to have even one example working good :)

@kanthi0802
Copy link
Author

kanthi0802 commented Jun 1, 2018

@photonstorm . the example mentioned above is the same as the one mentioned in #3722. I'm afraid I cannot make it simpler. But i'm attaching screen shots so that you get an idea.

auto mode with container nesting

This occurs when there is a container nesting ( Phaser.AUTO mode ), meaning A parent container ---- N number of children which are also containers --- Each child container has three text objects and an image as children.

auto mode with no container nesting

This occurs almost in a similar way but there are not text objects added to the child container ( Phaser.AUTO mode ) , meaning
A parent container ---- N number of children which are also containers --- Each child container has an image as a child.


canvas mode

This occurs when there is a container nesting ( Phaser.CANVAS mode ), meaning
A parent container ---- N number of children which are also containers --- Each child container has three text objects and an image as children. Please observe the mask is not even applied.


expected
And finally this is the expected behaviour :)

@kanthi0802
Copy link
Author

@flahhi . Gone through the examples. Removing the strokeRect gives a painting effect indeed. Looks good actually :) . But this happens only in CANVAS mode . In AUTO mode it works like it is intended to. :). I'm not equipped to say why there is a difference in CANVAS and AUTO modes

@purnakrishnap
Copy link

Hi, @photonstorm . We are also facing a similar kind of issue. Any updates on this?. It would be very helpful to us if this issue gets fixed.

@jowy
Copy link

jowy commented Jun 12, 2018

This would be great!

@pradeeppenugonda
Copy link

Hi @photonstorm, we are facing similar issue, could you please look into this ASAP, it would be a great help, if we have a fix.

@yashwanthkoppula
Copy link

@photonstorm, any update on this ?
facing similar issue.

@jjalonso
Copy link

jjalonso commented Jul 8, 2018

same

@RichardGale
Copy link

RichardGale commented Oct 30, 2018

Maybe related. Maybe a different issue. I have a similar use case, scrolling lists that need to be clipped against something.

It would appear that any form of masking on an object is ignored if the object is in a container.

For example, take the labs sample, https://labs.phaser.io/view.html?src=src\display\masks\geometry%20mask\multiple%20image%20mask.js, and add the first image to a container

function create ()
{
    var cont = this.add.container(0,0); // <<== added this, container at origin
    var image1 = this.add.image(0, 0, 'pic1').setOrigin(0);
    var image2 = this.add.image(320, 0, 'pic2').setOrigin(0);
    var image3 = this.add.image(0, 256, 'pic3').setOrigin(0);
    var image4 = this.add.image(320, 256, 'pic4').setOrigin(0);

    cont.add(image1); // <<== added this
    var shape = this.make.graphics();

The original labs sample has the hash mark masking all the graphics, with the above change the hash mark ignores the graphic in the container even though it is still added.

@photonstorm
Copy link
Collaborator

This is correct, in so much as it's always been like this and is mentioned specifically in the documentation. It's not great, but until I rewrite both Containers and the way masks work (or someone submits a PR), it's going to remain like it for now.

@galarant
Copy link

Shame, I am running into this issue too

@ADM87
Copy link

ADM87 commented Jan 24, 2019

Came across this issue as well. It's preventing setting up sorting layers and UI elements such as progress bars, carousels, etc from being grouped together and animated around the screen.

@spayton
Copy link
Contributor

spayton commented Mar 21, 2019

I wanted and needed this functionality too.

You can modify the container render function to apply child masks in much the same way that masks are applied in the scene render loop of the root display list. This will give you a little more functionality to be able to apply a mask further down the container tree, rather than only at the root.

But, this will not handle the correct reapplication of masks as the container traversal moves passed the child mask and back up towards the root. For that, there needs to be a proper mask manager to reapply higher level masks after lower level masks have been passed.

I also noticed a problem with spines, they kill any masking when they restore the pipeline after rendering, eg to a masked container add a spine and then some other images (or spines), result only the 1st spine gets masked. Having a proper mask manager could also solve this problem.

Also worth mentioning is Rex's Container Lite, it works differently but may work enough for some. It's worth noting that it applies the mask to every child render rather than just once for the container, there'll be a performance hit for this.

@photonstorm
Copy link
Collaborator

The new Geometry Mask system is now in the master branch. It has a proper mask stack and will support child - parent depths up to 255 levels deep (the same as Phaser 2). Masks are also batched to avoid redundant stencil ops, which has improved performance massively across the board.

You can see this in the following tests:

http://labs.phaser.io/view.html?src=src%5Cdisplay%5Cmasks%5CContainer%20Mask%20Test%203.js&v=dev

and

http://labs.phaser.io/view.html?src=src%5Cdisplay%5Cmasks%5CMask%20Perf%20Test.js&v=dev

(warning: swapping the perf test demo back to 3.16 may crash some browsers!)

@spayton
Copy link
Contributor

spayton commented Dec 13, 2019

@photonstorm just tried again and noticed that spines with their own clipping that are inside containers do not apply the clipping, but if outside a container then their own clipping works.

Does the spine runtime work with the new mask system and should work, or is this an existing limitation?

@scott20145
Copy link

@photonstorm How can I apply this feature when target is CANVAS renderer? The code seems only supported for WEBGL mode

@photonstorm
Copy link
Collaborator

@scott20145 Bitmap Masks are WebGL only. Geometry Masks are both WebGL and Canvas.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests