2
\$\begingroup\$

I'm writing a simple game using Phaser 3.5.1. I made a 20X20 over world tile map for my hero to walk around on with the camera following the hero. I was able to implement tile based movement using tweens. This works but whenever the camera moves 1 pixel lines flash on the tile map perpendicular to the direction I move. Example uses a static map layer:

Static map layer no rounded pixels

As you can see I was also getting some weird artifacts on my sprite even when the camera wasn't moving, but after reading about rounded pixels I was able to eliminate that on my sprite by setting roundedPixels: true in my game config, but now the sprite jitters when the lines appear. Example uses static map layer with rounded pixels:

Static map layer with rounded pixels

I also experimented with static vs dynamic layers for my map. When I have a dynamic map layer without rounded pixels the result is the same as my static map layer without rounded pixels.

Dynamic map layer no rounded pixels

When I use rounded pixels on a dynamic map everything gets really jittery. Interestingly when the camera doesn't move the map shakes, and when the camera does move the sprite jitters.

Dynamic map with rounded pixels

Regardless of the map type or rounded pixels setting, the longer the tween's duration the worse the problem gets. In my examples I used 2 second tweens to emphasize the problem.

How do I fix this problem? In a perfect world I'd like to keep using tweens for tile based movement, keep a static map, and just update some config value. If that isn't going to work what approach should I take?


I'm happy to add code to my question if people think it would be helpful.

\$\endgroup\$
3
\$\begingroup\$

I was able to fix the problem by setting following a point instead of following my hero sprite. The core problem was the camera wasn't moving in round pixels. By making that point move in round pixels the problem was solved for both static and dynamic map layers. That combined with setting the round pixels parameter for the game cleaned up the jitter, lines, and artifacts around the sprite during motion. I got the idea from an old forum post. My solution is just an extremely simplified version of lewster32's suggestion.

My initial code in the create method looked like:

create() {
    // Create and display the overworld map.
    this.map = this.make.tilemap({ key: "overworld" });
    this.tileset = this.map.addTilesetImage("dragTilesSmall", "tiles");
    this.activeLayer = this.map.createStaticLayer("overworld", this.tileset, 0, 0);

    // The hero of the game
    this.hero = new Hero({ scene: this, key: "playerSprites", x: 16 * 5, y: 16 * 4 });

    // Setup the camera
    this.cameras.main.startFollow(this.hero);
    this.cameras.main.setBounds(0, 0, this.activeLayer.width * this.activeLayer.scaleX, this.activeLayer.height * this.activeLayer.scaleY);

    // Setup the inputs
    this.input.keyboard.on("keydown", this.handleKey, this);
}

The only thing that changed in the create function was I made the camera section follow a point instead of the hero. To update the location of the point I added an update function with two lines of code.

// This is the new "Setup camera section"
this.cameras.main.setBounds(0, 0, this.activeLayer.width * this.activeLayer.scaleX, this.activeLayer.height * this.activeLayer.scaleY);
this.cameraDolly = new Phaser.Geom.Point(this.hero.x, this.hero.y);
this.cameras.main.startFollow(this.cameraDolly);

// This is the update function I added
update() {
    // Move the camera dolly in round pixels
    this.cameraDolly.x = Math.floor(this.hero.x);
    this.cameraDolly.y = Math.floor(this.hero.y);
}

To set the roundPixels property you just need to add it to the game config. here's what mine looks like:

const config = {
    parent: "GameContainer",
    width: 160,
    height: 160,
    pixelArt: true,
    roundPixels: true,
    scene: [BootScene, MainScene],
    zoom: 5
};

const game = new Phaser.Game(config);
\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks for sharing the solution. I was having a similar problem, where the tiles were rendered with an additional 1px line of the adjacent tile (in the tileset image). I found that, to fix the issue, roundPixels is not very relevant in my case, but setting antialias: false did the trick. \$\endgroup\$ – afsantos May 10 '18 at 17:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.