How do you get the height and width of a container? If you’ve been playing around with Phaser 3 containers for a while, and are accustomed to using Phaser 2 groups, you may notice some familiar things missing. A few months ago I added some sprites to a container for building some user interface components. I needed to know the container size, so I could line things up properly and found that the width wasn’t set. Here is an example of what I mean.
First let’s start by preloading some images, and placing them on the stage and adding them inside a container
class SceneMain extends Phaser.Scene {
constructor() {
super('SceneMain');
}
preload() {
for (var i = 0; i < 4; i++) {
this.load.image("dot" + i, "images/" + i + ".png");
}
}
create() {
this.container = this.add.container();
this.dot1 = this.add.image(100, 250, "dot0");
this.dot2 = this.add.image(400, 250, "dot1");
//
//
this.dot3 = this.add.image(100, 400, "dot2");
this.dot4 = this.add.image(400, 400, "dot3");
//
//
//
this.container.add(this.dot1);
this.container.add(this.dot2);
this.container.add(this.dot3);
this.container.add(this.dot4);
//
//
console.log(this.container);
}
}
Inspecting the container
When we look in the developer console where we logged out the container and locate the displayWidth and displayHeight properties, we can see that the values are 0. (You’ll need to click the …).
Containers do not update their size, but it can be done manually. This can be done by using the setSize method of the container class. First, though we need to know what the size is. If we are making something like a message box, or anything that has a square background we can use the background’s size for the container. If we have several sprites inside like the example above we need to use some simple maths to accomplish this.
Calculate the container size
To get the size we need to make a square out the sprites. We can do this by getting the extreme positions of all the child sprites of the container. By this I mean the topmost, bottom most, and the greatest left and right positions.
getSize(con) {
//set the top position to the bottom of the game
var top = game.config.height;
var bottom = 0;
//set the left to the right of the game
var left = game.config.width;
var right = 0;
//
//
//loop through the children
//
con.iterate(function(child) {
//get the positions of the child
var childX = child.x;
var childY = child.y;
//
//
//
//test the positions against
//top, bottom, left and right
//
if (childY > bottom) {
bottom = childY;
}
if (childY < top) {
top = childY;
}
if (childX < left) {
left = childX;
}
if (childX > right) {
right = childX;
}
}.bind(this));
//calculate the square
var h = Math.abs(top - bottom);
var w = Math.abs(right - left);
//set the container size
con.setSize(w, h);
}
Usage
In the create function call the following code
this.getSize(this.container);
console.log(this.container);
Now when we log out the container, we can see the size has been set to 300 for the displayWidth and 150 for the displayHeight.
More Precision
While this gives us a size, it is not an exact size because it doesn’t take the origin of the image into account. Let’s add in that part now.
getSize(con) {
//set the top position to the bottom of the game
var top = game.config.height;
var bottom = 0;
//set the left to the right of the game
var left = game.config.width;
var right = 0;
//
//
//loop through the children
//
con.iterate(function(child) {
//get the positions of the child
var childX = child.x;
var childY = child.y;
//
//
//
var childW = child.displayWidth;
var childH = child.displayHeight;
//
//
//calcuate the child position
//based on the origin
//
//
var childTop = childY - (childH * child.originY);
var childBottom = childY + (childH * (1 - child.originY));
var childLeft = childX - (childW * child.originX);
var childRight = childX + (childW * (1 - child.originY));
//test the positions against
//top, bottom, left and right
//
if (childBottom > bottom) {
bottom = childBottom;
}
if (childTop < top) {
top = childTop;
}
if (childLeft < left) {
left = childLeft;
}
if (childRight > right) {
right = childRight;
}
}.bind(this));
//
//calculate the square
var h = Math.abs(top - bottom);
var w = Math.abs(right - left);
//set the container size
con.setSize(w, h);
}
Testing the code
Now how can we make sure that this is getting the container size correctly? Let’s draw a square based on the positions, just to test it out. Add this code to the end of the getSize function
this.graphics = this.add.graphics();
this.graphics.fillStyle(0xff00ff, .4);
this.graphics.fillRect(left,top,w,h);
More Testing
This works well for our dots that are already in a square, but will it work if we more the dots? That’s the beauty of using maths to find the container size. Let’s change how we are placing the dots. Let’s add the dots into random positions. Replace the code in the create function with the following code:
create() {
this.container = this.add.container();
for (var i = 0; i < 4; i++) {
var xx = Phaser.Math.Between(200, 400);
var yy = Phaser.Math.Between(100, 500);
var dot = this.add.image(xx, yy, "dot" + i);
this.container.add(dot);
}
this.getSize(this.container);
}
And here is the result
Thanks for this example, it brought me on the way to find the solution. I found that you can actually call the method container.getBounds() which returns a Geom.Rectangle object with the proper info needed like your code. Maybe this method wasn’t available at the time of writing this tutorial.
To follow-up on my previous comment, it seems like container.getBounds() doesn’t take into account any BitmapText objects. The BitmapText class doesn’t have a .getBounds() method, but has a .getTextBounds(), so maybe that’s why. I don’t know if this is a bug, but unless the BitmapText is included by container.getBounds(), then your solution still holds.
Hi Benjamin,
I’m not sure if it was available or not, but at least at the time, you had to manually set the size of the container.
Container.setSize(100,100)
I’m not sure if that has changed.