获取交互坐标
当点击画布时, 要想获得事件点相对于画布内的坐标位置, 可以通过如下方式:
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)
})