TerminalDiscord
TerminalDiscord

Reputation: 23

JavaScript 2D Canvas Screen tearing when using scale

I'm using the scale feature in the 2D Context to scale in-game tiles to fit the screen, however the scaling integer has to be a float to make this happen. Due to this tiles are rendered so that in certain positions you can see lines in the air or inbetween tiles. On some screens screen tearing is minimal but on some is very apparent.

Scaling code: context.scale(this.camera.scale, this.camera.scale);
How scale is measured: window.innerHeight/672 * 3;
Note: Dividing by 672, since when divided by 48 (game units) results in 14, which is the general zone height.

What happens: Imgur link

Please help!

Upvotes: 1

Views: 223

Answers (1)

Helder Sepulveda
Helder Sepulveda

Reputation: 17594

Yes that can happen using scale, but instead you can do the scaling yourself, it's just a multiplication and rounding to keep numbers nice and integer...

Here is the a nice visual showing the difference between the two methods:

Sample code below:

var ctx1 = document.getElementById('canvas1').getContext('2d');
var ctx2 = document.getElementById('canvas2').getContext('2d');
var rect = { x: 10, y: 10, w: 50, h: 50 }
const scale = 0.63517

function drawRects(ctx, pos) {
  ctx.fillRect(pos.x, pos.y, pos.w, pos.h);
  ctx.fillRect(pos.x, pos.y + pos.h, pos.w, pos.h);
  ctx.fillRect(pos.x + pos.w, pos.y + pos.h / 4, pos.w, pos.h);
}

function draw1() {
  ctx1.scale(scale, scale);
  drawRects(ctx1, rect)
}

function draw2() {
  scaled_rect = { 
    x: Math.round(rect.x * scale), 
    y: Math.round(rect.y * scale), 
    w: Math.round(rect.w * scale), 
    h: Math.round(rect.h * scale) 
  }
  drawRects(ctx2, scaled_rect)
}

draw1()
draw2()
canvas {
  border: solid 1px red
}
<canvas id="canvas1" width=80 height=80></canvas>
<canvas id="canvas2" width=80 height=80></canvas>

Upvotes: 2

Related Questions