geckosio / phaser-on-nodejs

Allows you to run Phaser 3 game (including Phaser's physics engines) on Node.js
MIT License
102 stars 11 forks source link

Unable to use plugins #13

Open TomYeoman opened 2 years ago

TomYeoman commented 2 years ago

Describe the bug

Loving the project so far, thanks for keeping it up to date. I may be missing something but it seems plugins are not working for now -

Using the following code -

require("@geckos.io/phaser-on-nodejs");
import Phaser from "phaser";
import PhaserMatterCollisionPlugin from "phaser-matter-collision-plugin";

// @ts-ignore
import { phaserGameConfig, serverFPS } from "../../../common/config/phaserConfig";
global.phaserOnNodeFPS = serverFPS; // default is 60

// prepare the config for Phaser
const config = {
  ...phaserGameConfig,
  type: Phaser.HEADLESS,
  audio: false,
  fps: {
    target: serverFPS,
    forceSetTimeOut: true,
  },
  plugins: {
    scene: [
      {
        plugin: PhaserMatterCollisionPlugin, // The plugin class
        key: "matterCollision", // Where to store in Scene.Systems, e.g. scene.sys.matterCollision
        mapping: "matterCollision" // Where to store in the Scene, e.g. scene.matterCollision
      }
    ]
  }
};

export default config;

I then use in the scene as such -


      //@ts-ignore
      console.log(this.scene.matterCollision);
      //@ts-ignore
      this.scene.matterCollision.addOnCollideActive({
        objectA: bot,
        objectB: [Object.entries(this.playerSystem.playerGraphics)],
        callback: ({ gameObjectA, gameObjectB }: any) => {
          console.log("COLLISSSION ALLLEEERRTTTT");
        },
      });

However review the following error -

image

xptavares commented 2 years ago

I found a workaround using this.game.plugins.installScenePlugin

Remove plugins from game config:

const config = {
  type: Phaser.HEADLESS,
  width: 512,
  height: 512,
  banner: false,
  audio: false,
  scene: [MainScene],
  fps: {
    target: FPS
  },
  physics: {
    default: 'matter',
    matter: {
      debug: false,
      gravity: { y: 0 },
    }
  },
}

and at my MainScene#preload I did this:

const PhaserMatterCollisionPlugin = require('phaser-matter-collision-plugin')

module.exports = class MainScene extends Phaser.Scene {
  constructor() {
    super('MainScene')
  }

  preload() {
    this.game.plugins.installScenePlugin('matterCollision', PhaserMatterCollisionPlugin.default, 'matterCollision', this);
    this.matterCollision.start()
  }

Note

Call start method is very important without it the colliders won't work.

TomYeoman commented 1 year ago

Perfect worked a charm! Thanks very much @xptavares

hubertgrzeskowiak commented 1 month ago

Just stumbled upon this bug while developing a plugin for Phaser and it took me a few hours to realise this is a bug in Phaser on NodeJS.

Any idea where the bug could be?

UPDATE: I looked into it a little more and it looks like plugins are in fact loading and being started, but only AFTER the whole game has booted and the first scene started, whereas on the web the plugins are all part of the boot process before any scene is started.

hubertgrzeskowiak commented 1 month ago

One workaround I found for starting the game with plugins loaded is to not add any in the global config and instead start the first scene through the game object:

const game = new Phaser.Game(config);
game.scene.add("SampleScene", SampleScene, true)

The downside, aside from being unintuitive, is that the __SYSTEM scene will not have any plugins installed

hubertgrzeskowiak commented 2 weeks ago

Another workaround, not sure whether it's any better:

const config: GameConfig = {
  ...
  callbacks: {
    preBoot: BROWSER ? undefined : (game) => {
      // The existing plugin manager is booted too late in the process when running in headless mode, but we can not
      // explicitly boot it, and it's not safe to override it, because it's already hooked into the game's boot event.
      // Instead, we give the existing plugin manager some dummy objects to work on, and then replace it with a new one
      // that gets booted immediately.
      // @ts-ignore
      game.plugins.game = {config: new Config(), events: new EventEmitter()};
      game.plugins = new PluginManager(game);
    }
  },
  scene: [SampleScene]
};

The downside of this approach is that whatever the global plugins do with the plugin manager instance (e.g. installing scene plugins) gets lost...