为什么缩放后的 HTML5 画布上的“像素"奇怪地对齐? [英] Why are the 'pixels' on my scaled HTML5 canvas strangely aligned?

查看:21
本文介绍了为什么缩放后的 HTML5 画布上的“像素"奇怪地对齐?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在编写一个类似于经典诺基亚 Snake 的基于 HTML5 canvas/JS 的小蛇克隆.(这是我的第一个 HTML5 canvas/JS 游戏,也是我的第一个游戏,我仍然是一个新手程序员;))

I'm currently writing a little HTML5 canvas/JS based snake clone similar to the classic Nokia Snake. (This is my first HTML5 canvas/JS game as well as my first game, I'm still a novice programmer ;) )

为了简单起见,我决定让蛇和樱桃的每一部分都只有 1 个像素,但这通常会导致非常小的蛇和樱桃!;) 所以我决定用 .scale(8,8) 缩放画布,这样每个像素都是 8*8.

To keep things simple I decided to make every segment of the snake and the cherry just 1 pixel, however that would normally result in a very tiny snake and cherry! ;) So I decided to scale the canvas with .scale(8,8) so every pixel would be 8*8.

var snake = {
  length: 4,
  direction: "right",
  color: "#9A9A92",
  location: [{x: 32, y: 32}, {x: 31, y: 32}, {x: 30, y: 32}, {x: 29, y: 32}]
}
var cherry = {
  color: "#B1001D",
  x: Math.random()*65,
  y: Math.random()*65
}
var ToDrawOrNotToDraw; //limits the speed of the snake
function moveSnake(eventinfo){
  if(eventinfo.keyCode === 38){
    if(snake.direction === "left" || snake.direction === "right"){
      snake.direction = "up";
    }
  }
  else if(eventinfo.keyCode === 40){
    if(snake.direction === "left" || snake.direction === "right"){
      snake.direction = "down";
    }
  }
  else if(eventinfo.keyCode === 37){
    if(snake.direction === "up" || snake.direction === "down"){
      snake.direction = "left";
    }
  }
  else if(eventinfo.keyCode === 39){
    if(snake.direction === "up" || snake.direction === "down"){
      snake.direction = "right";
    }
  }
}
function draw(){
  requestAnimationFrame(draw);
  if(ToDrawOrNotToDraw === true){
    var snakeDrawerCount = 0;
    ctx.fillStyle = "#006C00";
    ctx.fillRect(0, 0, 64, 64);
    ctx.fillStyle = cherry.color;
    ctx.fillRect(cherry.x, cherry.y, 1, 1);
    ctx.fillStyle = snake.color;
    if(snake.direction === "up"){
      if(snake.location[0].y > 0){
        snake.location.unshift({x: snake.location[0].x, y: snake.location[0].y-1});
        snake.location.pop();
      }
      else {
        snake.location.unshift({x: snake.location[0].x, y: 64});
        snake.location.pop();
      }
    }
    else if(snake.direction === "down"){
      if(snake.location[0].y < 64){
        snake.location.unshift({x: snake.location[0].x, y: snake.location[0].y+1});
        snake.location.pop();
      }
      else {
        snake.location.unshift({x: snake.location[0].x, y: 0});
        snake.location.pop();
      }
    }
    else if(snake.direction === "left"){
      if(snake.location[0].x > 0){
        snake.location.unshift({x: snake.location[0].x-1, y: snake.location[0].y});
        snake.location.pop();
      }
      else {
        snake.location.unshift({x: 64, y: snake.location[0].y});
        snake.location.pop();
      }
    }
    else {
      if(snake.location[0].x < 64){
        snake.location.unshift({x: snake.location[0].x+1, y: snake.location[0].y});
        snake.location.pop();
      }
      else {
        snake.location.unshift({x: 0, y: snake.location[0].y});
        snake.location.pop();
      }
    }
    var snakeDrawerCount = 0;
    while(snakeDrawerCount < snake.location.length){
      ctx.fillRect(snake.location[snakeDrawerCount].x, snake.location[snakeDrawerCount].y, 1, 1);
      snakeDrawerCount++;
    }
    ToDrawOrNotToDraw = false;
  }
  else {
    ToDrawOrNotToDraw = true;
  }
}

var cnvs = document.getElementById("cnvs");
window.addEventListener("keydown", moveSnake, false);
var ctx = cnvs.getContext("2d");
ctx.scale(8,8); //actual size of the canvas is 512 * 512, this gives the 'pixels'/blocks on the canvas a size of 8 * 8, so the canvas will get a size of 64 * 64 'pixels'/blocks
draw();

但出于某种奇怪的原因,那些大像素"(8*8 缩放像素)似乎相互重叠.可以在这里看到:

But for some strange reason those 'big pixels' (the 8*8 scaled pixels) seem to overlap each other. As can be seen here:

不幸的是,我完全不知道为什么会发生这种情况,因为正如我之前提到的,我对 HTML5 canvas/JS 的东西仍然很陌生,我之前只用 Qt/QML/C++ 和 Python 进行过编程.我在 Firefox 26(在 Linux 上)和 Konqueror(在 KDE 4.11)(WebKit) 上都尝试了我的游戏,这两个浏览器似乎都有问题,所以我认为这与 Gecko 无关.

Unfortunately I have absolutely no idea why this is happening, because as I mentioned earlier I'm still very new to the HTML5 canvas/JS stuff, I have only programmed in Qt/QML/C++ and Python before. I tried my game in both Firefox 26 (on Linux) and Konqueror (on KDE 4.11)(WebKit), both browsers seem to have the issue, so I don't think it is Gecko-related.

推荐答案

问题来自于抗锯齿/亚像素化.

The problem comes from anti-aliasing / sub-pixeling.

您的樱桃以随机值放置在棋盘上.随机值的问题在于它是一个浮点值,因此樱桃将被放置在带有一些小数的偏移处,因此浏览器会对其进行亚像素化.

Your cherry is placed in the board at a random value. The problem with the random value is that it's a float value so the cherry will be placed offset with some decimals and therefor sub-pixeled by the browser.

当使用缩放时,这个子像素化的结果也会被缩放(当你把它的颜色改成白色时会更清楚),结果是它与网格不匹配.

When using scale the result of this sub-pixeling is also scaled (which is more clear when you change its color to for example white) and the result is that it doesn't match the grid.

要解决这个问题,只需将樱桃的 x 和 y 位置强制为整数,例如像这样:

To solve this simply force the x and y position of the cherry to integer, for example like this:

var cherry = {
  color: "#B1001D",
  x: Math.random()*65|0,
  y: Math.random()*65|0
}

在这里小提琴

| 是按位 OR 运算符,它首先将数字强制为整数,以便能够使用按位 OR.由于我们与 0 进行 OR,因此输出是相同的(除了切割浮点小数).

| is the bitwise OR operator which forces the number first to an integer in order to be able to use bitwise OR. Since we OR with 0, the output is the same (beyond cutting the float decimal).

这篇关于为什么缩放后的 HTML5 画布上的“像素"奇怪地对齐?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆