canvas 1000个小球弹射

191 阅读3分钟

我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!

前言

大家好,我是小阵 🔥,一路奔波不停的码字业务员
如果喜欢我的文章,可以关注 ➕ 点赞,与我一同成长吧~😋
加我微信:zzz886885,邀你进群,一起学习交流,摸鱼学习两不误🌟

开开心心学技术大法~~

开心

来了来了,他真的来了~

正文

先看效果

iShot_2022-09-22_00.01.14

实现思路

  • 首先是可以看到左上角一个绝对定位的一个框体用来描述信息和一个开始按钮

  • 然后下面一整个都是一个canvas

  • 可以看到在Start之前canvas就是一个棋盘,因此需要首先绘制一个棋盘

  • 绘制棋盘只需要首先绘制纵向的,再绘制横向的

    • 绘制纵向和和横向的思想都一样
    • 通过moveTo确定落点,通过lineTo画线到canvas的右边缘或下边缘即可
  • 然后是开始之后的情况

  • 先看如何维护开始状态

    • 只有开始状态才会开始绘制多个球体运动的canvas
    • 因此只需要将这一个变量跟start的btn点击事件绑定起来即可
  • 再来看canvas生成球体

  • 可以一个循环生成多条绘制圆形的ctx.arc()的必要参数,x,y,radius,起点,终点,画笔颜色,x方向运动速率,y方向运动速率

  • 生成了球体数据,自然而然的就可以通过canvas生成这些球体

  • 如何让球体动起来?

    • 可以通过无限迭代循环下去,当然也要有sleep的操作,要不然canvas的操作就快了,我们就没办法看到运动的效果了
    • 也可以通过setInterval来让球体动起来
  • 具体怎样操作?

    • 我们只需要在每一个时间片段清空画布再重新计算圆球的下一个位置信息,将新的圆球绘制上去即可
    • 至于怎样计算下一个位置信息,我们上面保留了x和y方向的速率,我们只需要每个时间片段从当前x,y坐标加上速率即是下一个位置信息
  • 然后是球体碰到canvas的边缘转换方向

    • canvas有四条边,因此需要考虑四种情况
    • 这个是数学问题,大家想一下就能明白,我就不浪费口舌了,一会儿看到代码就都清楚了
  • 对了,多说一句,定时器最好是1000 / 60,因为人眼能捕捉到的频率就是这个,当然也可以通过requestAnimationFrame来控制,效果比1000 / 60更好,那个是基于当前浏览器的刷新频率的

  • 其他的应该没什么,剩下的都在代码里

具体实现

html结构

<body>
  <!--玻璃窗格 glass pane-->
  <div id='glasspane'>
    <h2 class='title'>弹射小球</h2>
​
    <p>一千个小球弹射</p>
​
    <a id='startButton'>Start</a>
  </div><canvas id='canvas' width='750' height='500'>
    Canvas not supported
  </canvas>
</body>

基础css样式

body {
  background: #dddddd;
}
​
#canvas {
  margin-left: 10px;
  margin-top: 10px;
  background: #ffffff;
  border: thin solid #aaaaaa;
}
​
#glasspane {
  position: absolute;
  left: 50px;
  top: 50px;
  padding: 0px 20px 10px 10px;
  background: rgba(0, 0, 0, 0.3);
  border: thin solid rgba(0, 0, 0, 0.6);
  color: #eeeeee;
  font-family: Droid Sans, Arial, Helvetica, sans-serif;
  font-size: 12px;
  cursor: pointer;
  -webkit-box-shadow: rgba(0, 0, 0, 0.5) 5px 5px 20px;
  -moz-box-shadow: rgba(0, 0, 0, 0.5) 5px 5px 20px;
  box-shadow: rgba(0, 0, 0, 0.5) 5px 5px 20px;
}
​
#glasspane h2 {
  font-weight: normal;
}
​
#glasspane .title {
  font-size: 2em;
  color: rgba(255, 255, 0, 0.8);
}
​
#glasspane a:hover {
  color: yellow;
}
​
#glasspane a {
  text-decoration: none;
  color: #cccccc;
  font-size: 3.5em;
}
​
#glasspane p {
  margin: 10px;
  color: rgba(65, 65, 220, 1.0);
  font-size: 12pt;
  font-family: Palatino, Arial, Helvetica, sans-serif;
}

canvas代码

生成表格

// 渲染表格
function drawGird(context,color,stepX,stepY) {
  context.strokeStyle = color;
  context.lineWidth = 0.5;
​
  for (var i = stepX+0.5;i<context.canvas.width;i+=stepX){
    context.beginPath();
    context.moveTo(i,0);
    context.lineTo(i, context.canvas.height);
    context.stroke();
  }
​
  for (var i = stepY + 0.5; i < context.canvas.height; i+=stepY) {
    context.beginPath();
    context.moveTo(0, i);
    context.lineTo(context.canvas.width, i);
    context.stroke();
  }
}

然后是循环生成球体数据

//给1000个小球设置不同的方向,半径,颜色
for (var i = 0; i < 1000; i++) {
  circles[i] = {
    x: 100,
    y: 100,
    //向x方向移动的像素
    velocityX: 3 * Math.random(),
    velocityY: 3 * Math.random(),
    radius: 20 * Math.random() + 5,
    color: 'rgba(' + (Math.random() * 255).toFixed(0) + ',' +
    (Math.random() * 255).toFixed(0) + ',' +
    (Math.random() * 255).toFixed(0) + ',1.0)'
  };
}

球体动画

setInterval(function () {
  if (!paused) {
    context.clearRect(0, 0, context.canvas.width, context.canvas.height);
    drawGird(context, 'lightgray', 10, 10);
​
    circles.forEach(function (circle) {
      context.beginPath();
      context.arc(circle.x, circle.y, circle.radius,
                  0, Math.PI * 2, false);
      context.fillStyle = circle.color;
      context.fill();
      adjustPosition(circle);
    });
  }
}, 1000 / 60);

球体转方向

function adjustPosition(circle) {
  if (circle.x + circle.velocityX + circle.radius > context.canvas.width || circle.x - circle.radius + circle.velocityX<0)
    circle.velocityX = -circle.velocityX;
​
  if (circle.y + circle.velocityY + circle.radius > context.canvas.height || circle.y - circle.radius + circle.velocityY<0)
    circle.velocityY = -circle.velocityY;
​
  circle.x += circle.velocityX;
  circle.y += circle.velocityY;
}

完整代码

总结

  • canvas表格绘制
  • cavnas球体数据生成与绘制(速率)
  • 球体canavs边缘转方向

结语

如果文章真的有帮到你,希望可以多多点赞、收藏、关注支持一波呀!!小阵会很开心哒~

热爱开源,支持开源,拥抱开源!

文章如有错误或不严谨之处,还望指出,感谢感谢!!!

加油!

往期好文推荐