HTML Canvas Animation Bouncing Balls With Interactions and Friction

Description

HTML Canvas Animation Bouncing Balls With Interactions and Friction

View in separate window

<!doctype html>
<html lang="en">
<body>
  <canvas id="canvasOne" width="500" height="500">
 Your browser does not support the HTML 5 Canvas. 
</canvas>//from  w w w.  j a  v  a  2 s.c  o m
  <script type="text/javascript">
    function drawScreen() {
      context.fillStyle = '#EEEEEE';
      context.fillRect(0, 0, theCanvas.width, theCanvas.height);
      //Box
      context.strokeStyle = '#000000';
      context.strokeRect(1, 1, theCanvas.width - 2, theCanvas.height - 2);

      update();
      testWalls();
      collide();
      render();

    }

    function update() {
      for (let i = 0; i < balls.length; i++) {
        ball = balls[i];
        //Friction
        ball.velocityx = ball.velocityx - (ball.velocityx * friction);
        ball.velocityy = ball.velocityy - (ball.velocityy * friction);

        ball.nextx = (ball.x += ball.velocityx);
        ball.nexty = (ball.y += ball.velocityy);
      }

    }

    function testWalls() {
      let ball;
      let testBall;

      for (let i = 0; i < balls.length; i++) {
        ball = balls[i];

        if (ball.nextx + ball.radius > theCanvas.width) {
          ball.velocityx = ball.velocityx * -1;
          ball.nextx = theCanvas.width - ball.radius;

        } else if (ball.nextx - ball.radius < 0) {
          ball.velocityx = ball.velocityx * -1;
          ball.nextx = ball.radius;

        } else if (ball.nexty + ball.radius > theCanvas.height) {
          ball.velocityy = ball.velocityy * -1;
          ball.nexty = theCanvas.height - ball.radius;

        } else if (ball.nexty - ball.radius < 0) {
          ball.velocityy = ball.velocityy * -1;
          ball.nexty = ball.radius;
        }

      }

    }

    function render() {
      let ball;

      context.fillStyle = "#000000";
      for (let i = 0; i < balls.length; i++) {
        ball = balls[i];
        ball.x = ball.nextx;
        ball.y = ball.nexty;

        context.beginPath();
        context.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2, true);
        context.closePath();
        context.fill();
      }

    }

    function collide() {
      let ball;
      let testBall;
      for (let i = 0; i < balls.length; i++) {
        ball = balls[i];
        for (let j = i + 1; j < balls.length; j++) {
          testBall = balls[j];
          if (hitTestCircle(ball, testBall)) {
            collideBalls(ball, testBall);
          }
        }
      }
    }

    function hitTestCircle(ball1, ball2) {
      let retval = false;
      let dx = ball1.nextx - ball2.nextx;
      let dy = ball1.nexty - ball2.nexty;
      let distance = (dx * dx + dy * dy);
      if (distance <= (ball1.radius + ball2.radius)
          * (ball1.radius + ball2.radius)) {
        retval = true;
      }
      return retval;
    }

    function collideBalls(ball1, ball2) {

      let dx = ball1.nextx - ball2.nextx;
      let dy = ball1.nexty - ball2.nexty;

      let collisionAngle = Math.atan2(dy, dx);

      let speed1 = Math.sqrt(ball1.velocityx * ball1.velocityx
          + ball1.velocityy * ball1.velocityy);
      let speed2 = Math.sqrt(ball2.velocityx * ball2.velocityx
          + ball2.velocityy * ball2.velocityy);

      let direction1 = Math.atan2(ball1.velocityy, ball1.velocityx);
      let direction2 = Math.atan2(ball2.velocityy, ball2.velocityx);

      let velocityx_1 = speed1 * Math.cos(direction1 - collisionAngle);
      let velocityy_1 = speed1 * Math.sin(direction1 - collisionAngle);
      let velocityx_2 = speed2 * Math.cos(direction2 - collisionAngle);
      let velocityy_2 = speed2 * Math.sin(direction2 - collisionAngle);

      let final_velocityx_1 = ((ball1.mass - ball2.mass) * velocityx_1 + (ball2.mass + ball2.mass)
          * velocityx_2)
          / (ball1.mass + ball2.mass);
      let final_velocityx_2 = ((ball1.mass + ball1.mass) * velocityx_1 + (ball2.mass - ball1.mass)
          * velocityx_2)
          / (ball1.mass + ball2.mass);

      let final_velocityy_1 = velocityy_1;
      let final_velocityy_2 = velocityy_2;

      ball1.velocityx = Math.cos(collisionAngle) * final_velocityx_1
          + Math.cos(collisionAngle + Math.PI / 2)
          * final_velocityy_1;
      ball1.velocityy = Math.sin(collisionAngle) * final_velocityx_1
          + Math.sin(collisionAngle + Math.PI / 2)
          * final_velocityy_1;
      ball2.velocityx = Math.cos(collisionAngle) * final_velocityx_2
          + Math.cos(collisionAngle + Math.PI / 2)
          * final_velocityy_2;
      ball2.velocityy = Math.sin(collisionAngle) * final_velocityx_2
          + Math.sin(collisionAngle + Math.PI / 2)
          * final_velocityy_2;

      ball1.nextx = (ball1.nextx += ball1.velocityx);
      ball1.nexty = (ball1.nexty += ball1.velocityy);
      ball2.nextx = (ball2.nextx += ball2.velocityx);
      ball2.nexty = (ball2.nexty += ball2.velocityy);
    }
    let numBalls = 50;
    let maxSize = 12;
    let minSize = 3;
    let maxSpeed = maxSize + 5;
    let balls = new Array();
    let tempBall;
    let tempX;
    let tempY;
    let tempSpeed;
    let tempAngle;
    let tempRadius;
    let tempRadians;
    let tempvelocityx;
    let tempvelocityy;
    let friction = .01;

    theCanvas = document.getElementById('canvasOne');
    context = theCanvas.getContext('2d');

    for (let i = 0; i < numBalls; i++) {
      tempRadius = Math.floor(Math.random() * maxSize) + minSize;
      let placeOK = false;
      while (!placeOK) {
        tempX = tempRadius
            * 3
            + (Math.floor(Math.random() * theCanvas.width) - tempRadius * 3);
        tempY = tempRadius
            * 3
            + (Math.floor(Math.random() * theCanvas.height) - tempRadius * 3);
        tempSpeed = maxSpeed - tempRadius;
        tempAngle = Math.floor(Math.random() * 360);
        tempRadians = tempAngle * Math.PI / 180;
        tempvelocityx = Math.cos(tempRadians) * tempSpeed;
        tempvelocityy = Math.sin(tempRadians) * tempSpeed;

        tempBall = {
          x : tempX,
          y : tempY,
          radius : tempRadius,
          speed : tempSpeed,
          angle : tempAngle,
          velocityx : tempvelocityx,
          velocityy : tempvelocityy,
          mass : tempRadius * 8,
          nextx : tempX,
          nexty : tempY
        };
        placeOK = canStartHere(tempBall);
      }
      balls.push(tempBall);
    }

    function canStartHere(ball) {
      let retval = true;
      for (let i = 0; i < balls.length; i++) {
        if (hitTestCircle(ball, balls[i])) {
          retval = false;
        }
      }
      return retval;
    }
    function gameLoop() {
      window.setTimeout(gameLoop, 20);
      drawScreen()
    }

    gameLoop();
  </script>
</body>
</html>



PreviousNext

Related