使用画布的等距tilemap(带点击检测)

时间:2016-09-07 10:10:02

标签: javascript html5 math canvas

我目前正在开发一款游戏,需要一张由各种图块组成的地图。我设法让它们正确显示(见第二张图片)但我现在不确定如何从鼠标位置计算点击的图块。

是否有用于此目的的现有库?

请注意,瓷砖图像不能完美地绘制为“朝向相机的角落”,它们会顺时针轻微旋转。

enter image description here enter image description here

1 个答案:

答案 0 :(得分:1)

等轴变换

定义投影

等距显示与标准显示相同,唯一改变的是x和y轴的方向。通常,x轴定义为(1,0)一个单位横向和零向下,y轴是(0,1)零个单位横向和一个向下。对于等距(严格来说,您的图像是一个二维投影),您将有x轴(0.5,1)和y轴(-1,0.5)

之类的东西

矩阵

从这里你可以创建一个具有6个值的渲染矩阵两个轴各有两个,原点有两个,我现在将忽略它(原点)并且只使用4作为轴并假设原点总是在0,0

var dimetricMatrix = [0.5,1.0,-1,0.5]; // x and y axis

矩阵转换

由此可以在显示屏上获得与给定等距坐标匹配的点。假设块是200乘200像素,并且您通过块x和y对每个块进行寻址。因此,图片底部的块位于x = 2y = 1(第一个顶部块为x = 0y = 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};
}

Befoer我继续前进你可以看到我按块大小缩放了x和y。我们可以简化上面的代码,并在矩阵中包含200,200的比例

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;
}

所以传递一个点并获得一个转换点。结果参数允许您传递现有点,如果您经常这样做,则可以节省必须分配新点。

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

用于渲染的矩阵

对于一些魔术,2D画布也可以使用变换矩阵dimetricMatrix,但是你需要添加原点。

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渲染都使用它们并且对它们有深入了解,因此在线有关于矩阵的数万亿页如果你想进入计算机可视化。