Register gameobject class with matter physics

How do you create subclasses derived from Phaser.Physics.Matter.Sprite and register them to instantiate them like

this.matter.add.myMatterSprite(...)

I know how to register Sprite subclasses but no clue on how to do it matter physics sprites.

Ok, I think I see the problem: there is no register function on the Matter.Factory class.

I did found a workaround though:

Lander.js

import Phaser from "phaser";

class Lander extends Phaser.Physics.Matter.Sprite {
    
    update(time, delta) {
        super.update(time, delta);
        /* gameobject update logic */
    }
}

Phaser.GameObjects.GameObjectFactory.register('lander', function (x, y, key, frame, matterOptions) {
        
        var lander = new Lander(this.scene.matter.world, x, y, key, frame, matterOptions);

        this.displayList.add(lander);
        this.updateList.add(lander);

        return lander;
    }
);

export default Lander;

So that now I can do on my scene:

import Phaser from "phaser";
import Lander from "/gameobjects/space/Lander";
class SpaceScene extends Phaser.Scene {
    //...
    create() {
       //...
       var lander = this.add.lander(
           this.scale.width/2, 
           this.scale.height*.9, 
           'space', 'lander.png', 
           { 
                shape: matterShapes['lander']
           }
       );
       //...
    }
}

Being a maniac as I am I don’t find very elegant to invoke a matter physics factory function directly from the scene, but I guess there is nothig I can do about it without modifying the phaser source code, right?

Ok, being stubborn in addition to a maniac and reading how the register function is injected in the GameObjectFactory prototype I found a better(*) solution.

Import this file after phaser, but before your scene classes on your index.js (or whatever js file you use as entry point)

MatterFactoryRegister.js

Phaser.Physics.Matter.Factory.register = function (factoryType, factoryFunction) {
    if (!Phaser.Physics.Matter.Factory.prototype.hasOwnProperty(factoryType))
    {
        Phaser.Physics.Matter.Factory.prototype[factoryType] = factoryFunction;
    }
}

Lets you register the Matter.Sprite subclass into the Matter factory this way:

Lander.js

import Phaser from "phaser";

class Lander extends Phaser.Physics.Matter.Sprite {
    
    update(time, delta) {
        super.update(time, delta);
        /* gameobject update logic */
    }
}

Phaser.Physics.Matter.Factory.register('lander', 
    function (x, y, key, frame, matterOptions) {
        var lander = new Lander(this.scene.matter.world, x, y, key, frame, matterOptions);

        this.sys.displayList.add(lander);
        this.sys.updateList.add(lander);

        return lander;
    }
);

export default Lander;

And so you can do this in your scene:

SpaceScene.js

import Phaser from "phaser";
import Lander from "/gameobjects/space/Lander";
class SpaceScene extends Phaser.Scene {
    //...
    create() {
       //...
       var lander = this.matter.add.lander(
           this.scale.width/2, 
           this.scale.height*.9, 
           'space', 'lander.png', 
           { 
                shape: matterShapes['lander']
           }
       );
       //...
    }
}

Which is what I originally was looking for.

:wink:

EDIT:
(*) Actually it’s not a very good idea to modify native or library prototypes on the fly because in a later version of phaser we could be overwriting library functionality, so it’s better to do something like this (kinda polyfill):
MatterFactoryRegister.js

if (!Phaser.Physics.Matter.Factory.register) {

    Phaser.Physics.Matter.Factory.register = function (factoryType, factoryFunction) {
        if (!Phaser.Physics.Matter.Factory.prototype.hasOwnProperty(factoryType))
        {
            Phaser.Physics.Matter.Factory.prototype[factoryType] = factoryFunction;
        }
    }
}
3 Likes

You can actually just extend the Matter.Sprite class and add it to your scene. Makes for an easier solution (in TypeScript):

export default class SpriteCharacter extends Phaser.Physics.Matter.Sprite {
  constructor(scene: Scene, spriteTexture: string, x: number, y: number) {
    super(scene.matter.world, x, y, spriteTexture, 0)
    scene.add.existing(this)
  }
}