Jump to content

sprite.smoothed = false fails when switching states


indextwo
 Share

Recommended Posts

I'm working on a game that switches through various states for the menu, main game and game-over screens. for the most part I'm happy for antialiasing to be used on my sprites and particularly my text, as forcing a crisp pixelated render on the whole game can lead to some of the text & sprites looking a little janky. I'm instantiating my game pretty simply:

`MY.game = new Phaser.Game(800, 600, Phaser.AUTO, 'game');`

I'm not setting any scale modes or special rendering prior to playing the game. In the Game Over state I'm loading a small pixel image I created, and adding some bitmapText to the top of the screen. I'm scaling the pixel image up by a factor of 6, and the bitmap text is set at 32px. On both of these, I set `smoothed = false`, because I wanted both the text and the sprite to appear pixel-perfect, and because I use FF by default (which uses WebGL by default), it will usually smooth out sprites unless explicitly told otherwise. It looks like this:

var gameOverText = this.game.add.bitmapText(0, 0, 'FFF', 'GAME OVER', 32);
gameOverText.anchor.setTo(0.5);
gameOverText.x = Math.floor(this.game.width / 2);
gameOverText.smoothed = false;

var skull = this.game.add.sprite(0, 0, 'atlas-sprite', 'skull');
skull.scale.setTo(6);
skull.anchor.setTo(0.5);
skull.x = Math.floor(this.game.width / 2);
skull.y = Math.floor(this.game.height / 2);
skull.smoothed = false;

Here's where it gets weird: if I jump straight from my BootState (which is always loaded before everything else) to my GameOver state, it works perfectly - text and sprite look nice and crisp. However, if I actually go through the game (so, go from BootState to GameState to GameOver state), it doesn't work at all - text is blurry and the sprite looks awful.

I've managed to narrow it down to the point at which I start adding sprites:

// this.levelData is a previously-loaded JSON map

this.parallax = this.add.group();

this.levelData.parallax.clips.forEach(function(element) {
	var parallax = this.parallax.create(element.x, element.y, 'atlas-sprite', element.name);
}, this);

(it's worth noting that these loops create sprites way outside of the camera's viewport, as the game is scrolling)

If I add `this.state.start('GameOverState')` and return out of the function prior to this loop, my text & sprite in the GameOver state remain perfectly pixelated; if I move `this.state.start('GameOverState')` to after that first loop (or at any point after this), it's as if all of the smoothing arguments are ignored.

I've tried a LOT of different methods to try to fix this, but nothing is working. I figured it might be something to do with the world bounds, or the camera position, or the game antialiasing, but nothing seems to work.

Any ideas on why this might be happening and how to get around it?

Link to comment
Share on other sites

11 minutes ago, samme said:

Have you verified that smoothed == false in both cases?

Yup. I just double-confirmed by console.logging the .smoothed property for both sprites, and they're both echoing as false. Like I said, it works exactly as expected as long as I do it before adding a group full of Sprites to the main GameState. If I switch to the GameOverState from any other point prior to the GameState (i.e. skipping that step entirely), it works as expected. It's just that point, where I'm adding sprites that create a group larger than the visible game area, that it stops working.

Link to comment
Share on other sites

7 minutes ago, samme said:

What happens if you use separate images instead of an atlas?

Huh. I don't know why I didn't think of that (aside from all of my images being within an atlas); but that totally works. I'm not super-precious about it HAVING to load from the atlas, but I'm now very curious as to why it wouldn't work under these particular circumstances. Any ideas?

Link to comment
Share on other sites

The smoothing is done per texture, not per sprite. But I'm still not sure how that would affect you. It seems you would have to later set smoothed = true on another sprite sharing the atlas. And in that case I'd expect you'd be able to check smoothed on the original sprite and see that it had also changed to true.

Link to comment
Share on other sites

The only time I'm ever explicitly setting the smoothed property is in that last GameOverState, and that's when I'm switching it to false (although I gather that it is enabled by default). I hadn't realised it's actually on the texture rather than the Sprite though, and I guess that makes sense: once the texture has been used, smoothed is implicitly defaulting to true, and that's where it stays thereafter. Because, if I jump straight to the GameOverState and set it to the sprites (with the first in-game use of the image) to false, it works as expected.

I would guess that the same is true of a bitmapFont texture too - if I use my loaded bitmapFont anywhere else prior to invoking my GameOverState, I cannot for the life of my get that font to appear nice and crisp at a larger font size than its 'natural' size.

Out of interest, is there a straightforward way to set the smoothing on the texture prior to anything else? Or is there a possibility of changing that value after the load by manipulating the cache?

Update:

So I've just tested this for myself, and the results are interesting: If I create some bitmapText and, the first time I use it, I set that particular instance to to smoothed = false, all subsequent instances will be non-smoothed. However, If I create a second bitmapText instance and set it to smoothed = true, not only will all subsequent instances appear antialiased, but trying to use smoothed = false again will not work.

I haven't tested this with my sprite atlas yet, but I expect the results will be the same. Which is weird, but again leads me to wonder if there's any way this can be dealt with maybe at the baseTexture level?

Link to comment
Share on other sites

PARTIALLY SOLVED.

Thanks to this ambiguously-titled thread, I found the solution for my sprite smoothing issue, at least. I solved it with:

var skull = this.game.add.sprite(0, 0, 'atlas-sprite', 'skull');
skull.scale.setTo(6);
skull.smoothed = false;
skull.texture.baseTexture.dirty();

The key is that last line, .texture.baseTexture.dirty(), which I guess forces a cache refresh on the texture.

Unfortunately, the same trick doesn't work on my bitmapText, even after using generateTexture(). Is there a similar dirty() method I could use for that?

Link to comment
Share on other sites

  • 3 months later...
 Share

  • Recently Browsing   0 members

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