前端canvas粒子碰撞小球动画

337 阅读3分钟

前端canvas粒子碰撞小球动画

第一步:初始化

程序逻辑:

  1. 获取浏览器宽高
  2. 给canvas设置宽高
  3. 给canvas设置宽高
  4. 浏览器宽高发生变化重新设置canvas的宽高
 // 获取canvas元素
 const canvas = document.querySelector("#canvas");
 // 初始化圆心坐标
 let x = 100,
     y = 100;
 // 获取浏览器宽高
 const w = window.innerWidth;
 const h = window.innerHeight;
 //给canvas设置宽高
 canvas.width=w
 canvas.height=h
 // 浏览器宽高变化重置宽高
 window.onresize = () => {
    const w = window.innerWidth;
    const h = window.innerHeight;
    canvas.width = w;
    canvas.height = h;
 };
 ​
 // 优化重置函数后
 const canvas = document.querySelector("#canvas");
 let w, h;
 // 初始化圆心坐标
 let x = 100,
     y = 100;
 (function setSize() {
    window.onresize = arguments.callee;
    const w = window.innerWidth;
    const h = window.innerHeight;
    canvas.width = w;
    canvas.height = h;
 })();
 ​

第二步:开始绘制

  1. 获取绘制区域

     // 获取可以绘制的区域
     const ctx = canvas.getContext("2d");
    
  2. 添加绘制的颜色

     // 添加绘制颜色
     ctx.fillStyle = "red";
    
  3. 开始绘画第一个圆

     ctx.arc(x, y, 66, 0, 2 * Math.PI);
     ctx.fill();
    
  4. 重复画圆

     setInterval(() => {
         ctx.beginPath();
         ctx.clearRect(0, 0, w, h);
         ctx.fillStyle = "red";
         ctx.arc(x++, y++, 66, 0, 2 * Math.PI);
         ctx.fill();
     }, 1000 / 60);
    

第三步:面向对象重构小球

以上已经能实现效果,但是不符合面向对象编程,因此上面的代码改写为面向对象编程方式,代码如下:

 // 随机坐标生成函数
 const randomNum = (min, max) => {
     return Math.random() * (max - min) + min;
 };
 // 随机颜色预制
 const colorList = ["#7AA874", "#F7DB6A", "#EBB02D", "#D864A9", "#159895"];
 class LittleBall {
     // 初始化属性
     constructor() {
         this.px = randomNum(0, w); // 小球很坐标
         this.py = randomNum(0, h); // 小球纵坐标
         this.r = randomNum(1, 4); // 小球半径
         this.color = colorList[Math.floor(randomNum(0, 5))]; // 小球颜色
     }
     // 绘制小球
     drawBall() {
         ctx.beginPath();
         ctx.fillStyle = this.color;
         ctx.arc(this.px, this.py, this.r, 0, 2 * Math.PI);
         ctx.fill();
     }
 }
 // 测试
 const ball = new LittleBall();
 ball.drawBall();

image-20230330105207946.png

 // 为方便产生更多的小球,封装函数调用,传入需要绘制的小球数目即可
 function createBall(num) {
     for (let index = 0; index < num; index++) {
         const ball = new LittleBall();
         ball.drawBall();
     }
 }
 // 比如生成2000个
 createBall(2000);

得到效果如下图:

image-20230330105744958.png

image-20230330110847097.png

添加移动的方法

 // 小球移动的方法
 ballMove() {
     if (this.px - this.r < 0 || this.px + this.r > w) {
         this.vx = -this.vx;
     }
     if (this.py - this.r < 0 || this.py + this.r > h) {
         this.vy = -this.vy;
     }
 ​
     this.px += this.vx;
     this.py += this.vy;
     this.drawBall();
 }

移动的小球.gif

移动的小球01.gif

为了方便记录移动的位置还需要初始化变量保存绘制的小球

 // 创建一个变量储存小球信息
 const ballList = [];
 ​
 // 在绘制小球的时候把小球保存到变量中
 function createBall(num) {
     for (let index = 0; index < num; index++) {
         const ball = new LittleBall();
         ball.drawBall();
         ballList.push(ball);
     }
 }
 ​
 ​
 // 定时器运动
 setInterval(() => {
     ctx.clearRect(0, 0, w, h);
     ballList.forEach((item) => {
         item.ballMove();
     });
 }, 20);

最终效果如下图:

移动的小球03.gif

完整全部代码

html

<canvas id="canvas">你的浏览器不支持canvas元素</canvas>

js

const canvas = document.querySelector("#canvas");
   let w, h;
   // 初始化圆心坐标
   let x = 100,
           y = 100;
   // 创建一个变量储存小球信息
  const ballList = [];
  (function setSize() {
     window.onresize = arguments.callee;
     w = window.innerWidth;
     h = window.innerHeight;
      canvas.width = w;
     canvas.height = h;
  })();
   // 获取可以绘制的区域
   const ctx = canvas.getContext("2d");
   // 添加绘制颜色
   ctx.fillStyle = "red";
   
   // 随机坐标生成函数
   const randomNum = (min, max) => {
     return Math.random() * (max - min) + min;
   };
   // 随机颜色预制
const colorList = ["#7AA874", "#F7DB6A", "#EBB02D", "#D864A9", "#159895"];
class LittleBall {
   // 初始化属性
   constructor() {
           this.px = randomNum(0, w); // 小球横坐标
           this.py = randomNum(0, h); // 小球纵坐标
           this.r = randomNum(1, 4); // 小球半径
          this.color = colorList[Math.floor(randomNum(0, 5))]; // 小球颜色
         // 往哪个方向移动
        this.vx = randomNum(-1, 1);
       this.vy = randomNum(-1, 1);
}
// 绘制小球
drawBall() {
      ctx.beginPath();
     ctx.fillStyle = this.color;
    ctx.arc(this.px, this.py, this.r, 0, 2 * Math.PI);
   ctx.fill();
 }
// 小球移动的方法
ballMove() {
      if (this.px - this.r < 0 || this.px + this.r > w) {
             this.vx = -this.vx;
    }
   if (this.py - this.r < 0 || this.py + this.r > h) {
          this.vy = -this.vy;
 }

          this.px += this.vx;
         this.py += this.vy;
        this.drawBall();
}
}

  // 为方便产生更多的小球,封装函数调用,传入需要绘制的小球数目即可
function createBall(num) {
       for (let index = 0; index < num; index++) {
              const ball = new LittleBall();
             ball.drawBall();
            ballList.push(ball);
   }
}
createBall(500);
// 定时器运动
setInterval(() => {
      ctx.clearRect(0, 0, w, h);
     ballList.forEach((item) => {
            item.ballMove();
   });
}, 20);

css

* {
  margin: 0;
 padding: 0;
box-sizing: border-box;
}
#canvas {
  display: block;
}