SOURCE

console 命令行工具 X clear

                    
>
console
 // 获取canvas画布和context
    const canvas = document.getElementById('canvas')
    const ctx = canvas.getContext('2d')

    // 封装一个小球类
    class Ball {
      constructor(x, y, radius) {
        this.x = x
        this.y = y
        this.radius = radius
        this.dx = Math.random() * 5
        this.dy = Math.random() * 5
        this.flag = false
      }

      draw(ctx) {
        ctx.beginPath()
        ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI)
        ctx.closePath()
        ctx.fillStyle = 'blue'
        ctx.fill()
      }

      collide(ball) {
        const dx = this.x - ball.x
        const dy = this.y - ball.y
        const dl = Math.sqrt(dx * dx + dy * dy)
        return dl <= this.radius + ball.radius
      }
      redirect(ball) {
        if (!this.flag) {
            const dx = ball.dx; ball.dx = this.dx; this.dx = dx;
            const dy = ball.dy; ball.dy = this.dy; this.dy = dy;

            this.flag = true
            ball.flag = true
        }
      }
    }

    // 随机生成若干个小球
    const balls = []
    while (balls.length < 5) {
      const radius = Math.random() * 20 + 10 // 10 ~ 30
      const x = Math.random() * (canvas.width - radius - radius) + radius
      const y = Math.random() * (canvas.height - radius - radius) + radius

      // let flag = true
      const newBall = {x, y, radius}
      if (balls.every( x => !x.collide(newBall))) {
        balls.push(new Ball(x, y, radius))
      }
    }

    function drawFrame () {
      window.requestAnimationFrame(drawFrame, canvas)
      canvas.height = canvas.height // 清空画布

      // 绘制墙壁
      ctx.strokeRect(0, 0, canvas.width, canvas.height)
      for (let ball of balls) {
        // 计算小球下一帧的坐标
        ball.x += ball.dx
        ball.y -= ball.dy

        // 绘制
        ball.draw(ctx)
        ball.flag = false
      }
      for (let i = 0; i < balls.length; i++) {
        const ball = balls[i]
        // 判断与墙壁的碰撞反弹
        if (!ball.flag) {
          if (ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
            ball.dx = -ball.dx
            ball.flag = true
          }

          if (ball.y - ball.radius < 0 || ball.y + ball.radius > canvas.height) {
            ball.dy = -ball.dy
            ball.flag = true
          }
        }
        // 判断小球间的碰撞
        for (let j = i + 1; j < balls.length; j++) {
          if (ball.collide(balls[j])) {
            ball.redirect(balls[j])
          }
        }


      }

    }

    drawFrame()
	<canvas id="canvas" width="300" height="300"></canvas>