前端canvas粒子碰撞小球动画
第一步:初始化
程序逻辑:
- 获取浏览器宽高
- 给canvas设置宽高
- 给canvas设置宽高
- 浏览器宽高发生变化重新设置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; })();
第二步:开始绘制
-
获取绘制区域
// 获取可以绘制的区域 const ctx = canvas.getContext("2d"); -
添加绘制的颜色
// 添加绘制颜色 ctx.fillStyle = "red"; -
开始绘画第一个圆
ctx.arc(x, y, 66, 0, 2 * Math.PI); ctx.fill(); -
重复画圆
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();
// 为方便产生更多的小球,封装函数调用,传入需要绘制的小球数目即可
function createBall(num) {
for (let index = 0; index < num; index++) {
const ball = new LittleBall();
ball.drawBall();
}
}
// 比如生成2000个
createBall(2000);
得到效果如下图:
添加移动的方法
// 小球移动的方法 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(); }
为了方便记录移动的位置还需要初始化变量保存绘制的小球
// 创建一个变量储存小球信息 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);
最终效果如下图:
完整全部代码
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; }