Warning: The magic method EDD_Blocks::__wakeup() must have public visibility in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/edd-blocks-master/edd-blocks.php on line 101

Warning: The magic method EDD_Blocks::__wakeup() must have public visibility in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/edd-blocks/edd-blocks.php on line 101

Warning: The magic method GAINWP_Manager::__wakeup() must have public visibility in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/ga-in/gainwp.php on line 78

Deprecated: Optional parameter $filter declared before required parameter $metric is implicitly treated as a required parameter in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/ga-in/tools/gapi.php on line 555

Deprecated: Optional parameter $filter declared before required parameter $metric is implicitly treated as a required parameter in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/ga-in/tools/gapi.php on line 585

Deprecated: Optional parameter $filter declared before required parameter $metric is implicitly treated as a required parameter in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/ga-in/tools/gapi.php on line 617

Deprecated: Optional parameter $filter declared before required parameter $metric is implicitly treated as a required parameter in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/ga-in/tools/gapi.php on line 651

Deprecated: Optional parameter $filter declared before required parameter $metric is implicitly treated as a required parameter in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/ga-in/tools/gapi.php on line 686

Deprecated: Optional parameter $filter declared before required parameter $metric is implicitly treated as a required parameter in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/ga-in/tools/gapi.php on line 745

Deprecated: Optional parameter $filter declared before required parameter $metric is implicitly treated as a required parameter in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/ga-in/tools/gapi.php on line 785

Warning: Cannot modify header information - headers already sent by (output started at /home/wcc1969/public_html/phasergames.com/wp-content/plugins/edd-blocks-master/edd-blocks.php:101) in /home/wcc1969/public_html/phasergames.com/wp-includes/rest-api/class-wp-rest-server.php on line 1831

Warning: Cannot modify header information - headers already sent by (output started at /home/wcc1969/public_html/phasergames.com/wp-content/plugins/edd-blocks-master/edd-blocks.php:101) in /home/wcc1969/public_html/phasergames.com/wp-includes/rest-api/class-wp-rest-server.php on line 1831

Warning: Cannot modify header information - headers already sent by (output started at /home/wcc1969/public_html/phasergames.com/wp-content/plugins/edd-blocks-master/edd-blocks.php:101) in /home/wcc1969/public_html/phasergames.com/wp-includes/rest-api/class-wp-rest-server.php on line 1831

Warning: Cannot modify header information - headers already sent by (output started at /home/wcc1969/public_html/phasergames.com/wp-content/plugins/edd-blocks-master/edd-blocks.php:101) in /home/wcc1969/public_html/phasergames.com/wp-includes/rest-api/class-wp-rest-server.php on line 1831

Warning: Cannot modify header information - headers already sent by (output started at /home/wcc1969/public_html/phasergames.com/wp-content/plugins/edd-blocks-master/edd-blocks.php:101) in /home/wcc1969/public_html/phasergames.com/wp-includes/rest-api/class-wp-rest-server.php on line 1831

Warning: Cannot modify header information - headers already sent by (output started at /home/wcc1969/public_html/phasergames.com/wp-content/plugins/edd-blocks-master/edd-blocks.php:101) in /home/wcc1969/public_html/phasergames.com/wp-includes/rest-api/class-wp-rest-server.php on line 1831

Deprecated: Automatic conversion of false to array is deprecated in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/publitio-offloading/includes/class-publitio-offloading.php on line 577

Deprecated: Automatic conversion of false to array is deprecated in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/publitio-offloading/includes/class-publitio-offloading.php on line 577

Deprecated: Automatic conversion of false to array is deprecated in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/publitio-offloading/includes/class-publitio-offloading.php on line 577

Deprecated: Automatic conversion of false to array is deprecated in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/publitio-offloading/includes/class-publitio-offloading.php on line 577

Deprecated: Automatic conversion of false to array is deprecated in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/publitio-offloading/includes/class-publitio-offloading.php on line 577

Deprecated: Automatic conversion of false to array is deprecated in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/publitio-offloading/includes/class-publitio-offloading.php on line 577

Deprecated: Automatic conversion of false to array is deprecated in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/publitio-offloading/includes/class-publitio-offloading.php on line 577

Deprecated: Automatic conversion of false to array is deprecated in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/publitio-offloading/includes/class-publitio-offloading.php on line 577

Deprecated: Automatic conversion of false to array is deprecated in /home/wcc1969/public_html/phasergames.com/wp-content/plugins/publitio-offloading/includes/class-publitio-offloading.php on line 577

Warning: Cannot modify header information - headers already sent by (output started at /home/wcc1969/public_html/phasergames.com/wp-content/plugins/edd-blocks-master/edd-blocks.php:101) in /home/wcc1969/public_html/phasergames.com/wp-includes/rest-api/class-wp-rest-server.php on line 1831

Warning: Cannot modify header information - headers already sent by (output started at /home/wcc1969/public_html/phasergames.com/wp-content/plugins/edd-blocks-master/edd-blocks.php:101) in /home/wcc1969/public_html/phasergames.com/wp-includes/rest-api/class-wp-rest-server.php on line 1831
{"id":7205,"date":"2018-09-09T23:01:34","date_gmt":"2018-09-09T23:01:34","guid":{"rendered":"https:\/\/phasergames.com\/?p=7205"},"modified":"2018-09-09T23:01:34","modified_gmt":"2018-09-09T23:01:34","slug":"ui-blocks-a-lightweight-alternate-to-containers","status":"publish","type":"post","link":"https:\/\/phasergames.com\/ui-blocks-a-lightweight-alternate-to-containers\/","title":{"rendered":"Ui Blocks-A lightweight alternate to containers"},"content":{"rendered":"

Phaser Containers Alternative<\/h2>\n

As a developer for a gaming company that has a lot of feedback from its users I understand that people can get very passionate about the features that they’re used to having. I’m afraid I was a victim of that passion about a week ago when I saw this notice from Richard Davey(creator of Phaser).<\/span><\/p>\n

This is just a heads-up for those who track issues that support for\u00a0nested<\/em>\u00a0Containers will be removed from a forthcoming version of Phaser (not 3.12, but probably 3.13).<\/p>\n

The ability to create and use Containers will remain, but you will no longer be able to add a Container as a child of another. Source<\/a><\/p><\/blockquote>\n

I understand and support this decision, but it did leave me with a problem to solve.<\/p>\n

Groups and Containers in Phaser 3<\/h2>\n

Coming from a background of flash I was used to creating MovieClips and adding other objects inside those clips.\u00a0 I especially use this for user interface components. In Phaser\u00a02 I use groups quite a bit to create UI.<\/span><\/p>\n

To understand the problem, we need to understand a bit about groups and containers. Lately, I’ve been seeing a lot of confusion about groups and containers. It is especially confusing for those of us that are coming from Phaser 2. Groups in Phaser 3 do not work the same as in Phaser 2.<\/p>\n

A common question I’ve seen is ” why can I not add a group to a group?”. Let’s have a look at what happens when you add a child to a container or group.<\/p>\n

How Groups Work<\/h2>\n

Here is some simple code that adds 4 images to a scene. We then add 2 images to each of the group and the container.<\/p>\n

create() {\r\n        this.icon1 = this.add.image(100, 100, \"icon1\");\r\n        this.icon2 = this.add.image(200, 200, \"icon2\");\r\n        this.icon3 = this.add.image(300, 300, \"icon3\");\r\n        this.icon4 = this.add.image(400, 400, \"icon4\");\r\n        \/\/\r\n        \/\/\r\n        \/\/\r\n        this.con = this.add.container();\r\n        this.group = this.add.group();\r\n        \/\/\r\n        \/\/\r\n        this.con.add(this.icon1);\r\n        this.con.add(this.icon2);\r\n        \/\/\r\n        \/\/\r\n        this.group.add(this.icon3);\r\n        this.group.add(this.icon4);\r\n    }<\/pre>\n

Now if we log out the scene to the console this is the result<\/p>\n

\"\"<\/a><\/p>\n

As you can see even though we have added the images, icon3 and 4 to the group, they are still on the display list of the scene. The group isn’t anywhere to be seen on the list at all! In Phaser 3\u00a0groups are used to organize game objects. You may group objects together for physics collisions, or simply to have an easy way to iterate through the children.\u00a0 In Phaser 3\u00a0 Sprites, images, texts are always children of the scene.\u00a0 That is except for containers.<\/p>\n

How Containers Work<\/h2>\n

Containers have their own display list. If you add a game object to a container it goes on the container’s list. Here is the output of the container.<\/p>\n

\"\"<\/a><\/p>\n

As you can see, icon1 and icon2 are on the list of the container. So when you change something on the container, those changes will affect all the children on the list.<\/p>\n

So what’s the problem?<\/h2>\n

Because we can add a container to a container and then that container can contain an infinite number of containers it begins to affect the performance of the code.\u00a0 In the words of Richard Davey:<\/span><\/p>\n

Containers can be nested. This means you can insert one Container inside another and branch children off of that. We do not recommend this as the deeper the chain goes, the more expensive every single look-up becomes, as each child traverses the tree back to the root every time it renders.<\/p><\/blockquote>\n

This is what apparently has caused enough problems to eliminate\u00a0container nesting.<\/p>\n

My Workaround<\/h2>\n

\u00a0I do not intend this to serve as a replacement for containers everywhere in every situation. However, a lot of developers I’ve talked to are using containers to build UI, and it is the only way that I am currently using containers.<\/span><\/p>\n

As you can see from the output above phaser containers have bodies this means that physics can be applied to a container. They also have a lot of other things in there such as transform, angle and blend mode that I don’t need for my UI.\u00a0\u00a0<\/span>All I need to do is to find a set of elements that can be positioned relative to another set of coordinates. I’ve also added the functionality to set visibility or not. These features can be expanded but for now, these basics will suffice.<\/span><\/p>\n

For example to create a text button I combine a text field and an image inside a container. say that I want to make a message box, that would require making another container. Then I would have to put the first container(the button) inside the second container.\u00a0<\/span><\/p>\n

This solution solves that problem. It does have its limitations but it’s what I need and I hope that you find it helpful.\u00a0<\/span><\/p>\n

The UIBlock Class<\/h2>\n

The UIBlock class leaves the children on the stage the same way that groups do. I also used a linked list instead of for next Loops to speed up the iteration through the children to update their positions. Everything else is just basic maths.\u00a0<\/span><\/p>\n

class UIBlock {\r\n    constructor() {\r\n        \/\/init private variables\r\n        this._x = 0;\r\n        this._y = 0;\r\n        \/\/\r\n        \/\/\r\n        \/\/keep track of this block's previous position\r\n        this._oldX = 0;\r\n        this._oldY = 0;\r\n        \/\/\r\n        \/\/\r\n        this._visible = true;\r\n        \/\/\r\n        \/\/\r\n        \/\/needs to be set by developer\r\n        this._displayWidth = 0;\r\n        this._displayHeight = 0;\r\n        \/\/\r\n        \/\/\r\n        \/\/an array of the children\r\n        this.children = [];\r\n        \/\/current child count\r\n        \/\/used for indexing\r\n        this.childIndex = -1;\r\n        \/\/\r\n        \/\/used to identify this as a UIBlock to another UIBlock\r\n        this.isPosBlock = true;\r\n    }\r\n    set x(val) {\r\n        \/\/record the current x into oldX\r\n        this._oldX = this._x;\r\n        \/\/\r\n        \/\/update the value\r\n        this._x = val;\r\n        \/\/\r\n        \/\/update the children\r\n        this.updatePositions();\r\n    }\r\n    set y(val) {\r\n        \/\/record the current y into oldY\r\n        this._oldY = this._y;\r\n        \/\/\r\n        \/\/update the value\r\n        this._y = val;\r\n        \/\/update the children\r\n        this.updatePositions();\r\n    }\r\n    \/\/getters\r\n    get x() {\r\n        return this._x;\r\n    }\r\n    get y() {\r\n        return this._y;\r\n    }\r\n    \/\/add a child\r\n    add(child) {\r\n        \/\/up the index\r\n        this.childIndex++;\r\n        \/\/make a note of the index inside the child\r\n        child.childIndex = this.childIndex;\r\n        \/\/add to the array\r\n        this.children.push(child);\r\n        \/\/build the linked list\r\n        this.buildList();\r\n    }\r\n    removeChild(child) {\r\n        \/\/take the child off the array based on index\r\n        this.children.splice(child.childIndex, 1);\r\n        \/\/\r\n        \/\/rebuild the linked list\r\n        this.buildList();\r\n        \/\/rebuild the indexes\r\n        var len = this.children.length;\r\n        for (var i = 0; i < len; i++) {\r\n            this.children[i].childIndex = i;\r\n        }\r\n        \/\/set the childIndex to the length of the array\r\n        this.childIndex = len;\r\n    }\r\n    buildList() {\r\n        var len = this.children.length;\r\n        if (len > 1) {\r\n            for (var i = 1; i < len; i++) {\r\n                \/\/set the current child to the previous child's nextChild property\r\n                this.children[i - 1].nextChild = this.children[i];\r\n            }\r\n        }\r\n        this.children[len - 1].nextChild = null;\r\n    }\r\n    get displayWidth() {\r\n        return this._displayWidth;\r\n    }\r\n    get displayHeight() {\r\n        return this._displayHeight;\r\n    }\r\n    setSize(w, h) {\r\n        this._displayWidth = w;\r\n        this._displayHeight = h;\r\n    }\r\n    setXY(x, y) {\r\n        this.x = x;\r\n        this.y = y;\r\n        this.updatePositions();\r\n    }\r\n    set visible(val) {\r\n        if (this._visible != val) {\r\n            this._visible = val;\r\n            if (this.children.length > 0) {\r\n                \/\/send the first child to the updateChildVisible function\r\n                this.updateChildVisible(this.children[0], val);\r\n            }\r\n        }\r\n    }\r\n    get visible() {\r\n        return this._visible;\r\n    }\r\n    updateChildVisible(child, vis) {\r\n        child.visible = vis;\r\n        if (child.isPosBlock == true) {\r\n            child.visible = vis;\r\n        }\r\n        if (child.nextChild != null) {\r\n            \/\/if the child has a nextChild call this function recursively \r\n            this.updateChildVisible(child.nextChild, vis);\r\n        }\r\n    }\r\n    updateChildPos(child) {\r\n        child.y = child.y - this._oldY + this._y;\r\n        child.x = child.x - this._oldX + this._x;\r\n        if (child.isPosBlock == true) {\r\n            child.updatePositions();\r\n        }\r\n        if (child.nextChild != null) {\r\n            \/\/if the child has a nextChild call this function recursively \r\n            this.updateChildPos(child.nextChild);\r\n        }\r\n        \/\/set the old values to the new\r\n        this._oldX = this._x;\r\n        this._oldY = this._y;\r\n    }\r\n    updatePositions() {\r\n        if (this.children.length > 0) {\r\n            \/\/send the first child to the updateChildPos function\r\n            this.updateChildPos(this.children[0]);\r\n        }\r\n    }\r\n    getRelPos(child) {\r\n        return {\r\n            x: child.x - this.x,\r\n            y: child.y - this.y\r\n        }\r\n    }\r\n    \r\n}<\/pre>\n

Usage<\/h2>\n

My preferred\u00a0way of using this is to extend a class<\/p>\n

class TextButton extends UIBlock {\r\n    constructor(config) {\r\n        super(config.scene);\r\n        \/\/add children\r\n        \r\n        }\r\n}\r\n\r\nvar textButton=new TextButton({scene:this});<\/pre>\n

However, you can also use it this way<\/p>\n

var back = this.add.image(0, 0, \"box\");\r\nvar back = this.add.image(0, 0, \"box\");\r\nvar button = this.add.image(0, 50, \"button\");\r\nvar text=this.add.text(0,-30,\"Message Here\",{color:'#ff0000'}).setOrigin(0.5,0.5);\r\n\r\nblock=new UIBlock();\r\n\r\nblock.add(back);\r\nblock.add(button);\r\nblock.add(text);\r\n\r\nblock.x=240;\r\nblock.y=300;<\/pre>\n

Result:<\/p>\n

\"\"<\/a><\/p>\n

Limitations<\/h2>\n

These are the main features missing from the UIBlock:<\/p>\n