Javascript 使用画布的等轴测平铺贴图(带有点击检测)
我目前正在开发一个游戏,它需要一个由各种瓷砖图像组成的地图。我设法使它们正确显示(参见第二幅图),但我现在不确定如何从鼠标位置计算单击的平铺 是否有任何现有的图书馆用于此目的 还请注意,瓷砖图像并不是完美地“面向角落的相机”绘制的,它们是稍微顺时针旋转的 等距变换 定义投影 等轴测显示与标准显示相同,唯一改变的是x轴和y轴的方向。通常,x轴被定义为(1,0)跨一个单位并向下归零,y轴被定义为(0,1)跨一个单位并向下归零。对于等轴测(严格来说,您的图像是一个二次投影),您将有类似于x轴(0.5,1)和y轴(-1,0.5)的东西 矩阵 由此,您可以创建一个渲染矩阵,其中6个值,两个轴各两个,原点两个,我将暂时忽略(原点),只使用4作为轴,并假设原点始终为0,0Javascript 使用画布的等轴测平铺贴图(带有点击检测),javascript,html,math,canvas,Javascript,Html,Math,Canvas,我目前正在开发一个游戏,它需要一个由各种瓷砖图像组成的地图。我设法使它们正确显示(参见第二幅图),但我现在不确定如何从鼠标位置计算单击的平铺 是否有任何现有的图书馆用于此目的 还请注意,瓷砖图像并不是完美地“面向角落的相机”绘制的,它们是稍微顺时针旋转的 等距变换 定义投影 等轴测显示与标准显示相同,唯一改变的是x轴和y轴的方向。通常,x轴被定义为(1,0)跨一个单位并向下归零,y轴被定义为(0,1)跨一个单位并向下归零。对于等轴测(严格来说,您的图像是一个二次投影),您将有类似于x轴(0.5,
var dimetricMatrix = [0.5,1.0,-1,0.5]; // x and y axis
矩阵变换
从中可以在显示器上获得与给定等轴测坐标匹配的点。假设块是200 x 200像素,并且您通过块x和y来寻址每个块。因此,图像底部的块位于x=2
和y=1
(第一个顶部块是x=0
,y=0
)
利用矩阵可以得到块的像素位置
var blockW = 200;
var blockH = 200;
var locX = 2;
var locY = 1;
function getLoc(x,y){
var xx,yy; // intermediate results
var m = dimetricMatrix; // short cut to make code readable
x *= blockW; // scale up
y *= blockH;
// now move along the projection x axis
xx = x * m[0];
yy = x * m[1];
// then add the distance along the y axis
xx += y * m[2];
yy += y * m[3];
return {x : xx, y : yy};
}
在我继续之前,您可以看到我已按块大小缩放了x和y。我们可以简化上述代码,并在矩阵中包含刻度200200
var xAxis = [0.5, 1.0];
var yAxis = [-1, 0.5];
var blockW = 200;
var blockH = 200;
// now create the matrix and scale the x and y axis
var dimetricMatrix = [
xAxis[0] * blockW,
xAxis[1] * blockW,
yAxis[0] * blockH,
yAxis[1] * blockH,
]; // x and y axis
矩阵保持x轴和y轴的比例,因此x轴的两个数字告诉我们变换单元的方向和长度
简化功能
并重新执行getLoc
功能以提高速度和效率
function transformPoint(point,matrix,result){
if(result === undefined){
result = {};
}
// now move along the projection x axis
result.x = point.x * matrix[0] + point.y * matrix[2];
result.y = point.x * matrix[1] + point.y * matrix[3];
return result;
}
所以,传递一个点,然后得到一个变换后的点。result参数允许您传递一个现有点,如果您经常这样做,那么就不必分配新点
var point = {x : 2, y : 1};
var screen = transformPoint(point,dimetricMatrix);
// result is the screen location of the block
// next time
screen = transformPoint(point,dimetricMatrix,screen); // pass the screen obj
// to avoid those too
// GC hits that kill
// game frame rates
将矩阵倒置
所有这些都很方便,但你需要与我们刚才做的相反。幸运的是,矩阵的工作方式允许我们通过反转矩阵来反转过程
function invertMatrix(matrix){
var m = matrix; // shortcut to make code readable
var rm = [0,0,0,0]; // resulting matrix
// get the cross product of the x and y axis. It is the area of the rectangle made by the
// two axis
var cross = m[0] * m[3] - m[1] * m[2]; // I call it the cross but most will call
// it the determinate (I think that cross
// product is more suited to geometry while
// determinate is for maths geeks)
rm[0] = m[3] / cross; // invert both axis and unscale (if cross is 1 then nothing)
rm[1] = -m[1] / cross;
rm[2] = -m[2] / cross;
rm[3] = m[0] / cross;
return rm;
}
现在我们可以反转我们的矩阵
var dimetricMatrixInv = invertMatrix(dimetricMatrix); // get the invers
现在我们有了逆矩阵,我们可以使用变换函数将屏幕位置转换为块位置
var screen = {x : 100, y : 200};
var blockLoc = transformPoint(screen, dimetricMatrixInv );
// result is the location of the block
用于渲染的矩阵
变换矩阵dimetricMatrix
也可以被2D画布使用,但您需要添加原点
var m = dimetricMatrix;
ctx.setTransform(m[0], m[1], m[2], m[3], 0, 0); // assume origin at 0,0
现在,您可以在块周围使用
ctx.strokeRect(2,1,1,1); // 3rd by 2nd block 1 by 1 block wide.
来源
我在上面的所有内容中都省略了起源,我将把它留给你去查找,因为在线上有一万亿页关于矩阵的内容,因为所有2D和3D渲染都使用它们,如果你想进入计算机可视化领域,对它们有很好的深入了解是很重要的 旧帖子,但仍然非常有用。泰。