onlyforbopi
9/24/2018 - 9:48 AM

JS.Interact.Animate.UseArraysandLoopstoAnimatemany.ex1

JS.Interact.Animate.UseArraysandLoopstoAnimatemany.ex1

canvas {
  border: 1px solid black;
}
// useful to have them as global variables
var canvas, ctx, w, h; 
// an empty array!
var balls = []; 

var player = {
  x:10,
  y:10,
  width:20,
  height:20,
  color:'red'
}

window.onload = function init() {
    // called AFTER the page has been loaded
    canvas = document.querySelector("#myCanvas");
  
    // often useful
    w = canvas.width; 
    h = canvas.height;  
  
    // important, we will draw with this object
    ctx = canvas.getContext('2d');
  
    // create 10 balls
    balls = createBalls(10);
  
    // ready to go !
    mainLoop();
};

function mainLoop() {
  // 1 - clear the canvas
  ctx.clearRect(0, 0, w, h);
  
  // draw the ball and the player
  drawFilledRectangle(player);
  drawAllBalls(balls);

  // animate the ball that is bouncing all over the walls
  moveAllBalls(balls)
  
  // ask for a new animation frame
  requestAnimationFrame(mainLoop);
}

function createBalls(n) {
  // empty array
  var ballArray = [];
  
  // create n balls
  for(var i=0; i < n; i++) {
     var b = {
        x:w/2,
        y:h/2,
        radius: 5 + 30 * Math.random(), // between 5 and 35
        speedX: -5 + 10 * Math.random(), // between -5 and + 5
        speedY: -5 + 10 * Math.random(), // between -5 and + 5
        color:getARandomColor(),
      }
     // add ball b to the array
     ballArray.push(b);
    }
  // returns the array full of randomly created balls
  return ballArray;
}

function getARandomColor() {
  var colors = ['red', 'blue', 'cyan', 'purple', 'pink', 'green', 'yellow'];
  // a value between 0 and color.length-1
  // Math.round = rounded value
  // Math.random() a value between 0 and 1
  var colorIndex = Math.round((colors.length-1)*Math.random()); 
  var c = colors[colorIndex];
  
  // return the random color
  return c;
}

function drawAllBalls(ballArray) {
    ballArray.forEach(function(b) {
      drawFilledCircle(b);
    });
}

function moveAllBalls(ballArray) {
  // iterate on all balls in array
  ballArray.forEach(function(b) {
      // b is the current ball in the array
      b.x += b.speedX;
      b.y += b.speedY;
  
      testCollisionBallWithWalls(b); 
  });
}

function testCollisionBallWithWalls(b) {
    // COLLISION WITH VERTICAL WALLS ?
    if((b.x + b.radius) > w) {
    // the ball hit the right wall
    // change horizontal direction
    b.speedX = -b.speedX;
    
    // put the ball at the collision point
    b.x = w - b.radius;
  } else if((b.x -b.radius) < 0) {
    // the ball hit the left wall
    // change horizontal direction
    b.speedX = -b.speedX;
    
    // put the ball at the collision point
    b.x = b.radius;
  }
  
  // COLLISIONS WTH HORIZONTAL WALLS ?
  // Not in the else as the ball can touch both
  // vertical and horizontal walls in corners
  if((b.y + b.radius) > h) {
    // the ball hit the right wall
    // change horizontal direction
    b.speedY = -b.speedY;
    
    // put the ball at the collision point
    b.y = h - b.radius;
  } else if((b.y -b.radius) < 0) {
    // the ball hit the left wall
    // change horizontal direction
    b.speedY = -b.speedY;
    
    // put the ball at the collision point
    b.Y = b.radius;
  }  
}

function drawFilledRectangle(r) {
    // GOOD practice: save the context, use 2D trasnformations
    ctx.save();
  
    // translate the coordinate system, draw relative to it
    ctx.translate(r.x, r.y);
  
    ctx.fillStyle = r.color;
    // (0, 0) is the top left corner of the monster.
    ctx.fillRect(0, 0, r.width, r.height);
  
    // GOOD practice: restore the context
    ctx.restore();
}

function drawFilledCircle(c) {
    // GOOD practice: save the context, use 2D trasnformations
    ctx.save();
  
    // translate the coordinate system, draw relative to it
    ctx.translate(c.x, c.y);
  
    ctx.fillStyle = c.color;
    // (0, 0) is the top left corner of the monster.
    ctx.beginPath();
    ctx.arc(0, 0, c.radius, 0, 2*Math.PI);
    ctx.fill();
 
    // GOOD practice: restore the context
    ctx.restore();
}

JS.Interact.Animate.UseArraysandLoopstoAnimatemany.ex1

A Pen by Pan Doul on CodePen.

License.

<!DOCTYPE html>
<html lang="en">
<head>
  
<!----
Let's look at the new functions we've added: 

createBalls(numberOfBalls), returns an array of balls:

function createBalls(n) {
  // empty array
  var ballArray = [];
  // create n balls
  for(var i=0; i < n; i++) {
      var b = {
          x:w/2,
          y:h/2,
          radius: 5 + 30 * Math.random(), // between 5 and 35
          speedX: -5 + 10 * Math.random(), // between -5 and + 5
          speedY: -5 + 10 * Math.random(), // between -5 and + 5
          color: getARandomColor(),
      }
      // add ball b to the array
      ballArray.push(b);
  }
  // returns the array full of randomly created balls
  return ballArray;
}
Explanations:

Line 3: we declare an empty array that will contain the balls,
Lines 7-14: we create a new ball object with random values. Note the use of Math.random(), a predefined JavaScript function that returns a decimal value between 0 and 1. We call another function named getARandomColor() that returns a color taken randomly.
Line 16: we add the newly created ball b to the array,
Line 19: we return the array to the caller.
The getARandomColor function

function getARandomColor() {
    var colors = ['red', 'blue', 'cyan', 'purple',
                  'pink', 'green', 'yellow'];
    // a value between 0 and color.length-1
    // Math.round = rounded value
    // Math.random() a value between 0 and 1
    var colorIndex = Math.round((colors.length-1)*Math.random());
    var c = colors[colorIndex];
    // return the random color
    return c;
}
Explanations:

Line 2: in this function, we use an array of random color names named colors (you can go on the codePen example and change these colors or add new ones).
Line 7: then we compute an index with a random value between 0 and colors.length-1. Remember that in an array of n elements, the index of the first is always 0 and the index of the last one is always equal to the length of the array -1. For example: var myArray = ['red', 'blue', 'green'], red is at index 0, green at index 2, while myArray.length = 3, the number of elements in the array.
Lines 8 and 11: once we get a random index in the correct range, we can return the corresponding color.
Functions drawAllBalls and moveAllBalls:

function drawAllBalls(ballArray) {
    ballArray.forEach(function(b) {
        drawFilledCircle(b);
    });
}
 
function moveAllBalls(ballArray) {
    // iterate on all balls in array
    ballArray.forEach(function(b) {
        // b is the current ball in the array
        b.x += b.speedX;
        b.y += b.speedY;
        testCollisionBallWithWalls(b);
    });
}
Explanations:

These two functions use an iterator on the array of balls (using the forEach method that looked the best fit here). The code inside the iterator is the same as in the previous example. We did not have to modify the testCollisionBallWithWalls code, for example.
-->
  
  <meta charset="utf-8">
  <title>Draw a monster in a canvas</title>
</head>
<body>
  <canvas id="myCanvas"  width="400" height="400"></canvas>
</body>
</html>