4 - 坐标获取、触碰检测、层级管理


获取交互坐标

当点击画布时, 要想获得事件点相对于画布内的坐标位置, 可以通过如下方式:

canvas.addEventListener('click', (e) => {
    //  获取canvas所占据的矩形区域
    var rect = canvas.getBoundingClientRect()
    var x = e.clientX - rect.left   //  px
    var y = e.clientY - rect.top    //  px

    //  canvas内的实际坐标点
    x *= canvas.width / canvas.offsetWidth
    y *= canvas.height / canvas.offsetHeight
})

触碰检测

现在已经知道了画布内发生 click 事件的坐标(x, y), 为了判断在这次点击的位置触碰到了哪些显示对象, 需要一种碰撞检测的判定方法。 最简单的, 遍历全部子对象, 检查触碰点是否在这个子对象的矩形区域范围内。如果有触碰到的, 使它静止下来

//  hit area detect
var hits = children.filter(child => {
    return x >= child.x && x <= child.x + child.img.width && y >= child.y && y <= child.y + child.img.height
})

//  让触碰到的显示对象中心移动到(x, y)位置
hits.forEach(hit => {
    hit.static = true   //  make it static
    hit.x = x - hit.img.width / 2
    hit.y = y - hit.img.height / 2
})

改进: 因为图片的内容实际上是圆形,以上的矩形区域检测并不精准。可以根据实际情况, 检测事件点到图标中心的距离是否小于图标半径来判定是否碰撞

var hits = children.filter(child => {
    return Math.sqrt(Math.pow(child.x + child.img.width / 2 - x, 2) + Math.pow(child.y + child.img.height / 2 - y, 2)) <= child.img.width / 2
})

层级管理

有时候, 点击到的显示对象可能会被其他的元素盖住, 此时需要改变对象的层级。好在可以通过 children 数组快速达成这一目标

hits.forEach((hit) => {
    children.splice(children.indexOf(hit), 1)
    children.push(hit)
})