等距地图上的平滑角色移动
Smooth character movement on an Isometric map
我正在构建一个 Isometric 引擎:
http://jsfiddle.net/neuroflux/09h43kz7/1/
(方向键移动)。
我正在更新 Engine.player.x
和 Engine.player.y
以移动角色,但(显然)玩家只是 "pops" 从一个板块到另一个板块。
我想知道有没有办法让他"slide"从一个瓷砖到另一个瓷砖?
或者更好的是,自由移动...
我一直在努力拔头发。
相关代码如下:
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);
};
}());
提前致谢!
您正在图块位置绘制角色。您想要的只是为代表其目的地的角色添加第二组坐标。为了顺利移动,您可以将字符位置设置为瓷砖的分数。例如 player.x = 2.5 字符位于图块 2 和图块 3 之间。
您还想摆脱等轴测图 space 中的乱七八糟的东西。卸载从 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。您可能还想延迟移动,直到玩家到达当前目的地。
这涵盖了基础知识。
我正在构建一个 Isometric 引擎:
http://jsfiddle.net/neuroflux/09h43kz7/1/
(方向键移动)。
我正在更新 Engine.player.x
和 Engine.player.y
以移动角色,但(显然)玩家只是 "pops" 从一个板块到另一个板块。
我想知道有没有办法让他"slide"从一个瓷砖到另一个瓷砖? 或者更好的是,自由移动...
我一直在努力拔头发。
相关代码如下:
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);
};
}());
提前致谢!
您正在图块位置绘制角色。您想要的只是为代表其目的地的角色添加第二组坐标。为了顺利移动,您可以将字符位置设置为瓷砖的分数。例如 player.x = 2.5 字符位于图块 2 和图块 3 之间。
您还想摆脱等轴测图 space 中的乱七八糟的东西。卸载从 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。您可能还想延迟移动,直到玩家到达当前目的地。
这涵盖了基础知识。