当青训营遇上码上掘金|遇见

200 阅读2分钟

当青训营遇上码上掘金

主题 2:遇见

据说世界上两个陌生人相遇且相识的概率是 0.0000005,大家来到我们青训营能够遇见许多志同道合的伙伴一同学习、快乐成长,这是件多么美妙的事情。请大家围绕“遇见”这个主题进行代码创作。

💡效果如下图所示:

截屏2023-02-12 12.04.29.png

设计思路

两个人在茫茫人海中相遇和概率据说只有0.0000005。我看到这个题目第一时间就想到了无序额度粒子系统。完全无序的粒子在画布上无序运动,不正像是茫茫人海中的红尘众生吗?再点上两个红绿色的粒子代表陌生的两个人,在这茫茫的人海中随波逐流,相遇的几率确实渺茫至极。

正巧前两天跟着某博主利用canvas绘制了无序粒子,正好发扬拿来主义,稍加修改,便成了这个作品~

代码逻辑

利用canvas画布功能,绘制粒子和统计数据。

  • 首先写入canvas标签
<canvas id="canvas"></canvas>
  • 数据初始化部分:初始化粒子数量,粒子大小,粒子颜色等信息

    • 设置背景人物:本案例将背景人数设置为100个,可以模拟出较好的人海效果并且节省性能。
    //定义背景人海粒子
    const particleNum = 100;
    const colorRGB = "254, 250, 224";
    let particles = [];
    let interacionParticle = null;
    
    • 设置陌生两个人:因为要单独设置样式,计算相遇和位置等,因此单独提出来作为变量保存,便于后期读取
    //定义陌生的两人
    let person = [];
    const personNumber = 2;
    const personDistance = 20;
    const personColor = ["red", "green"];
    const personSize = 5;
    let flag = true;
    
    //节流后返回的函数~
    let printProbability;
    
    //相遇可能性
    const date = +new Date();
    let collision = 1;
    let possible = 1;
    
    • 定义粒子类:包括位置(x, y)和正交分速度(velocityX, velocityY),粒子大小和颜色。
    //定义粒子类
    class Particle {
      constructor(x, y, velocityX, velocityY, size, color) {
        this.x = x;
        this.y = y;
        this.velocityX = velocityX;
        this.velocityY = velocityY;
        this.size = size;
        this.color = color;
      }
      draw() {
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
        ctx.fillStyle = this.color;
        ctx.fill();
      }
      update() {
        if (this.x < 0 || this.x > canvas.width) {
          this.velocityX *= -1;
        }
        if (this.y < 0 || this.y > canvas.height) {
          this.velocityY *= -1;
        }
        this.x += this.velocityX;
        this.y += this.velocityY;
        this.draw();
      }
    }
    
    • 创建粒子:用createParticlescreatePerson两个函数分别创造背景粒子和陌生人粒子
    //背景粒子
    function createParticles() {
      for (let i = 0; i < particleNum; i++) {
        let size = getRandomArbitrary(2, 5);
        let x = Math.random() * canvas.width;
        let y = Math.random() * canvas.height;
        let velocityX = getRandomArbitrary(-2, 2);
        let velocityY = getRandomArbitrary(-2, 2);
        let color = `rgba(${colorRGB},${1 - size / 5})`;
        particles.push(
          new Particle(x, y, velocityX, velocityY, size, color)
        );
      }
    }
    
    //创造相遇的陌生人粒子
    function createPerson() {
      for (let i = 0; i < personNumber; i++) {
        let x = Math.random() * canvas.width;
        let y = Math.random() * canvas.height;
        let velocityX = getRandomArbitrary(-2, 2);
        let velocityY = getRandomArbitrary(-2, 2);
        person.push(
          new Particle(
            x,
            y,
            velocityX,
            velocityY,
            personSize,
            personColor[i]
          )
        );
      }
    }
    
    • 计算相遇可能性:利用初始化中的时间戳和每次更新动画时间戳对比,计算经过时间(在本案例中设置1秒1天);然后通过相遇次数和时间相除得到相遇概率。

      PS:为了计算方便,将初始的相遇次数置为1,便于看到概率随时间下降。

    function probability() {
      let distance = Math.sqrt(
        Math.pow(person[0].x - person[1].x, 2) +
          Math.pow(person[0].y - person[1].y, 2)
      );
      possible = collision / ((+new Date() - date) / 1000);
      console.log(possible);
    }
    
    • 定义动画:利用requestAnimationFrameAPI,申请动画帧。
    //定义动画
    function animate() {
      requestAnimationFrame(animate);
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      particles.forEach((item) => {
        item.update();
      });
      person.forEach((item) => {
        item.update();
      });
      printProbability();
      connect();
      ctx.beginPath();
      ctx.fillStyle = `rgba(${colorRGB},0.5)`;
      ctx.fillRect(0, 0, 300, 180);
      ctx.beginPath();
      ctx.font = "26px sanserif";
      if (possible < 0.0000005) {
        ctx.fillStyle = "red";
      } else {
        ctx.fillStyle = "#fff";
      }
      ctx.fillText(`经过时间:${((+new Date() - date) / 1000).toFixed(0)} 天`, 30, 50);
      ctx.fillText(`相遇次数:${collision - 1} 次`, 30, 100);
      ctx.fillText(`相遇概率:${possible.toFixed(7)}`, 30, 150);
    }
    

效果展示

可能由于页面大小原因显示不完整,具体可以查看这个链接遇见