Canvas进阶-5、碰撞检测

什么是碰撞检测?

碰撞检测,是物体与物体之间的关系。用来检测物体与物体之间是否发生了碰撞,例如:射击游戏,就是检测子弹与敌人的碰撞。

碰撞检测,主要归纳为以下两种实现方式:

  1. 外接矩形判定法
  2. 外接圆判定法

外接矩形判定法

当我们需要被检测的物体为矩形,或者形态接近于矩形,我们就可以把这个物体抽象为矩形,然后判断两个矩形是否发生了碰撞。实现该方法,我们需要做到两步:1. 找出物体的外接矩形 2. 对外接矩形进行碰撞检测。

请添加图片描述

📢 有些物体虽然看起来没有发生碰撞,但是在外接矩形检测法的规则下,它们就会被认定为发生了碰撞

在我们实际开发中,如果想要判定两个不规则的图形是否生了碰撞,是非常困难的!但是,我们使用“外接矩形法”去判断,将会特别简单,但是,“外接矩形法”有个明显的缺点,就是误差较大。即使是这样,它简单的判定方式可以减少我们的开发难度,依然备受欢迎,毕竟有得必有失,没有什么完美的算法,只能取最合适的算法

请添加图片描述

 init1() {
      class Ball {
        constructor(x, y, radius, color) {
          this.x = x
          this.y = y
          this.radius = radius
          this.color = color
          this.vx = Math.random() * 3 - 1 // 添加随机速度
          this.vy = Math.random() * 3 - 1
          this.opacity = 1
          this.lifeTime = 400 // 添加生命周期属性(毫秒)
          this.birthTime = Date.now() // 记录小球创建的时间
        }
        fill(context) {
          context.save()
          context.globalAlpha = this.opacity
          context.beginPath()
          context.arc(this.x, this.y, this.radius, 0, Math.PI * 2)
          context.fillStyle = this.color
          context.fill()
          context.closePath()
          context.restore()
        }
      }
      // 获取鼠标移动位置
      const mouseMove = element => {
        let mouse = { x: 0, y: 0 }
        element.addEventListener('mousemove', e => {
          let x = e.pageX
          let y = e.pageY
          mouse.x = e.clientX - element.getBoundingClientRect().left // 使用clientX和getBoundingClientRect计算鼠标位置
          mouse.y = e.clientY - element.getBoundingClientRect().top
        })
        return mouse
      }
      // 判断矩形是否发生了碰撞
      const checkRect = (rectA, rectB) => {
        return !(
          rectA.x + rectA.width < rectB.x ||
          rectB.x + rectB.width < rectA.x ||
          rectA.y + rectA.height < rectB.y ||
          rectB.y + rectB.height < rectA.y
        )
      }
      // 获取小球的外接矩形
      const getRect = ball => {
        return {
          x: ball.x - ball.radius,
          y: ball.y - ball.radius,
          width: ball.radius * 2,
          height: ball.radius * 2
        }
      }

      var cnv = document.getElementById('myCanvas1')
      var ctx = cnv.getContext('2d')

      const ballA = new Ball(cnv.width / 2, cnv.height / 2, 30)
      const rectA = getRect(ballA)

      const getMouse = mouseMove(cnv)

      ;(function frame() {
        window.requestAnimationFrame(frame)
        ctx.clearRect(0, 0, cnv.width, cnv.height)

        ballA.fill(ctx)
        ctx.strokeRect(rectA.x, rectA.y, rectA.width, rectA.height)

        const ballB = new Ball(getMouse.x, getMouse.y, 30, 'red')
        const rectB = getRect(ballB)
        ballB.fill(ctx)
        ctx.strokeRect(rectB.x, rectB.y, rectB.width, rectB.height)

        // 碰撞检测
        if (checkRect(rectA, rectB)) {
          ctx.save()
          ctx.fillStyle = 'red'
          ctx.font = '24px 黑体'
          ctx.fillText('撞上了', 0, 20, 50)
          ctx.restore()
        } else {
          ctx.fillStyle = 'black'
          ctx.font = '24px 黑体'
          ctx.fillText('没撞上', 0, 20, 50)
        }
      })()
    }

外接圆判定法

外接圆判定法指的是,当一个物体为圆,或者接近圆,我们可以把这个物体抽象成圆,然后判断这两个圆是否发生了碰撞。实现该方法,我们需要做到两步:1. 找出物体的外接圆 2. 对外接圆进行碰撞检测。

如下图所示,有些物体虽然看起来没有发生碰撞,但是在外接圆检测法的规则下,它们就会被认定为发生了碰撞。

请添加图片描述

请添加图片描述

 <canvas id="myCanvas" width="300" height="300"></canvas>
 init() {
      class Ball {
        constructor(x, y, radius, color) {
          this.x = x
          this.y = y
          this.radius = radius
          this.color = color
          this.vx = Math.random() * 3 - 1 // 添加随机速度
          this.vy = Math.random() * 3 - 1
          this.opacity = 1
          this.lifeTime = 400 // 添加生命周期属性(毫秒)
          this.birthTime = Date.now() // 记录小球创建的时间
        }
        fill(context) {
          context.save()
          context.globalAlpha = this.opacity
          context.beginPath()
          context.arc(this.x, this.y, this.radius, 0, Math.PI * 2)
          context.fillStyle = this.color
          context.fill()
          context.closePath()
          context.restore()
        }
      }
      // 获取鼠标移动位置
      const mouseMove = element => {
        let mouse = { x: 0, y: 0 }
        element.addEventListener('mousemove', e => {
          let x = e.pageX
          let y = e.pageY
          mouse.x = e.clientX - element.getBoundingClientRect().left // 使用clientX和getBoundingClientRect计算鼠标位置
          mouse.y = e.clientY - element.getBoundingClientRect().top
        })
        return mouse
      }

      // 定义一个函数checkCircle,用于检查两个圆是否相交
      const checkCircle = (circleA, circleB) => {
        // 计算两个圆心在x轴上的距离差
        const dx = circleB.x - circleA.x
        // 计算两个圆心在y轴上的距离差
        const dy = circleB.y - circleA.y
        // 计算两个圆心之间的距离
        const distance = Math.sqrt(dx * dx + dy * dy)
        // 判断两个圆心之间的距离是否小于两个圆的半径之和,如果是则说明两个圆相交
        if (distance < circleA.radius + circleB.radius) {
          return true // 返回true表示两个圆相交
        }
        return false // 否则返回false表示两个圆不相交
      }
      var cnv = document.getElementById('myCanvas')
      var ctx = cnv.getContext('2d')

      const ballA = new Ball(cnv.width / 2, cnv.height / 2, 30)
      const getMouse = mouseMove(cnv)

      ;(function frame() {
        window.requestAnimationFrame(frame)
        ctx.clearRect(0, 0, cnv.width, cnv.height)
        ballA.fill(ctx)

        let ballB = new Ball(getMouse.x, getMouse.y, 30, 'red')
        ballB.fill(ctx)
        if (checkCircle(ballA, ballB)) {
          ctx.save()
          ctx.fillStyle = 'red'
          ctx.font = '24px 黑体'
          ctx.fillText('撞上了', 0, 20, 50)
          ctx.restore()
        } else {
          ctx.fillStyle = 'black'
          ctx.font = '24px 黑体'
          ctx.fillText('没撞上', 0, 20, 50)
        }
      })()
    }

到此canvas碰撞检测学习结束,道阻且长,行则将至。与诸君共勉。 ⭐️

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值