【问题标题】:Isometric tilemap using canvas (with click detection)使用画布的等距平铺地图(带有点击检测)
【发布时间】:2017-01-14 23:22:13
【问题描述】:

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

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

另请注意,平铺图像并非完美地绘制为“面向角的相机”,它们是顺时针略微旋转的。

【问题讨论】:

    标签: javascript html math canvas


    【解决方案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 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;
    }
    

    所以传递一个点并返回一个转换点。结果参数允许您传递现有点,如果您经常这样做,则无需分配新点。

    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 渲染都使用它们,并且深入了解它们很重要如果你想进入计算机可视化。

    【讨论】:

    • 旧帖子,但仍然非常有用。泰。 ??
    猜你喜欢
    • 2014-09-05
    • 1970-01-01
    • 2013-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2018-07-04
    相关资源
    最近更新 更多