question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Spine Pluging stop working with multiple containers

See original GitHub issue

Version

  • Phaser Version: v3.19.0 (WebGL | Web Audio)

Description

Adding a spine to a container works fine, but if you create another container the webGL crash with error:

WebGL: INVALID_OPERATION: bufferSubData: no buffer

Example Test Code

Using this code: https://labs.phaser.io/edit.html?src=src\spine\spine inside container.js

If you add a new container BEFORE the container that contains the spines (just add one line var newCont = this.add.container(400, 300)) the program will crash:



var config = {
    type: Phaser.WEBGL,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    backgroundColor: '#2d2d66',
    scene: {
        preload: preload,
        create: create,
        update: update,
        pack: {
            files: [
                { type: 'scenePlugin', key: 'SpinePlugin', url: 'plugins/SpinePluginDebug.js', sceneKey: 'spine' }
            ]
        }
    }
};

var controls;

var game = new Phaser.Game(config);

function preload ()
{
    this.load.image('logo', 'assets/sprites/phaser.png');

    this.load.setPath('assets/animations/spine/webgl/');

    this.load.spine('boy', 'spineboy-ess.json', 'spineboy.atlas', true);
    this.load.spine('coin', 'coin-pro.json', 'coin.atlas');
}

function create ()
{
    this.add.image(0, 0, 'logo').setOrigin(0);

    var spineBoy = this.add.spine(0, 0, 'boy', 'walk', true).setScale(0.5);
    var coin = this.add.spine(0, 0, 'coin', 'rotate', true).setScale(0.3);

	
    var newCont = this.add.container(400, 300);
    var container = this.add.container(400, 300, [ spineBoy, coin ]);
	

    this.tweens.add({
        targets: container,
        angle: 360,
        duration: 6000,
        repeat: -1
    });

    var cursors = this.input.keyboard.createCursorKeys();

    var controlConfig = {
        camera: this.cameras.main,
        left: cursors.left,
        right: cursors.right,
        up: cursors.up,
        down: cursors.down,
        acceleration: 0.06,
        drag: 0.0005,
        maxSpeed: 1.0
    };

    controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);
}

function update (time, delta)
{
    controls.update(delta);
}

If you add a container AFTER the container that contains the spines (just add one line var newCont = this.add.container(400, 300)) the program will also stop working well with no error message:


var config = {
    type: Phaser.WEBGL,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    backgroundColor: '#2d2d66',
    scene: {
        preload: preload,
        create: create,
        update: update,
        pack: {
            files: [
                { type: 'scenePlugin', key: 'SpinePlugin', url: 'plugins/SpinePluginDebug.js', sceneKey: 'spine' }
            ]
        }
    }
};

var controls;

var game = new Phaser.Game(config);

function preload ()
{
    this.load.image('logo', 'assets/sprites/phaser.png');

    this.load.setPath('assets/animations/spine/webgl/');

    this.load.spine('boy', 'spineboy-ess.json', 'spineboy.atlas', true);
    this.load.spine('coin', 'coin-pro.json', 'coin.atlas');
}

function create ()
{
    this.add.image(0, 0, 'logo').setOrigin(0);

    var spineBoy = this.add.spine(0, 0, 'boy', 'walk', true).setScale(0.5);
    var coin = this.add.spine(0, 0, 'coin', 'rotate', true).setScale(0.3);

	

    var container = this.add.container(400, 300, [ spineBoy, coin ]);
    var newCont = this.add.container(400, 300);
	

    this.tweens.add({
        targets: container,
        angle: 360,
        duration: 6000,
        repeat: -1
    });

    var cursors = this.input.keyboard.createCursorKeys();

    var controlConfig = {
        camera: this.cameras.main,
        left: cursors.left,
        right: cursors.right,
        up: cursors.up,
        down: cursors.down,
        acceleration: 0.06,
        drag: 0.0005,
        maxSpeed: 1.0
    };

    controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);
}

function update (time, delta)
{
    controls.update(delta);
}

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:9 (2 by maintainers)

github_iconTop GitHub Comments

6reactions
justslcommented, Aug 15, 2019

Ok, it seems i got the source of problem.

Its related on new members of renderer:

WebGLRenderer.newType WebGLRenderer.nextTypeMatch

It looks like a little bug in a detection algorithm:

// list is a scene.children.list. 
nextTypeMatch = (i < childCount - 1) ? (list[i + 1].type === this.currentType) : false;
//child is an item of list. And list is a scene.children.list. 
 if (child.type!== this.currentType) 
 {
   this.newType = true;
   this.currentType = child.type;
 }

So if u add an object to the parentContainer it will remove this object from a display list of the scene, and the order of the render-queue will be messed.

The quick solution is to redefine a render function in ur spine objects like this:

create(){

... 
//Code with a problem:
const container = this.add.container(400, 300);
const spineGameObject = this.add.spine(100, 550, 'vine', 'grow', true);
container.add(spineGameObject);
...

//Quick solution:
      const originalRenderWebGL = spineGameObject.renderWebGL;
      spineGameObject.renderWebGL  = function(renderer, ...args) {
                if (this.parentContainer) {
			renderer.nextTypeMatch = false;
			renderer.newType = true;
		}

		return originalRenderWebGL.call (this, renderer, ...args);
      }
}

Better solution is to inherit ur own Spine class with fixes:


import SpineGameObject from "phaser/plugins/spine/src/gameobject/SpineGameObject";

class FixedSpine extends SpineGameObject
{
        .... //Some redefined methods
	renderWebGL (renderer, ...args) {
		if (this.parentContainer) {
			renderer.nextTypeMatch = false;
			renderer.newType = true;
		}

		return super.renderWebGL(renderer, ...args);
	}
}

...//Dont forget to replace original spine class with yours. And reregister your own spine factory.

//You can use my helper
const GOFactory = Phaser.GameObjects.GameObjectFactory;
const GOFactoryProto = GOFactory.prototype;
const register = GOFactory.register;

/**
 * @memberOf Phaser.GameObjects.GameObjectFactory
 * @method register
 * @param {string} type
 * @param {function} creator
 * @param overwrite
 * @param configurable
 */
GOFactory.register = function (type = "type", creator = noop, overwrite = false, configurable = true) {
	if (overwrite) {
		if (!delete GOFactoryProto[type]) {
			return;
		}
	}

	register(type, creator);

	const factory = GOFactoryProto[type];

	if (delete GOFactoryProto[type]) {
		Object.defineProperty(GOFactoryProto, type, {
			value: factory,
			configurable,
			enumerable: true,
			writable: false,
		});
	}
};



//Then use it like this:
const creator = function (x = 0, y = 0, key = "", animationName = "", loop = false) {
...
        let scene = this.scene;

	let spine = new FixedSpine(
		scene,
		scene["spine"], // "spine" is a mapping key for spine plugin.
		x,
		y,
		key,
		animationName,
		loop,
	);

	if (!spine.parentContainer) {
		this.displayList && this.displayList.add && this.displayList.add(spine);
	}

	this.updateList && this.updateList.add && this.updateList.add(spine);
	return spine;
}
Phaser.GameObjects.GameObjectFactory.register("spine", creator, true, false);


//So after that u can simply use this.add.spine(...) like before with ur own spine class.

Hope its gonna help u. Cya

2reactions
justslcommented, Aug 15, 2019

Same here image

W/o another spines in a container looks: image

Read more comments on GitHub >

github_iconTop Results From Across the Web

Phaser 3 API Documentation - Class: SpinePlugin
Therefore, files created in a different version of Spine may not work as a result, without you first updating the runtimes and rebuilding...
Read more >
Spine Web Player - Esoteric Software
Adding the JavaScript & CSS files; Creating a container element ... The Spine Web Player consists of two files: spine-player.js and spine-player.css ....
Read more >
Phaser 3 Dev Log #132: The latest news about the Spine ...
Recent work has centered around adding Spine support in Phaser 3. ... The Phaser plugin adds a bit to the weight, but not...
Read more >
Use Spine with Arcade Physics in Phaser 3 - Ourcade Blog
Adding Arcade Physics to a SpineGameObject may not work well for complex animations · SpinePlugin and TypeScript · Using a Container · Integrate ......
Read more >
Phaser + Spine-Ts : How to get it work?
Since there is no official support of spine by Phaser, ... August 24, 2016 in Phaser 2 ... I already saw your spine...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found