在等轴测图上平滑的角色移动

时间:2015-10-19 09:16:05

标签: javascript animation canvas isometric

我正在构建一个等距引擎:

http://jsfiddle.net/neuroflux/09h43kz7/1/

(箭头键移动)。

我正在更新Engine.player.xEngine.player.y来移动角色,但(显然)玩家只是从一个磁贴“弹出”到另一个磁贴。

我想知道是否有办法让他从瓷砖“滑动”到瓷砖? 或者更好的是,自由运动......

我一直在试着拔头发。

以下是相关代码:

var Engine = {

    // canvas variables
    canvas: null,
    ctx: null,

    // map
    map: [
        [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],
        [2,1,1,1,1,1,1,1,1,1,1,1,1,1,2],
        [2,1,1,0,0,1,1,1,1,0,0,0,1,1,2],
        [2,2,1,0,0,0,0,1,0,0,0,0,1,1,2],
        [2,2,1,1,1,1,0,0,0,0,1,0,0,1,2],
        [2,2,2,2,2,1,0,0,0,1,0,0,0,1,2],
        [2,2,1,1,1,1,0,0,0,0,0,0,0,1,2],
        [2,1,1,0,1,0,0,0,0,1,1,0,0,1,2],
        [2,1,0,0,0,0,0,1,0,0,0,0,0,1,2],
        [2,1,0,0,0,0,0,0,0,0,1,0,0,1,2],
        [2,1,0,0,0,0,1,0,0,0,0,0,0,1,2],
        [2,1,0,1,1,0,0,0,0,1,0,0,0,1,2],
        [2,1,0,0,0,0,0,0,0,0,1,0,1,1,2],
        [2,1,1,1,1,1,1,1,1,1,1,1,1,1,2],
        [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]
    ],

    // player info
    player: {
        x:1,
        y:1
    },

    // tile size
    tileH: 31,
    tileW: 63,

    // map position
    mapX: window.innerWidth/2,
    mapY: window.innerHeight/3,

    // tile images
    tileSources: [
        "images/stone.png",
        "images/grass.png",
        "images/water.png",
        "images/ralph.png"
    ],

    // for pre-loading
    tileGraphics: [],
    tilesLoaded: 0,

    // image preloader
    loadImages: function() {
        for (var i = 0; i < Engine.tileSources.length; i++) {
            Engine.tileGraphics[i] = new Image();
            Engine.tileGraphics[i].src = Engine.tileSources[i];
            Engine.tileGraphics[i].onload = function() {
                Engine.tilesLoaded++;
                if (Engine.tilesLoaded === Engine.tileSources.length) {
                    Engine.draw();
                }
            }
        }
    },

    // update logic
    update: function() {
        Engine.draw();
    },

    // draw the scene
    draw: function() {
        Engine.ctx.clearRect(0, 0, Engine.canvas.width, Engine.canvas.height);
        var drawTile;
        for (var i = 0; i < Engine.map.length; i++) {
            for (var j = 0; j < Engine.map[i].length; j++) {
                drawTile = Engine.map[i][j];
                Engine.ctx.drawImage(Engine.tileGraphics[drawTile], (i - j) * Engine.tileH + Engine.mapX, (i + j) * Engine.tileH / 2 + Engine.mapY);
                if (Engine.player.x === i && Engine.player.y === j) {
                    Engine.ctx.drawImage(Engine.tileGraphics[3], (i - j) * Engine.tileH + Engine.mapX, (i + j) * Engine.tileH / 2 + Engine.mapY - Engine.tileH + 10);
                }
            }
        }
        Engine.gameLoop();
    },

    // game loop
    gameLoop: function() {
        Engine.gameTimer = setTimeout(function() {
            requestAnimFrame(Engine.update, Engine.canvas);
        }, 1);
    },

    // start
    init: function() {
        Engine.canvas = document.getElementById("main");
        Engine.canvas.width = window.innerWidth;
        Engine.canvas.height = window.innerHeight;
        Engine.ctx = Engine.canvas.getContext("2d");
        document.addEventListener("keyup", function(e) {
            //console.log(e.keyCode);
            switch(e.keyCode) {
                case 38:
                    if (Engine.map[Engine.player.x-1][Engine.player.y] !== 2) {
                        Engine.player.x--;
                    }
                    break;
                case 40:
                    if (Engine.map[Engine.player.x+1][Engine.player.y] !== 2) {
                        Engine.player.x++;
                    }
                    break;
                case 39:
                    if (Engine.map[Engine.player.x][Engine.player.y-1] !== 2) {
                        Engine.player.y--;
                    }
                    break;
                case 37:
                    if (Engine.map[Engine.player.x][Engine.player.y+1] !== 2) {
                        Engine.player.y++;
                    }
                    break;
            }
        });
        Engine.loadImages();
    }

}


// loaded
window.onload = function() {
    Engine.init();
};


// request animation frame
window.requestAnimFrame = (function(){
  return window.requestAnimationFrame || 
    window.webkitRequestAnimationFrame || 
    window.mozRequestAnimationFrame || 
    window.oRequestAnimationFrame || 
    window.msRequestAnimationFrame || 
    function (callback, element){
    fpsLoop = window.setTimeout(callback, 1000 / 60);
  };
}());

提前致谢!

1 个答案:

答案 0 :(得分:2)

您正在平铺位置绘制角色。你想要的只是为代表其目的地的角色添加第二组坐标。要平滑移动,您可以在拼贴的分数中设置字符位置。例如,player.x = 2.5,角色位于第2和第3区之间。

你也想摆脱等距空间的混乱。将转换从2d卸载到等距到绘制功能,而不是每次绘制到游戏区时手动完成。

创建绘图功能

// add to the Engine object.
// img is the image to draw. x and y are the tile locations. 
// offsetX and offsetY [optional] are pixel offsets for fine tuning;
drawImageIso:function (img,x,y,offsetX,offsetY){
    offsetX = offsetX === undefined ? 0: offsetX; // so you dont have to 
    offsetY = offsetY === undefined ? 0: offsetY; // add the offset if you 
                                                  // are not using it;
    Engine.ctx.drawImage(  // draw the image
        img,
        (x - y) * Engine.tileH + Engine.mapX + offsetX, 
        (x + y) * Engine.tileH / 2 + Engine.mapY - Engine.tileH+offsetY
    );
},

将玩家对象更改为

player: {
    x:1,
    y:1,
    destX:1,  // the destination tile
    destY:1,   
    playerAtDest:true, // true if the player has arrived     
},

为瓷砖渲染循环添加此

    var p = Engine.player; // because I am lazy and dont like typing.
    var dx = p.destX;
    var dy = p.destY;
    var maxPlayerSpeed = 0.1;  // max speed in tiles per frame
    var mps = maxPlayerSpeed; // because I am lazy
    // check if the player needs to move
    if( Math.abs(p.x - dx) > mps  || Math.abs(p.y - dy) > mps ){
        p.x += Math.max( -mps , Math.min( mps , dx - p.x )); // move to destination clamping speed;
        p.y += Math.max( -mps , Math.min( mps , dy - p.y ));            
        p.playerAtDest = false;  // flag the player is on the way
    }else{
        // player directly over a till and not moving;
        p.x = dx; // ensure the player positioned correctly;
        p.y = dy;
        p.playerAtDest = true;  // flag the player has arrived
    }

添加以下用于绘制播放器的位置。使用目的地x,y确定何时绘制或使用Math.round(Engine.player.x)和y来确定何时。

    // now draw the player at its current position
    Engine.drawImageIso( Engine.tileGraphics[3] , p.x , p.y , 0 , 10);

您必须更改界面才能移动播放器目的地而不是x和y。您可能还想延迟移动,直到玩家到达当前目的地。

这涵盖了基础知识。