Canvas进阶-4、边界检测(流光,鼠标拖尾)

1. 什么是边界检测?

在之前的开发中,物体在运动过程中一旦超出画布,就会消失,今天学习如何去检测是否碰到了边界,碰到边界后又会有哪些处理的办法。

边界检测,就是物体运动的限制范围。边界检测的范围,既可以是画布的某个区域,也可以是整个画布。

下面是一个代码示例:


html 复制代码
 <canvas id="myCanvas"></canvas>
js 复制代码
 init() {
      //定义一个球
      class Ball {
        constructor(x, y) {
          this.x = x
          this.y = y
          this.radius = 10 //球的半径
          this.color = 'red' 
        }
        fill(context) {
          context.beginPath()
          context.arc(this.x, this.y, this.radius, 0, Math.PI * 2)
          context.fillStyle = this.color
          context.fill()
          context.closePath()
        }
      }
      const cnv = document.getElementById('myCanvas')
      const cxt = cnv.getContext('2d')
      // 初始化一个小球
      const ball = new Ball(0, cnv.height / 2)
      const vx = 2

      ;(function frame() {
        window.requestAnimationFrame(frame)
        //绘制前一定要重置
        cxt.clearRect(0, 0, cnv.width, cnv.height)
        ball.x += vx
       
        if (ball.x > cnv.width + ball.radius) {
          // 完全超出右边界
          ball.x = -ball.radius
        }
        ball.fill(cxt)
      })()
    },

看图理解边界限制,什么是边界?

js 复制代码
        if (ball.x < ball.radius) {
          //半径大于圆心绘制点
          console.log('小球碰到了左边界')
        } else if (ball.x > cnv.width - ball.raduis) {
          //圆心绘制点大于canvas-半径(球的圆边)
          console.log('小球碰到了右边界')
        }
        if (ball.y < ball.radius) {
          console.log('小球碰到了上边界')
        } else if (ball.y > cnv.height - ball.raduis) {
          console.log('小球碰到了下边界')
        }
        if (ball.x < -ball.radius) {
          console.log('完全超出左边界')
        } else if (ball.x > cnv.width + ball.radius) {
          console.log('完全超出右边界')
        }

        if (ball.y < -ball.radius) {
          console.log('完全超出上边界')
        } else if (ball.y > cnv.height + ball.radius) {
          console.log('完全超出下边界')
        }

2.如何利用边界?进阶应用

上图为超出边界线消失,下图只要我们稍稍调整,就成为一个简单的鼠标拖尾,就是如此简单

js 复制代码
 init1() {
      class Ball {
        constructor(x, y, color, radius) {
          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()
        }
      }

      function getMouse(element) {
        let mouse = { x: 0, y: 0 }
        element.addEventListener('mousemove', e => {
          mouse.x = e.clientX - element.getBoundingClientRect().left // 使用clientX和getBoundingClientRect计算鼠标位置
          mouse.y = e.clientY - element.getBoundingClientRect().top
        })
        return mouse
      }

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

      const getRandomColor = () => {
        return '#' + Math.floor(Math.random() * 16777215).toString(16)
      }

      let balls = []

      cnv.addEventListener('mousemove', () => {
        // 生成新小球
        const ball = new Ball(mouse.x, mouse.y, getRandomColor(), 2)
        balls.push(ball)
      })

      function frame() {
        window.requestAnimationFrame(frame)
        ctx.clearRect(0, 0, cnv.width, cnv.height)
        balls.forEach((ball, index) => {
          const remainingLifeTime = ball.lifeTime - (Date.now() - ball.birthTime)
          if (remainingLifeTime <= 0) {
            balls.splice(index, 1)
          } else {
            // 否则,根据剩余生命周期计算透明度
            ball.opacity = remainingLifeTime / ball.lifeTime
            ball.fill(ctx)
            ball.x += ball.vx
            ball.y += ball.vy
          }
        })
      }

      frame()
    }

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

相关推荐
霸道流氓气质几秒前
Java 大数据量异步处理方案:线程池 vs 消息队列
java·开发语言
devilnumber几秒前
想真正吃透 + 灵活运用 Java 代理模式
java·开发语言·代理模式
AC赳赳老秦5 分钟前
OpenClaw 助力技术面试:自动生成面试题、模拟面试、整理面试知识点
开发语言·python·面试·职场和发展·自动化·deepseek·openclaw
刘科领8 分钟前
修改jdk 第一步: 仓库以及构建(jdk17)
java·开发语言
道友可好12 分钟前
用 Linter 驾驭 AI:机械化执行的艺术
前端·人工智能·后端
C+-C资深大佬14 分钟前
C++ 中的 constexpr与 const区
java·开发语言·c++
流浪码农~17 分钟前
Element Plus DatePicker 动态设置每周起始日
前端·vue.js·elementui
仙俊红19 分钟前
Java 单例模式:类里面为什么可以有自己类型的字段?
java·开发语言·单例模式
jason_yang20 分钟前
刚发版就背锅?前端版本控制就靠他version-rocket
前端
如果超人不会飞23 分钟前
TinyVue NavMenu导航菜单组件使用指南
前端·vue.js