2013-03-02 107 views
1

正如您在此JSFiddle中所看到的,当您使用箭头键移动红色正方形时,平铺之间的过渡非常不连贯,看起来不太好。平铺之间的平滑过渡

我想知道是否有一种方法可以在瓷砖之间进行平滑过渡,使其看起来像一个平滑的动作?

var canvas, context, board, imageObj, tiles, board, display; 
var NUM_OF_TILES = 2; 

// viewport 
var vX = 0, 
    vY = 0, 
    vWidth = 15, 
    vHeight = 10; 

var playerX = 0, 
    playerY = 0; 

var worldWidth = 29, 
    worldHeight = 19; 

function loadMap(map) { 
    if (map == 1) { 
     return [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 0], [0, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 0], [0, 1, 1, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 0], [0, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 0], [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]; 
    } 
} 

$(document).ready(function() { 


    canvas = document.getElementById("canvas"); 
    context = canvas.getContext("2d"); 

    canvas.tabIndex = 0; 
    canvas.focus(); 
    canvas.addEventListener('keydown', function(e) { 
     console.log(e); 
     var key = null; 
     switch (e.which) { 
     case 37: 
      // Left 
      if (playerX > 0) playerX--; 
      break; 
     case 38: 
      // Up 
      if (playerY > 0) playerY--; 
      break; 
     case 39: 
      // Right 
      if (playerX < worldWidth) playerX++; 
      break; 
     case 40: 
      // Down 
      if (playerY < worldHeight) playerY++; 
      break; 
     } 
     // Okay! The player is done moving, now we have to determine the "best" viewport. 
     // Ideally the viewport centers the player, 
     // but if its too close to an edge we'll have to deal with that edge 

     vX = playerX - Math.floor(0.5 * vWidth); 
     if (vX < 0) vX = 0; 
     if (vX+vWidth > worldWidth) vX = worldWidth - vWidth; 


     vY = playerY - Math.floor(0.5 * vHeight); 
     if (vY < 0) vY = 0; 
     if (vY+vHeight > worldHeight) vY = worldHeight - vHeight; 


     draw(); 
    }, false); 

    var board = []; 

    canvas.width = 512; 
    canvas.height = 352; 

    board = loadMap(1); 
    imageObj = new Image(); 
    tiles = []; 

    var loadedImagesCount = 0; 
    for (x = 0; x <= NUM_OF_TILES; x++) { 
     var imageObj = new Image(); // new instance for each image 
     imageObj.src = "http://mystikrpg.com/canvas/img/tiles/t" + x + ".png"; 

     imageObj.onload = function() { 
      // console.log("Added tile ... "+loadedImagesCount); 
      loadedImagesCount++; 
      if (loadedImagesCount == NUM_OF_TILES) { 
       // Onces all tiles are loaded ... 
       // We paint the map 
       draw(); 
      } 
     }; 
     tiles.push(imageObj); 
    } 


    function draw() { 
     context.clearRect(0,0,canvas.width, canvas.height); 
     for (y = 0; y <= vHeight; y++) { 
      for (x = 0; x <= vWidth; x++) { 
       theX = x * 32; 
       theY = y * 32; 
       context.drawImage(tiles[board[y+vY][x+vX]], theX, theY, 32, 32); 
      } 
     } 
     context.fillStyle = 'red'; 
     context.fillRect((playerX-vX)*32, (playerY-vY)*32, 32, 32); 
    } 
}); 
+0

在回答你的问题:是的。 – 2013-03-02 22:21:38

+0

你需要将角色的位置不是以瓷砖而是以像素为单位。 – Philipp 2013-03-02 22:59:36

回答

2

我打得周围一点点,得到的东西的工作:

case 39: 
     // Right 
     if (playerX < worldWidth) { 
      var start = playerX; 
      var end = Math.round(playerX + 1); 
      $({ i : start }).animate({ i: end}, { 
       duration: 400, 
       step: function(now) { 
        playerX = now; 
        draw(); 
       } 
      }); 
     } 
     break; 

我使用jQuery的动画功能,以便在值之间进行插补。我意识到绘图函数只会被调用一次,为了得到一个动画我不得不每一步都调用它。

为了避免在重新对中使用Math.round()也出现错误。

vX = Math.round(playerX) - Math.floor(0.5 * vWidth); 
    if (vX < 0) vX = 0; 
    if (vX+vWidth > worldWidth) vX = worldWidth - vWidth; 


    vY = Math.round(playerY) - Math.floor(0.5 * vHeight); 
    if (vY < 0) vY = 0; 
    if (vY+vHeight > worldHeight) vY = worldHeight - vHeight; 

当然,你必须做额外的工作,例如,起点和终点可能会有所不同。正如建议你可能应该使用像素位置而不是瓷砖。但我不知道你的意图。

就可避免陷入上得到通过检查的keydown如果瓷砖是“满”的位置通过检查

if (playerY < worldHeight && playerY % 1 == 0) {... 
+0

谢谢,但是如果我移动方块的速度太快,为什么会出现空白屏幕? – Anzwur 2013-03-02 22:54:06

+0

哦等待我会修改代码 – pfried 2013-03-02 22:55:09

+0

好吧谢谢。 – Anzwur 2013-03-02 22:55:45