在Phaser3类方法之间共享变量的最佳方法是什么?

5
我正在尝试找到一种干净、易读的方法,在Phaser类中跨函数管理变量,但出于各种原因,我对已找到的解决方案不满意。
我所知道的选择有:
全局变量
我不太喜欢这种实现方式,因为变量可能会被其他文件访问。
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类(实现为注册表)

我更喜欢这种方式,因为它更加可控。但是对我而言,DataManager感觉像是用于配置,而不是作为在类方法之间处理/共享数据的手段;另外,访问和更新变量需要使用特定的服务来获取和设置其值,感觉非常笨重。

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);
    }
});

使用'this'

对我来说这是目前最简洁的方法,因为'this'指的是类对象,很容易更新和检索值,但在这种情况下,'this'与一些内部Phaser特定变量共享,我想将我的变量与其分开。除了使用'this'进行命名空间外,还有其他替代方案吗?

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();
            }
        });
    }
});

好问题!那么在类之间使用全局变量怎么样? - Ventoh
如果我想在不同的类之间共享变量(而不是在类的方法中) ,那么我会使用单个全局变量(可能由类名作为命名空间)。但我试图避免意外地向其他类公开类内部的工作方式。我的目标是使每个单独的类在其自己的方法中共享变量,而不将该变量归属于另一个对象(this.heroes属于已经有其他属性的对象,如this.A、this.B、this.Heroes、this.C)。自调用似乎迄今为止已经满足了我所有的需求。 - camjocotem
3个回答

4
尝试在场景之间传递全局数据时,发现每个场景都有自己的全局注册表引用。以下是文档中的引用:
“这是数据管理器的游戏范围实例,允许您通过通用和共享点在场景之间交换数据。 在默认设置中,您可以通过this.registry属性从场景内访问它。” https://photonstorm.github.io/phaser3-docs/Phaser.Data.DataManager.html 这是具有详细说明的类的文档。我在最近的游戏中尝试了这个功能 - 使用起来非常方便。

this.registry worked for me! It can be used like this: this.registry.set('playerData', {lives: 0, deaths: 0, health: 100}) and can then be retrieved like this: this.registry.get('playerData') - Florestan Korp

1

在我看来,最清晰可读的方式是使用适当的类(而不是Phaser.Class的实例)。你可以随时扩展你需要的Phaser类(就像在这里使用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(除了类型声明和访问修饰符外):
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' });
    }
}

如果你因某些原因被困在ES5中,那么你的最后一个建议可能是最好的选择。

我并不完全局限于ES5,只是我和我的朋友对ES6的经验不够丰富。 话虽如此,我已经想到了一个我喜欢的ES5解决方案,但我会先尝试这个并进行比较,因为它肯定读起来更好 :) - camjocotem
我建议你看一下TypeScript。是的,它会增加一点额外的开销(你不能直接使用你的代码,你必须有一个构建步骤,这也是ES6的情况 - 虽然大多数现代浏览器直接兼容,但你会看到很多项目使用Babel来针对ES5),但一旦你的项目开始增长,它就可以节省很多麻烦。 - Kamen Minkov
Phaser3似乎还没有完整的TS定义,所以我尝试使用ES6来使其正常工作。 尽管我遵循了这个教程:http://codetuto.com/2018/02/getting-started-phaser-3-es6-create-boomdots-game/ 但是源代码映射似乎不起作用(可能是因为我对webpack缺乏经验),这使得调试有些困难。 除此之外,如果我使用"this.",它看起来我的变量仍然会与Phaser库变量共享相同的作用域,所以我认为我将坚持使用ES5解决方案。 在我们更熟悉Phaser之后,我们可能会再次回到ES6。 - camjocotem

1

我刚意识到另一种方法是使用自执行函数:

在这个例子中,英雄将被限定在函数内部,也不会污染返回对象;

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();
            }
        });
    }
}}());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接