0

I'm developing a small browser game where the map size is 300x300. Hence, I set my HMTL canvas's width and height to 300x300. Then, when I want to spawn an object at the center, I spawn it at position 150, 150. Also, when doing physics calculations involving position and velocity, I am likewise using static units that work well within the 300x300 size.

However, some users have tiny screens, or much larger screens, and I would like to scale the canvas size to accommodate them.

However, if I change the actual canvas's resolution, then all my calculations are thrown off. 150x150 is no longer the center, and likewise objects move either faster or slower. As a result, it seems ideal to keep the canvas resolution to be 300x300 and then simply scale the size via CSS, like this:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

canvas.style.width = "600px";
canvas.style.height = "600px";

ctx.fillStyle = 'red';

ctx.font = "600 48px Arial";
ctx.fillText("hello", 150, 150);
canvas { border: 1px solid #333; }
<canvas width="300" height="300"></canvas>

However, the issue with this is that the screen is now blurry.

Is there a way to both scale the screen size without it looking blurry in addition to being able to still just use static values like 150x150 to refer to the center?


I can't post an answer to this since it was closed for whatever reason, but I believe the solution is the following:

export function resize2DContext(context, canvasWidth, canvasHeight) {
  context.setTransform(1, 0, 0, 1, 0, 0);

  const canvas = context.canvas;

  const gameWidth = 600; // native game width
  const gameHeight = 600; // native game height

  canvas.style.width = canvasWidth + "px";
  canvas.style.height = canvasHeight + "px";
  
  canvas.width = canvasWidth;
  canvas.height = canvasHeight;

  context.scale(canvasWidth / gameWidth, canvasHeight / gameHeight);
}

And by handling input events like this:

function handlePointerMove(e) {
  const xRatio = gameWidth / canvasWidth;
  const yRatio = gameHeight / canvasHeight;

  pointerX = e.offsetX * xRatio;
  pointerY = e.offsetY * yRatio;
}
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Ryan Peschel
  • 11,087
  • 19
  • 74
  • 136
  • 1
    The answers point out what the difference is between setting the `width` and `height` properties on the canvas itself and the `style` property of the canvas. The Q&A implies that setting `canvas.style.width` and `canvas.style.height` is almost never useful, because CSS isn’t aware of the contents of a canvas. – Sebastian Simon Dec 04 '22 at 19:22

1 Answers1

-1

You either want to use image-rendering: pixelated;

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

canvas.style.width = "600px";
canvas.style.height = "600px";

ctx.fillStyle = 'red';

ctx.font = "600 48px Arial";
ctx.fillText("hello", 150, 150);
canvas {
  border: 1px solid #333;
  image-rendering: pixelated;
}
<canvas width="300" height="300"></canvas>

Or scale your variables according to the screen size

Konrad
  • 21,590
  • 4
  • 28
  • 64
  • Well pixelated isn't good either because then it is .. well .. pixelated. And scaling my variables to screen size seems to be very cumbersome. Is there no way I can simply provide a transformation to the canvas such that everything is scaled automatically? – Ryan Peschel Dec 04 '22 at 18:47
  • You can try using [scale](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/scale) – Konrad Dec 04 '22 at 18:48
  • I tried that as well, but I was not able to get it to work for me. I wonder if I need to call `translate()` as well? I'll keep investigating. – Ryan Peschel Dec 04 '22 at 18:49
  • You set a font size of 48px for your text, no matter what transformations you will do after that it will always be drawn as if it was 48px. Usually you have to write your own scaling – Konrad Dec 04 '22 at 18:51
  • I don't believe that is the case. You can see for yourself that the text is drawn smaller if you first apply `ctx.scale(0.5, 0.5)` – Ryan Peschel Dec 04 '22 at 18:53
  • It's smaller, but it number of pixels is defined by font size – Konrad Dec 04 '22 at 18:56