尝试让 Phaser 2 在 Quasar 上运行时出现浏览器错误

I have browser errors when trying to get Phaser 2 to work on Quasar

我正在使用 Phaser 2 并试图让它与 quasar 框架一起工作,但我总是遇到错误。我怀疑可能是webpack配置问题,加上包不兼容问题。

我的quasar.conf.js文件的相关部分如下

...
const webpack = require('webpack');
const path = require('path');

const phaserModule = path.join(__dirname, '/node_modules/phaser/');
const p2 = path.join(phaserModule, 'build/custom/p2.js');
const phaser = path.join(phaserModule, 'build/custom/phaser-split.js');
const pixi = path.join(phaserModule, 'build/custom/pixi.js');

module.exports = function (/* ctx */) {
  return {
      ....
      extendWebpack(cfg) {
        cfg.resolve.extensions = ['.js', '.vue', '.json'];
        cfg.resolve.alias.p2 = p2;
        cfg.resolve.alias.pixi = pixi;
        cfg.resolve.alias.phaser = phaser;
        cfg.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules|quasar)/,
        });
        cfg.module.rules.push({
          test: /\.(frag|vert)$/,
          // loader: 'gl-fragment-loader'
          loader: 'raw-loader',
        });
        cfg.module.rules.push({
          test: /pixi\.js/,
          loader: 'expose-loader',
          options: {
            exposes: {
              globalName: 'PIXI',
              moduleLocalName: 'PIXI',
              override: false,
            },
          },
        });
        cfg.module.rules.push({
          test: /phaser-split\.js$/,
          loader: 'expose-loader',
          options: {
            exposes: {
              globalName: 'Phaser',
              moduleLocalName: 'Phaser',
              override: false,
            },
          },
        });
        cfg.module.rules.push({
          test: /p2\.js/,
          loader: 'expose-loader',
          options: {
            exposes: {
              globalName: 'p2',
              moduleLocalName: 'p2',
              override: false,
            },
          },
        });
        cfg.plugins.push(new webpack.DefinePlugin({
          //  Required by Phaser: Enable the WebGL and Canvas renderers.
          WEBGL_RENDERER: true,
          CANVAS_RENDERER: true,
        }));
      },
    },
  };
};

我的package.json文件如下(请忽略Phaser和Phaser-ce的使用。我知道一个可以代替另一个,但我一直在尝试不同的配置)

{
  ...
  "dependencies": {
    "@quasar/extras": "^1.0.0",
    "amazon-cognito-identity-js": "^4.5.4",
    "axios": "^0.18.1",
    "core-js": "^3.6.5",
    "cross-fetch": "^3.0.6",
    "phaser": "^2.4.6",
    "phaser-ce": "^2.18.0",
    "quasar": "^1.0.0",
    "vue-paystack": "^2.0.4",
    "vue-social-sharing": "^3.0.5",
    "vue-worker": "^1.2.1"
  },
  "devDependencies": {
    "@quasar/app": "^2.0.0",
    "@quasar/quasar-app-extension-dotenv": "^1.0.5",
    "babel-eslint": "^10.0.1",
    "eslint": "^6.8.0",
    "eslint-config-airbnb-base": "^14.0.0",
    "eslint-loader": "^3.0.3",
    "eslint-plugin-import": "^2.20.1",
    "eslint-plugin-vue": "^6.1.2",
    "expose-loader": "^1.0.0",
    "raw-loader": "^4.0.2",
    "script-loader": "^0.7.2"
  },
   ...
}

我的游戏页面如下

<template>
  <div>
    <div :id="containerId"></div>
  </div>
</template>

<script>
/* eslint-disable no-unused-vars */
import 'pixi';
import 'p2';
import Phaser from 'phaser';
/* eslint-enable no-unused-vars */

export default {
  name: 'game',
  data() {
    return {
      game: null,
      containerId: 'gameScreen',
    };
  },
  props: {
    width: {
      type: Number,
      default: document.body.clientWidth,
    },
    height: {
      type: Number,
      default: document.body.clientHeight,
    },
  },
  mounted() {
    const self = this;
    if (this.game === null) {
      debugger;
      this.game = new Phaser.Game(this.width, this.height, Phaser.CANVAS, this.containerId, {
        preload: function preload() {
          self.preload(this);
        },
        create: function create() {
          self.create(this);
        },
        update: function update() {
          self.update(this);
        },
      });
    }
  },
  methods: {
    preload(game) {
      ...
    },
    create(game) {
      ...
    },
    upload(game) {
      ...
    }
  },
};
</script>

最近的错误(有很多)如下所示

我为任何和我有同样挑战的人想出了办法。我真的只需要 phaser-ceexpose-loader 包。我删除了 phaserraw-loaderscript-loader 包。我更新后的 Package.json 文件如下所示

"dependencies": {
    "@quasar/extras": "^1.0.0",
    "amazon-cognito-identity-js": "^4.5.4",
    "axios": "^0.18.1",
    "core-js": "^3.6.5",
    "cross-fetch": "^3.0.6",
    "phaser-ce": "^2.18.0",
    "quasar": "^1.0.0",
    "vue-paystack": "^2.0.4",
    "vue-social-sharing": "^3.0.5",
    "vue-worker": "^1.2.1"
  },
  "devDependencies": {
    "@quasar/app": "^2.0.0",
    "@quasar/quasar-app-extension-dotenv": "^1.0.5",
    "babel-eslint": "^10.0.1",
    "eslint": "^6.8.0",
    "eslint-config-airbnb-base": "^14.0.0",
    "eslint-loader": "^3.0.3",
    "eslint-plugin-import": "^2.20.1",
    "eslint-plugin-vue": "^6.1.2",
    "expose-loader": "^1.0.0"
  },

不过,quasar.conf.js 文件中进行了一些更改。我更改了 expose-loader 的 options.exposes 对象的 globalName 属性。 moduleLocalName 属性 是可选的,所以我删除了它。更新后的文件如下所示:

/*
 * This file runs in a Node context (it's NOT transpiled by Babel), so use only
 * the ES6 features that are supported by your Node version. https://node.green/
 */

// Configuration for your app
// https://quasar.dev/quasar-cli/quasar-conf-js
/* eslint-env node */
/* eslint func-names: 0 */
/* eslint global-require: 0 */

const webpack = require('webpack');
const path = require('path');

const phaserModule = path.join(__dirname, '/node_modules/phaser-ce/');
const p2 = path.join(phaserModule, 'build/custom/p2.js');
const phaser = path.join(phaserModule, 'build/custom/phaser-split.js');
const pixi = path.join(phaserModule, 'build/custom/pixi.js');

module.exports = function (/* ctx */) {
  return {
      ...
      extendWebpack(cfg) {
        cfg.resolve.extensions = ['.js', '.vue', '.json'];
        cfg.resolve.alias.p2 = p2;
        cfg.resolve.alias.pixi = pixi;
        cfg.resolve.alias.phaser = phaser;
        cfg.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules|quasar)/,
        });
        cfg.module.rules.push({
          test: /pixi\.js/,
          loader: 'expose-loader',
          options: {
            exposes: {
              globalName: 'window.PIXI', // changed
              override: false,
            },
          },
        });
        cfg.module.rules.push({
          test: /phaser-split\.js$/,
          loader: 'expose-loader',
          options: {
            exposes: {
              globalName: 'window.Phaser', // changed
              override: false,
            },
          },
        });
        cfg.module.rules.push({
          test: /p2\.js/,
          loader: 'expose-loader',
          options: {
            exposes: {
              globalName: 'window.p2', // changed
              override: false,
            },
          },
        });
        cfg.plugins.push(new webpack.DefinePlugin({
          //  Required by Phaser: Enable the WebGL and Canvas renderers.
          WEBGL_RENDERER: true,
          CANVAS_RENDERER: true,
        }));
      },
    ...
    },
  };
};

最大的变化发生在 gameplay.vue 文件中。更新后的文件如下

<template>
  <div>
    <div id="gameScreen"></div>
  </div>
</template>

<script>
/* eslint-disable no-unused-vars */
import 'pixi';
import 'p2';
import Phaser from 'phaser';
/* eslint-enable no-unused-vars */

export default {
  name: 'game',
  data() {
    return {
      game: null,
      containerId: 'gameScreen',
      game: null,
      width: null,
      height: null,
    };
  },
  mounted() {
  // putting this here ensured the accurate width and height were calculated
    this.width = document.body.clientWidth;
    this.height = document.body.clientHeight;
    const self = this;
    if (this.game === null) {
      // this.width and this.height were returning undefined
      this.game = new Phaser.Game(self.width, self.height, Phaser.CANVAS, "gameScreen", {
        preload: function preload() {
          self.preload(this);
        },
        create: function create() {
          self.create(this);
        },
        update: function update() {
          self.update(this);
        },
      });
    }
  },
  methods: {
   // notice the game object, as opposed to the game parameter. This caused the program to silently break. The `this` parameter passed in the functions belong to the Phaser.Game instance and thus `this.game` also had the same properties in some cases as `this`, causing the silent bug.
    preload({ game }) {
      ...
    },
    create({ game }) {
      ...
    },
    upload({ game }) {
      ...
    }
  },
};
</script>

现在完美运行。