Jump to content

Multiple wierd rendering issues in our game; sudden onset, cannot find the cause


Sixmorphugus
 Share

Recommended Posts

yxxgCj5m.png

jriE0mUm.png

 

This stuff started happening when I added some UI stuff to our game, such as these window objects:

// Message boxMsgBox = function (game, spawnX, spawnY, mWidth, type, var0, var1, callback, callbackObj) {    spawnX = Math.floor(spawnX);    spawnY = Math.floor(spawnY);        this.timePlaced = game.time.time;    this.destroyAfter = 0;        this.advanceSound = game.add.audio("speach");        this.origin = new Phaser.Point(spawnX, spawnY);        if(this.origin.x < (mWidth / 2) + 10) {        this.origin.x = (mWidth / 2) + 10;    }        this.game = game;        this.rect = this.game.add.sprite(spawnX, spawnY, "whiteout");    this.rect.alpha = 1;    this.rect.tint = 0x111111;        this.boarders = [];    this.boarders.push(this.game.add.sprite(spawnX, spawnY, "whiteout"));    this.boarders.push(this.game.add.sprite(spawnX, spawnY, "whiteout"));    this.boarders.push(this.game.add.sprite(spawnX, spawnY, "whiteout"));    this.boarders.push(this.game.add.sprite(spawnX, spawnY, "whiteout"));        this.boarders[0].alpha = 0;    this.boarders[1].alpha = 0;    this.boarders[2].alpha = 0;    this.boarders[3].alpha = 0;        this.rect.width = 0;    this.rect.height = 0;        this.rect.alpha = 0;        this.boxType = type;    this.boxPerams1 = var0;    this.boxPerams2 = var1;        this.result = -1;        this.deleteMe = false;        this.referenceText = [];    this.visibleText = [];        this.maxWidth = mWidth;        this.callback = callback;    this.callbackObj = callbackObj;        this.selectedOp = 0;    this.opChange = false;    this.opDown = true;        this.calculateAppearence();}MsgBox.prototype.constructor = MsgBox;MsgBox.prototype.skipFade = function() {    this.rect.alpha = 0.9;        this.boarders[0].alpha = 0.9;    this.boarders[1].alpha = 0.9;    this.boarders[2].alpha = 0.9;    this.boarders[3].alpha = 0.9;}MsgBox.prototype.prepareDelete = function() {    this.deleteMe = true; // tell the uiManager to get rid of us in the next update tick        // remove shared    this.rect.destroy();        //this.advanceSound.destroy();        this.boarders[0].destroy();    this.boarders[1].destroy();    this.boarders[2].destroy();    this.boarders[3].destroy();        if(this.continuer != null) {        this.continuer.destroy();    }        // remove any text lines    for(var i = 0; i < this.referenceText.length; i++) {        this.referenceText[i].destroy();        this.visibleText[i].destroy();    }        // call callbacks    if(this.callback != null) {        if(this.result != -1) {            this.callback.call(this.callbackObj, this.result);        }        else {            this.callback.call(this.callbackObj);        }    }}MsgBox.prototype.calculateTextLines = function() {    var string = this.boxPerams1;    var assumedLetterWidth = 12;    var lettersToFillBox = Math.floor(this.maxWidth / assumedLetterWidth);        var lCount = 0;        for(var i = 0; i < string.length; i++) {        lCount += 1;                if(lCount > lettersToFillBox) {            insertNewLineAt = i;                        while(string[insertNewLineAt] != " ") {                insertNewLineAt -= 1;            }                        string = string.replaceAt(insertNewLineAt, "#");                        lCount = 0;        }    }        var linesToCreate = string.split("#");        for(var i = 0; i < linesToCreate.length; i++) {        this.referenceText.push(this.game.add.bitmapText(this.rect.x + 4, this.rect.y + 4 + (i * 22), "goldfishWhite", linesToCreate[i], 18));        this.visibleText.push(this.game.add.bitmapText(this.rect.x + 4, this.rect.y + 4 + (i * 22), "goldfishWhite", "", 18));                this.referenceText[i].updateTransform();        this.visibleText[i].updateTransform();                this.visibleText[i].stage = 0;        this.referenceText[i].alpha = 0;    }}MsgBox.prototype.calculateOptionLines = function() {    var linesToCreate = this.boxPerams1;        for(var i = 0; i < linesToCreate.length; i++) {        this.referenceText.push(this.game.add.bitmapText(this.rect.x + 4, this.rect.y + 4 + (i * 22), "goldfishWhite", linesToCreate[i], 18));        this.visibleText.push(this.game.add.bitmapText(this.rect.x + 4, this.rect.y + 4 + (i * 22), "goldfishWhite", "", 18));                this.referenceText[i].updateTransform();        this.visibleText[i].updateTransform();                this.visibleText[i].stage = 0;        this.referenceText[i].alpha = 0;                // check if disabled        if(this.boxPerams2[i] == -1) { // menu art            this.visibleText[i].alpha = 0.1;            this.referenceText[i].noSelect = true;        }                if(this.boxPerams2[i] == 0) { // disabled option            this.visibleText[i].alpha = 0.5;            this.referenceText[i].noSelect = true;        }    }}MsgBox.prototype.calculateAppearence = function() {    if(this.boxType == 0) { // text box        this.calculateTextLines();                // calculate the size that the box will be with the text inside.        var width = this.maxWidth; //this.textLines[0].textWidth + 6;        var height = (this.referenceText.length * 22) + 4;                this.rect.width = width;        this.rect.height = height;                // calculate the position of the top left        var boxX = this.origin.x - (Math.floor(width/2));        var boxY = this.origin.y - (height);                this.rect.position.set(boxX, boxY);                // add boarders        this.boarders[0].position.set(boxX, boxY-2);        this.boarders[0].width = width;        this.boarders[0].height = 2;                this.boarders[1].position.set(boxX, boxY + height);        this.boarders[1].width = width;        this.boarders[1].height = 2;                this.boarders[2].position.set(boxX-2, boxY);        this.boarders[2].width = 2;        this.boarders[2].height = height;                this.boarders[3].position.set(boxX + width, boxY);        this.boarders[3].width = 2;        this.boarders[3].height = height;                // move all text into the new position        for(var i = 0; i < this.referenceText.length; i++) {            this.referenceText[i].position.set(boxX + 3, boxY + 3 + (i * 22));            this.visibleText[i].position.set(boxX + 3, boxY + 3 + (i * 22));        }                if(this.boxPerams2 == 0) { // "press to continue" message box            // place the continuer            this.continuer = this.game.add.sprite(boxX, boxY, "speachCont");                        this.continuer.alpha = 0;                        this.continuer.animations.add("flash", [0, 1], 2, true);            this.continuer.animations.play("flash");                        this.continuer.position.set((boxX + width) - 30, (boxY + height) - 5);        }        else if(this.boxPerams2 > 0) { // forever message box (must be removed manually)            // schedule the destruction of this box.            this.destroyAfter = this.boxPerams2;        }                // boxes with negative times stay forever and must be removed manually    }    else if(this.boxType == 1) {        // do an options box        this.calculateOptionLines();                // calculate the size that the box will be with the text inside.        var width = this.maxWidth; //this.textLines[0].textWidth + 6;        var height = (this.referenceText.length * 32) + 4;                this.rect.width = width;        this.rect.height = height;                // calculate the position of the top left        var boxX = this.origin.x - (Math.floor(width/2));        var boxY = this.origin.y - (height);                this.rect.position.set(boxX, boxY);                // add boarders        this.boarders[0].position.set(boxX, boxY-2);        this.boarders[0].width = width;        this.boarders[0].height = 2;                this.boarders[1].position.set(boxX, boxY + height);        this.boarders[1].width = width;        this.boarders[1].height = 2;                this.boarders[2].position.set(boxX-2, boxY);        this.boarders[2].width = 2;        this.boarders[2].height = height;                this.boarders[3].position.set(boxX + width, boxY);        this.boarders[3].width = 2;        this.boarders[3].height = height;                // move all text into the new position        for(var i = 0; i < this.referenceText.length; i++) {            // center texts            var xPos = (boxX + (width / 2)) - ((this.referenceText[i].text.length * 12) / 2) + 2;            xPos = Math.floor(xPos);                        this.referenceText[i].position.set(xPos, boxY + 6 + (i * 32));            this.visibleText[i].position.set(xPos, boxY + 6 + (i * 32));        }                // place the continuer - except NOW IT'S A SELECTOR OMFG MLG M8 WTFBBQ        this.continuer = this.game.add.sprite(boxX, boxY, "speachSel");        this.continuer.animations.add("flash", [0, 1], 2, true);        this.continuer.animations.play("flash");    }}MsgBox.prototype.inputUpdate = function() {    if(this.deleteMe) {        return;    }        if(this.boxType == 0) { // text box        if(this.continuer == null) {            return;        }                if(this.continuer.alpha == 1 && this.game.input.keyboard.downDuration(Phaser.Keyboard.ENTER, 1)) {            // remove message            this.prepareDelete();            return;        } else if(this.game.input.keyboard.downDuration(Phaser.Keyboard.ENTER, 1)) {            // autocomplete message            for(var i = 0; i < this.referenceText.length; i++) {                while(this.visibleText[i].stage < this.referenceText[i].text.length) {                    this.visibleText[i].stage += 1;                    this.visibleText[i].text = this.referenceText[i].text.slice(0, this.visibleText[i].stage);                }            }        }    }    else if(this.boxType == 1) {                if(this.game.input.keyboard.downDuration(Phaser.Keyboard.UP, 1) || this.game.input.keyboard.downDuration(Phaser.Keyboard.W, 1)) {            this.opChange = true;            this.opDown = false;                        if(BasicGame.playSFX)                this.advanceSound.play('', 0, BasicGame.sfxVol);        }        else if(this.game.input.keyboard.downDuration(Phaser.Keyboard.DOWN, 1) || this.game.input.keyboard.downDuration(Phaser.Keyboard.S, 1)) {            this.opChange = true;            this.opDown = true;                        if(BasicGame.playSFX)                this.advanceSound.play('', 0, BasicGame.sfxVol);        }                if(this.game.input.keyboard.downDuration(Phaser.Keyboard.ENTER, 1)) {            this.result = this.selectedOp;            this.prepareDelete();        }    }}MsgBox.prototype.update = function() {    // handle fade in    if(this.rect.alpha < 0.8) {        this.rect.alpha += 0.1;                this.boarders[0].alpha += 0.1;        this.boarders[1].alpha += 0.1;        this.boarders[2].alpha += 0.1;        this.boarders[3].alpha += 0.1;    }        if(this.deleteMe) {        return;    }        // delete now?    if(this.destroyAfter != 0) {        if(this.game.time.elapsedSince(this.timePlaced) > this.destroyAfter) {            this.prepareDelete();        }    }        if(this.boxType == 0) { // msg box        // scroll the text in according to referenceText        for(var i = 0; i < this.referenceText.length; i++) {            if(this.visibleText[i].stage < this.referenceText[i].text.length) {                for(var j = 0; j < BasicGame.dialogSpeed && this.visibleText[i].stage < this.referenceText[i].text.length; j++) {                    this.visibleText[i].stage += 1;                    this.visibleText[i].text = this.referenceText[i].text.slice(0, this.visibleText[i].stage);                }                                if(!this.advanceSound.isPlaying)                    if(BasicGame.playSFX)                        this.advanceSound.play('', 0, BasicGame.sfxVol);                                return;            }        }                if(this.continuer != null) {            this.continuer.alpha = 1;        }    } else if(this.boxType == 1) {        // all text appears immediately        for(var i = 0; i < this.referenceText.length; i++) {            if(this.visibleText[i].stage < this.referenceText[i].text.length) {                this.visibleText[i].stage = this.referenceText[i].text.length;                this.visibleText[i].text = this.referenceText[i].text.slice(0, this.visibleText[i].stage);            }        }                // make sure the continuer selects a valid option        while(this.referenceText[this.selectedOp].noSelect || this.opChange) {            this.opChange = false;                        if(this.opDown) {                this.selectedOp += 1;            }            else {                this.selectedOp -= 1;            }                        if(this.selectedOp > this.referenceText.length-1) {                this.selectedOp = 0;            }            if(this.selectedOp < 0) {                this.selectedOp = this.referenceText.length-1;            }        }                        // move continuer to selection        this.continuer.position.set(this.rect.position.x - 8, this.referenceText[this.selectedOp].position.y);    }}// UI Object - manages message boxes with unique lines of text + option selectionuiObject = function(game) {    this.game = game;        this.activeDialogs = [];        this.sequenceData = [];    this.sequenceStringCache = "";    this.sequenceLocation = new Phaser.Point();    this.sequenceCallback = null;    this.sequenceCallbackObj = null;}uiObject.prototype.constructor = uiObject;uiObject.prototype.update = function() {    // update active dialog    if(this.activeDialogs.length > 0) {        this.getActiveBox().inputUpdate(); // only the topmost dialog can take input    }        // make sure all the boxes do their normal thing    for(var i = 0; i < this.activeDialogs.length; i++) {        // if a dialog is done doing stuff, destroy it        if(this.activeDialogs[i].deleteMe) {            this.activeDialogs.splice(i, 1);            continue;        }                this.activeDialogs[i].update();    }        // sequences    if(this.sequenceData.length > 0) {        var advanceToNext = false;                if(this.activeDialogs.length > 0) { // crowbar in an sanity check to prevent the otherwise inevitable crash            var dlg = this.getActiveBox();                        if(dlg.boxPerams1 != this.sequenceStringCache) {                advanceToNext = true; // this box is irrelevant to us, we can continue our sequence            }        } else {            // no dialogs are open but several are waiting to open. Open them!            advanceToNext = true;        }                if(advanceToNext) {            this.sequenceStringCache = this.sequenceData.pop(); // pop next msg off the array;                        if(this.sequenceFirst) {                this.newMessageBox(this.sequenceLocation.x, this.sequenceLocation.y, this.sequenceStringCache, 0);                this.sequenceFirst = false;            }            else if(this.sequenceData.length == 0) { // finish the sequence by calling the sequence callbacks                box = this.newMessageBox(this.sequenceLocation.x, this.sequenceLocation.y, this.sequenceStringCache, 0, this.sequenceCallback, this.sequenceCallbackObj);                                box.skipFade();            } else { // otherwise, just display the message                box = this.newMessageBox(this.sequenceLocation.x, this.sequenceLocation.y, this.sequenceStringCache, 0);                                box.skipFade();            }        }    }}uiObject.prototype.closeActiveBox = function() {    this.activeDialogs[this.activeDialogs.length-1].prepareDelete();}uiObject.prototype.getActiveBox = function() {    return this.activeDialogs[this.activeDialogs.length-1];}uiObject.prototype.newMessageBox = function(spawnX, spawnY, message, timeToVanish, callback, callbackObject) {    boxLength = (message.length * 12) + 6;        if(boxLength > 550) {        boxLength = 550;    }        // timeToVanish can be set to 0 to make an advancable dialog, or -1 to make a static one.    var box = new MsgBox(this.game, spawnX, spawnY, boxLength, 0, message, timeToVanish, callback, callbackObject);    this.activeDialogs.push(box);        return box;}  uiObject.prototype.newOptionsBox = function(spawnX, spawnY, optionsArray, optionTypesArray, callback, callbackObject, selectedOp) {    // which option is longest    curLongestStringSize = 0;        for(var i = 0; i < optionsArray.length; i++) {        if(optionsArray[i].length > curLongestStringSize) {            curLongestStringSize = optionsArray[i].length;        }    }        boxLength = (curLongestStringSize * 12) + 6;        var box = new MsgBox(this.game, spawnX, spawnY, boxLength, 1, optionsArray, optionTypesArray, callback, callbackObject);    this.activeDialogs.push(box);        if(selectedOp != null) {        box.selectedOp = selectedOp;        box.update();    }        return box;}uiObject.prototype.sequenceMessageBox = function(spawnX, spawnY, messagesArray, callback, callbackObject) {    this.sequenceData = messagesArray.reverse();    this.sequenceStringCache = "";    this.sequenceLocation.x = spawnX;    this.sequenceLocation.y = spawnY;    this.sequenceCallback = callback;    this.sequenceCallbackObj = callbackObject;    this.sequenceFirst = true;}

And this splash screen:

create: function () {        if(!this.fail) {            this.bootLogo = this.add.sprite(this.game.canvas.width / 2, this.game.canvas.height / 2, "mmLogo");            this.bootLogo.anchor.set(0.5, 0.5);            this.bootLogo.alpha = 0;            this.logoIn = true;        } else {            this.bootLogo = this.add.sprite(this.game.canvas.width / 2, this.game.canvas.height / 2, "mmNope");                        this.bootLogo.anchor.set(0.5, 0.5);        }    },        update: function() {        if(this.fail) {            return;        }        if(this.logoIn) {            if(this.bootLogo.alpha < 1) {                this.bootLogo.alpha += 0.005;            } else {                this.logoIn = false;            }        }        else {            if(this.bootLogo.alpha > 0.1) {                this.bootLogo.alpha -= 0.005;            } else {                this.game.state.start('Preloader');            }        }                if(this.game.input.keyboard.isDown(Phaser.Keyboard.ENTER)) {             this.game.state.start('Preloader');        }    }

The problems themselves vary and I was only able to capture two. They happen in both WebGL mode and Canvas mode, with WebGL exhibiting the most stability.

According to my tester, the following can also manifest:

Ethnikoi: HOMEthnikoi: plus flickeringEthnikoi: plus framerapeEthnikoi: plus tile taeringSixsmorphugus: holy shitEthnikoi: plus missing backgroundEthnikoi: plus random artifacting

I feel I should probably say I'm very new to Phaser and there are probably better ways to do a lot of the things I'm doing. I am very much willing to consider alternative methods in order to fix the problem.

Link to comment
Share on other sites

It's impossible to tell from this post alone what is going on. There's too much code which no-one here can run, and too little info.

 

What size are your assets? (pixel dimensions, not file size). Does it work fine UNTIL you add the UI or was it messing up before that? What devices are you testing it on? etc.

Link to comment
Share on other sites

It's impossible to tell from this post alone what is going on. There's too much code which no-one here can run, and too little info.

 

Sorry about that. Our project was very big when the bugs started happening, and for all I know it might not be the things I've included that cause them. I can send you the entire project file or parts of it if you need more information.

 

 

What size are your assets? (pixel dimensions, not file size).

Sizes vary. The mmLogo and mmNope sprites are 546x150 pixels. The speachSel sprites are each 32x16 and have animation frames that are 16x16. The goldfishWhite font is a bitmap font created via a texture atlas, and "whiteout" is simply a 1x1 image that is stretched and recoloured to form the boarders of dialog windows.

 

The tileset of the world shown in the picture is 768x960 (each tile in it is 32x32),

 

 

Does it work fine UNTIL you add the UI or was it messing up before that?

When I test the game and do not instantuate any UI, no issues are present in the menu screen. The Game state always has issues, however, even if I remove the UI object; these issues seem much worse in Canvas mode. Occasionally, the game will crash completely and the message "Uncaught TypeError: Failed to execute 'createPattern' on 'CanvasRenderingContext2D': The provided value is not of type '(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap)'" will appear in the console, originating from PIXI. I have no idea what it means. Notably, upon crashing, all graphics glitches will revert just before the frame freezes; the background will correct itself, split tiles will rejoin etc.

 

 

What devices are you testing it on?

 

This game is for keyboard-and-mouse based systems only. If you try and run it on a mobile, it will display a message telling the user that the game is not compatible with mobile devices and not start. We are testing primarily on Windows 7, Windows 8 and Ubuntu using the Chrome browser.

 

Sorry to be a bother. The project files are so big that I don't know how to give you everything without flooding the topic with information.

Link to comment
Share on other sites

Getting an error in 'createPattern' is interesting - that would come from the TilingSprite class in Pixi.

 

Are you sure you're not doing something really expensive in a main loop? Like creating a TileSprite that is stupidly big, or using something like generateTexture or cacheBitmap on an object over and over?

Link to comment
Share on other sites

I think I found the cause.

 

I created a state that shows a menu (one of the objects that will cause the glitches when present) and tracked the bug to a part of my uiObject

this.rect = this.game.add.sprite(spawnX, spawnY, "whiteout");this.rect.alpha = 0;this.rect.tint = 0x111111;

This sprite serves as the "background" of a GUI window or message box. It is 1x1 and I stretch it to the size it needs to be, calculating that size automatically (boarders of windows are created in a similar way but do not cause the bug for reasons I will give below). Text and buttons are laid on top.

 

I found that:

- Not rendering this perticular sprite at all would cause the bug not to happen.

- Removing the tint on this sprite would prevent the bug.

- Skipping the window creation phase that stretches this sprite to the window size would prevent the bug.

 

Looking at other parts of the game where the rendering issues kick in, I have found that they all feature a Phaser.sprite that is tinted and stretched at the same time. Examples of this are backgrounds and screen fade transition surfaces. My current workaround is to manually create the base images the color I want instead of tinting them manually.

 

I've tested this in a sandboxed project as well, with a transparent white sprite and a cyan tinted + stretched sprite on a white background. When the tinted + stretched sprite was being rendered, the transparent sprite would become opaque and have Hall Of Mirrors esque rendering issues.

 

But yeah. Not sure if you can reproduce any of this, but for me (Phaser 3.3) very wierd stuff happens when I tint and stretch a sprite at the same time.

 

EDIT: I just managed to get it to happen with a 1x1 tinted sprite without any stretching, too. This is all in Canvas mode, by the way.

Link to comment
Share on other sites

Oh, damn it.

 

It still happens in the Game state when I create a MessWorld (wrapper for a tilemap)

// World Object - special object that holds the world and all its layers, as well as storing collision data for objects such as actors to useMessWorld = function (game) {    this.game = game;        this.manager = null;    this.data = null;    this.musicData = null;        this.music = "";    this.name = "";        this.loadedKey = "";        this.backgroundGroup = new Phaser.Group(game);        this.colLayer = null;        this.bgImage = null;        this.lvlText = null;        this.layer1 = null;    this.layer2 = null;    this.layer3 = null;    this.layer4 = null;        this.loaded = false;}MessWorld.prototype.constructor = MessWorld;MessWorld.prototype.setDebug = function(dbg) {    this.layer4.debug = dbg;}MessWorld.prototype.loadArea = function(name) {    console.log("[MESS] loading map " + name);        if(this.manager != null) {        this.unloadArea();    }        if(this.name == null) {        this.musicData.destroy();                this.musicData = null;        this.music = "";                this.name = "";                return;    }        this.loaded = true;        // load tilemap    this.manager = this.game.add.tilemap(name);    this.data = this.manager.properties;        // load tileset    this.manager.addTilesetImage("WorldTiles");        // load background image    /*    if(this.data.bgImage != null) {        this.bgImage = this.game.add.tileSprite(0, 0, this.game.canvas.width, this.game.canvas.height, this.data.bgImage);        this.bgImage.fixedToCamera = true;           this.backgroundGroup.add(this.bgImage);    }    */        // load layers - don't bother with the paralax layer on phones    if (BasicGame.parallaxEnabled) {        //this.layer1 = this.manager.createLayer("backgroundParalax");    }        //this.layer2 = this.manager.createLayer("backgroundFixed");    //this.layer3 = this.manager.createLayer("noCol");    this.layer4 = this.manager.createLayer("col");    //this.layer5 = this.manager.createLayer("foregroundFixed");        if (BasicGame.parallaxEnabled) {        //this.backgroundGroup.add(this.layer1);    }        //this.backgroundGroup.add(this.layer2);    //this.backgroundGroup.add(this.layer3);        this.layer4.resizeWorld();        if (BasicGame.parallaxEnabled) { // don't bother with paralax on phones as it lags them to death        if(this.data.xParalaxShift != null) {            //this.layer1.scrollFactorX = this.data.xParalaxShift;        }                if(this.data.yParalaxShift != null) {            //this.layer1.scrollFactorY = this.data.yParalaxShift;        }    }        // setup COL layer    this.manager.setCollisionBetween(0, 720, true, this.layer4);    this.colLayer = this.layer4;        if(BasicGame.displayColliders)        //this.layer4.debug = true;        // load map data    this.game.stage.backgroundColor = this.data.bgcol;        if(this.name != this.data.areaName) {        this.name = this.data.areaName;        this.lastNameUpdate = this.game.time.time;    }        // music!    if(this.music != this.data.music) {        this.music = this.data.music;                if(this.musicData != null) {            this.musicData.destroy();            this.musicData = null;        }                if(this.music != "") {            this.musicData = this.game.add.audio(this.music);                        if(BasicGame.playMusic)                this.musicData.play('', 0, BasicGame.musicVol, true);        }    }        this.loadedKey = name;};MessWorld.prototype.unloadArea = function() {    if (BasicGame.parallaxEnabled) {        this.layer1.destroy(); // no paralax layer on phones    }        this.layer2.destroy();    this.layer3.destroy();    this.layer4.destroy();    this.layer5.destroy();        this.manager.destroy();    this.manager = null;        if(this.bgImage != null) {        this.bgImage.destroy();        this.bgImage = null;    }        this.loaded = false;    this.loadedKey = "";};MessWorld.prototype.getInteractData = function(posX, posY) {    for(var i = 0; i < this.data.interactableTiles.length; i++) {        var tile = this.data.interactableTiles[i];                if(tile.posX == posX && tile.posY == posY) {            // found            return tile;        }    }        // found nothing! fuck!    return null;}MessWorld.prototype.doCollisionCheck = function(colObj) {    if(this.manager == null) {        return;    }    this.game.physics.arcade.collide(colObj, this.colLayer);}

(note: currently commented to only load in 1 layer of the world for debugging - glitch still happens)

Link to comment
Share on other sites

Hey guys,

 

I'm getting the same thing, all of a sudden. My JS console logs this message:

0EERQsB.png

 

It seems to be a tileSprite problem. I have multiple game states - a tileSprite is used in one state to create a background for an input screen, and when the user clicks a button, they are taken to the next game state, which also creates the same tileSprite for the same background effect. The code I use in both states are the same:

 

create: function () {        game.add.tileSprite(0, 0, game.world.width, game.world.height, 'grass');        // .... etc}

The error occurs when the user clicks the button to move from the first to the second state. If I comment out the line that creates the tileSprite in the second state, I don't get that error. I set my chrome dev tools to pause on exceptions, and on that line 11090 (as below), the source property on the baseTexture is null. The grass.png file is loaded once inside a preload state when the game starts, before any state uses it.

this.__tilePattern = context.createPattern(this.tilingTexture.baseTexture.source, 'repeat');

It's worth mentioning that I have just tried to upgrade from Phaser v2.2.0 to v2.3.0, when this started happening.

My grass.png file is 32x32.

Link to comment
Share on other sites

Bump. Still have been unable to resolve the rendering issues with Tilemaps. Any help you can offer is appreciated.

 

Notable: Some computers have no issues at all. Me and my friend's computers both have rendering bugs, but my laptop will run the game fine.

Link to comment
Share on other sites

I have encountered the exact same issue as Krummelz! I too use identical TileSprites on separate Stages and when I transition from the first of these stages to the next, I get the same stack trace that Krummelz shows above. I also narrowed my problem down to the same source code line:

this.__tilePattern = context.createPattern(this.tilingTexture.baseTexture.source, 'repeat');

Taking a closer look, I found that this.tilingTexture.baseTexture.source is null when the second stage gets loaded. I tracked it down even further to the following stack trace. In the screenshot below, you will see exactly where this value gets set to null!

 

phaser_230_stack.png?raw=1

 

I have compared the source code for 2.2.2 to 2.3.0 and found that the problem lies in a substantial change to Phaser.TileSprite.prototype.destroy. In 2.2.2, this method had a lot of custom Phaser code in it. In 2.3.0, it calls two other methods: Phaser.Component.Destroy.prototype.destroy.call(this, destroyChildren); and PIXI.TilingSprite.prototype.destroy.call(this); It's the call to the underlying PIXI code that is the problem. Calling destroy on PIXI.TilingSprite results in the underlying tilingTexture.baseTexture being destroyed too and then it can't be used again! I don't know what the correct solution is but I found that changing the code as follows actually solves the problem.

 

Change this:

Phaser.TileSprite.prototype.destroy = function(destroyChildren) {    Phaser.Component.Destroy.prototype.destroy.call(this, destroyChildren);    PIXI.TilingSprite.prototype.destroy.call(this);};

to this:

Phaser.TileSprite.prototype.destroy = function(destroyChildren) {    Phaser.Component.Destroy.prototype.destroy.call(this, destroyChildren);    //PIXI.TilingSprite.prototype.destroy.call(this);	    PIXI.Sprite.prototype.destroy.call(this);    this.tileScale = null;    this.tileScaleOffset = null;    this.tilePosition = null;};

The new code above was copied from PIXI.TilingSprite.prototype.destroy but I have excluded the lines where the tilingTexture is destroyed. This might have unexpected side effects but it's as far as I can get on my own. In fact, in my game it removes the physics body from one of my TileSprites so I know something is not right!

Hopefully, Richard and his team can use this info to fix the issue permanently.

Link to comment
Share on other sites

  • 3 weeks later...
  • 2 weeks later...
  • 2 months later...

Hey guys. I've been using Phaser for hobby projects for the past year or so and I've loved it. Thanks so much for putting the time and effort into such a polished library.

 

Just wanted to say that I ran into the same bug as @jrejigga with TileSprites crashing after changing game state. Doing the fix @jrejigga did solved the problem. This happened when I upgraded from 2.2.2 to 2.3.0.

 

Another problem with upgrading to 2.3.0 is that TileSprite instances no longer seem to be working in Arcade Physics. Their body hitboxes appear when rendered via debug.body(), but they don't seem to block anything or respond to Arcade.collide().

 

Upgrading isn't a critical issue for me right now, so I'm going to stick to 2.2.2. I thought I'd let you know, regardless!

Link to comment
Share on other sites

  • 2 weeks later...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...