为什么我的缩放HTML5画布上的“像素”奇怪地对齐?

时间:2013-12-21 13:42:30

标签: javascript html5 canvas 2d-games online-game

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

为了简单起见,我决定让蛇和樱桃的每个部分只有1个像素,但这通常会产生一个非常小的蛇和樱桃! ;)所以我决定用.scale(8,8)缩放画布,所以每个像素都是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比例像素)似乎彼此重叠。从这里可以看出:

1st image of the glitch 2nd image of the glitch 3rd image of the glitch

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

1 个答案:

答案 0 :(得分:1)

问题来自抗锯齿/子像素化。

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

使用缩放时,此子像素的结果也会缩放(当您将其颜色更改为例如白色时更清晰),结果是它与网格不匹配。

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

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

<强> Fiddle here

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