camjocotem
camjocotem

Reputation: 413

What is the best way to share variables across Phaser3 class methods?

I am trying to find a clean, readable way to manage variables across functions in a Phaser Class but for various reasons I am unsatisfied with the solutions I've found.

What I am aware is avaiable:

Global Variables

I'm not very fond of this implementation for the possibility of variables being accessible by other files.

var heroes = [];

var play = new Phaser.Class({
    Extends: Phaser.Scene,

    initialize: function(){
        Phaser.Scene.call(this, {key: 'play'});
    },
    create: function () {
        for(var i = 0; i < 5; i++){
            heroes.add(new Hero())
        }
    },
    update: function(){
        if(!heroes.length){
            heroes.add(new Hero())
        }

        heroes.forEach(function(hero){
            if(hero.hp <= 0){
                hero.destroy();
            }
        });
    }
});

DataManager class (implemented as registry)

I prefer this since it's more controlled but to me DataManager feels like it's intended for configs, not as a means to process/share data between class methods; also accessing and updating variables feels very heavy-handed with a specific service to get and set its values.

var play = new Phaser.Class({
    Extends: Phaser.Scene,

    initialize: function(){
        this.registry.set('heroes', []);
        Phaser.Scene.call(this, {key: 'play'});
    },
    create: function () {
        var heroes = this.registry.get('heroes');

        for(var i = 0; i < 5; i++){
            heroes.add(new Hero())
        }

        this.registry.set('heroes', heroes);
    },
    update: function(){
        var heroes = this.registry.get('heroes');

        if(!heroes.length){
            heroes.add(new Hero())
        }

        heroes.forEach(function(hero){
            if(hero.hp <= 0){
                hero.destroy();
            }
        });

        this.registry.set('heroes', heroes);
    }
});

Using 'this'

This feels the cleanest way to me so far since this refers to the class object and it's easy enough to update and retrieve values BUT in this context 'this' is shared with some internal Phaser specific variables which I want to separate my variables from. Besides namespacing with this are there any alternative solutions?

enter image description here

var play = new Phaser.Class({
    Extends: Phaser.Scene,

    initialize: function(){
        this.heroes = [];
        Phaser.Scene.call(this, {key: 'play'});
    },
    create: function () {
        for(var i = 0; i < 5; i++){
            this.heroes.add(new Hero())
        }
    },
    update: function(){
        if(!heroes.length){
            this.heroes.add(new Hero())
        }

        this.heroes.forEach(function(hero){
            if(hero.hp <= 0){
                hero.destroy();
            }
        });
    }
});

Upvotes: 6

Views: 9705

Answers (3)

Mykhailo Hordiienko
Mykhailo Hordiienko

Reputation: 61

Tried to pass some global data between scenes and found the following. Each scene has its own ref to the global registry. Here is the quote from documentation:

This is a game-wide instance of the Data Manager, allowing you to exchange data between Scenes via a universal and shared point.
In the default set-up you can access this from within a Scene via the this.registry property.

https://photonstorm.github.io/phaser3-docs/Phaser.Data.DataManager.html Here is the doc with the detailed description of the class. Tried this in a recent game - it's very convenient in use.

Upvotes: 5

camjocotem
camjocotem

Reputation: 413

Just realised another way to do it is using a self-invoking function:

In this example heroes will be scoped to the function and also shouldn't pollute the return object;

var play = new Phaser.Class(function(){
    var heroes = [];

    return {
    Extends: Phaser.Scene,

    initialize: function(){
        heroes = [];
        Phaser.Scene.call(this, {key: 'play'});
    },
    create: function () {
        for(var i = 0; i < 5; i++){
            heroes.add(new Hero())
        }
    },
    update: function(){
        if(!heroes.length){
            heroes.add(new Hero())
        }

        heroes.forEach(function(hero){
            if(hero.hp <= 0){
                hero.destroy();
            }
        });
    }
}}());

Upvotes: 1

Kamen Minkov
Kamen Minkov

Reputation: 3747

The cleanest and most readable way in my opinion would be using proper classes (and not instances of Phaser.Class). You can always extend a Phaser class that you need (like here with Phaser.Scene).

TypeScript:

class Play extends Phaser.Scene {
    private heroes: Hero[] = [];

    private create(): void {
        for (let i = 0; i < 5; i++) {
            this.heroes.push(new Hero());
        }
    }

    private update(): void {
        if (!this.heroes.length) {
            this.heroes.push(new Hero());
        }

        this.heroes.forEach((hero) => {
            if (hero.hp <= 0) {
                hero.destroy();
            }
        });
    }

    public initialize(): void {
        Phaser.Scene.call(this, { key: 'play' });
    }
}

ES6 (same, except for type declarations and access modifiers):

class Play extends Phaser.Scene {
    heroes = [];

    create() {
        for (let i = 0; i < 5; i++) {
            this.heroes.push(new Hero());
        }
    }

    update() {
        if (!this.heroes.length) {
            this.heroes.push(new Hero());
        }

        this.heroes.forEach((hero) => {
            if (hero.hp <= 0) {
                hero.destroy();
            }
        });
    }

    initialize() {
        Phaser.Scene.call(this, { key: 'play' });
    }
}

If you're for some reason stuck to ES5, then your last suggestion might be your best bet.

Upvotes: 1

Related Questions