title: HTML5 Canvas | Bouncing Balls | Looping through an image array and placing different background images on each ball, centered
body: <p>I am having a bit of a nightmare applying different background images onto balls that bounce around in the canvas under the effect of gravity and the bounds of my canvas, eventually settling down and stacking at the bottom.</p>
  
  <p>I have created an image array, that I am trying to loop through and create a ball for each image, where the image becomes a centred background.</p>
  
  <p>I can centre the image, but this makes the balls appear to leave the bounds of my canvas. So have reverted that change.</p>
  
  <p>I am unable to get the background image to be different from the previous ball. Where the image shown on all balls is the last image in the array. However the number of balls created does reflect the number of images in the array.</p>
  
  <p>Here is a link to a codepen:
  <a href="https://codepen.io/jason-is-my-name/pen/BbNRXB" rel="nofollow noreferrer">https://codepen.io/jason-is-my-name/pen/BbNRXB</a></p>
  
  <pre><code>html, body{
      width:100%;
      height:100%;
      margin: 0;
      padding: 0;
      background: #333333;
  }
  *{
      margin: 0;
      padding: 0;
  }
      .container {
          width: 410px;
          height: 540px;
      }
      #ball-stage{
          width: 100%;
          height: 100%;
      }
  
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"&gt;&lt;/script&gt;
  
  &lt;div class="container"&gt;
      &lt;canvas id="ball-stage" &gt;&lt;/canvas&gt;
  &lt;/div&gt;
  
  &lt;script&gt;
      /*
      /*
       * Created by frontside.com.au
       * Amended by Jason
      */
  
      $(document).ready(function () {
          $.ajaxSetup({
              cache: true
          });
          var url1 = "https://code.createjs.com/easeljs-0.6.0.min.js";
          $.getScript(url1, function () {
              new App();
          })
      });
  
      function App() {
  
          var self = this;
          self.running = false;
          self.initialized = false;
          var stageClicked = false;
          var stage, canvas;
  
          var canvasWidth = 410;
          var canvasHeight = 540;
          var bounce = -0.75;
          var balls = [];
          var _gravityY = 1;
          var _gravityX = 0;
          var FPS = 30;
          var infoText, detailsText;
          var ballsInitalized = false;
          var iOS = navigator.userAgent.match(/(iPod|iPhone|iPad)/);
  
          self.initialize = function () {
              toggleListeners(true);
              self.initCanvas();
              self.initGame();
          };
  
          var toggleListeners = function (enable) {
              if (!enable) return;
          };
  
          self.refresh = function () {}
  
          self.initCanvas = function () {
              canvas = $("#ball-stage").get(0);
              stage = new createjs.Stage(canvas);
  
              window.addEventListener('resize', onStageResize, false);
              onStageResize();
              createjs.Touch.enable(stage);
              createjs.Ticker.addListener(tick);
              createjs.Ticker.setFPS(FPS);
  
              self.initialized = true;
          }
  
          self.initGame = function () {
              initBalls(canvasWidth, canvasHeight);
          }
  
          var onStageResize = function () {
              stage.canvas.width = canvasWidth;
              stage.canvas.height = canvasHeight;
          }
  
          var initBalls = function (stageX, stageY) {
  
              var imagesArray = ["img-1.png","img-2.png","img-3.png","img-4.png","img-5.png","img-6.png","img-7.png","img-8.png"];
  
              for (var i = 0; i &lt; imagesArray.length; i++) {
                  console.log(i);
  
                  var imageArray = imagesArray[i];
                  console.log(imageArray);
  
                  setTimeout(function () {
  
                      var arrayImage = new Image();
                      console.log(arrayImage);
  
                      arrayImage.onload = function(){
  
                          addBall(arrayImage, stageX / 2, 0);
  
                      }
  
                      arrayImage.src = imageArray;
  
                  }, i * 1000);
  
              }
          }
  
          var addBall = function (img, x, y) {
              console.log(img);
              var shape = new createjs.Shape();
              shape.id = balls.length;
              shape.radius = 51.25;
              shape.mass = shape.radius;
              shape.x = x;
              shape.y = y;
              shape.vx = rand(-3, 3);
              shape.vy = rand(-3, 3);
  
              var image = new Image();
              image.src = img;
              shape.graphics.beginBitmapFill(img,'repeat').drawCircle(0, 0, shape.radius);
  
              stage.addChild(shape);
              balls.push(shape);
          }
  
          var numBalls = function () {
              return balls.length;
          }
          var tick = function () {
              balls.forEach(move);
              for (var ballA, i = 0, len = numBalls() - 1; i &lt; len; i++) {
                  ballA = balls[i];
                  for (var ballB, j = i + 1; j &lt; numBalls(); j++) {
                      ballB = balls[j];
                      checkCollision(ballA, ballB);
                  }
              }
  
              stage.update();
          }
  
          var rotate = function (x, y, sin, cos, reverse) {
              return {
                  x: (reverse) ? (x * cos + y * sin) : (x * cos - y * sin),
                  y: (reverse) ? (y * cos - x * sin) : (y * cos + x * sin)
              };
          }
  
          var checkCollision = function (ball0, ball1) {
              var dx = ball1.x - ball0.x,
                  dy = ball1.y - ball0.y,
                  dist = Math.sqrt(dx * dx + dy * dy);
              //collision handling code here
              if (dist &lt; ball0.radius + ball1.radius) {
                  //calculate angle, sine, and cosine
                  var angle = Math.atan2(dy, dx),
                      sin = Math.sin(angle),
                      cos = Math.cos(angle),
                      //rotate ball0's position
                      pos0 = {
                          x: 0,
                          y: 0
                      }, //point
                      //rotate ball1's position
                      pos1 = rotate(dx, dy, sin, cos, true),
                      //rotate ball0's velocity
                      vel0 = rotate(ball0.vx, ball0.vy, sin, cos, true),
                      //rotate ball1's velocity
                      vel1 = rotate(ball1.vx, ball1.vy, sin, cos, true),
                      //collision reaction
                      vxTotal = vel0.x - vel1.x;
                  vel0.x = ((ball0.mass - ball1.mass) * vel0.x + 2 * ball1.mass * vel1.x) /
                      (ball0.mass + ball1.mass);
                  vel1.x = vxTotal + vel0.x;
                  //update position - to avoid objects becoming stuck together
                  var absV = Math.abs(vel0.x) + Math.abs(vel1.x),
                      overlap = (ball0.radius + ball1.radius) - Math.abs(pos0.x - pos1.x);
                  pos0.x += vel0.x / absV * overlap;
                  pos1.x += vel1.x / absV * overlap;
                  //rotate positions back
                  var pos0F = rotate(pos0.x, pos0.y, sin, cos, false),
                      pos1F = rotate(pos1.x, pos1.y, sin, cos, false);
                  //adjust positions to actual screen positions
                  // ball1.x = ball0.x + pos1F.x;
                  setBallX(ball1, ball0.x + pos1F.x)
                  //ball1.y = ball0.y + pos1F.y;
                  setBallY(ball1, ball0.y + pos1F.y)
                  // ball0.x = ball0.x + pos0F.x;
                  setBallX(ball0, ball0.x + pos0F.x)
                  // ball0.y = ball0.y + pos0F.y;
                  setBallY(ball0, ball0.y + pos0F.y)
                  //rotate velocities back
                  var vel0F = rotate(vel0.x, vel0.y, sin, cos, false),
                      vel1F = rotate(vel1.x, vel1.y, sin, cos, false);
                  ball0.vx = vel0F.x;
                  ball0.vy = vel0F.y;
                  ball1.vx = vel1F.x;
                  ball1.vy = vel1F.y;
              }
          }
  
          var checkWalls = function (ball) {
              if (ball.x + ball.radius &gt; canvas.width) {
                  //  ball.x = canvas.width - ball.radius;
                  setBallX(ball, canvas.width - ball.radius)
                  ball.vx *= bounce;
              } else
              if (ball.x - ball.radius &lt; 0) {
                  // ball.x = ball.radius;
                  setBallX(ball, ball.radius)
                  ball.vx *= bounce;
              }
              if (ball.y + ball.radius &gt; canvas.height) {
                  //  ball.y = canvas.height - ball.radius;
                  setBallY(ball, canvas.height - ball.radius)
                  ball.vy *= bounce;
              } else
              if (ball.y - ball.radius &lt; 0) {
                  //ball.y = ball.radius;
                  setBallY(ball, ball.radius)
                  ball.vy *= bounce;
              }
          }
  
          var move = function (ball) {
              ball.vy += _gravityY;
              ball.vx += _gravityX;
              setBallX(ball, ball.x + ball.vx)
              setBallY(ball, ball.y + ball.vy)
              checkWalls(ball);
          }
          var setBallX = function (ball, x) {
              if (isNaN(ball.pointerID)) {
                  ball.x = x
              }
          }
          var setBallY = function (ball, y) {
              if (isNaN(ball.pointerID)) {
                  ball.y = y
              }
          }
  
          var rand = function (min, max) {
              return Math.random() * (max - min) + min;
              return (Math.random() * max) + min;
          }
  
          self.initialize();
          return self;
      }
  
      window.log = function f() {
          log.history = log.history || [];
          log.history.push(arguments);
          if (this.console) {
              var args = arguments,
                  newarr;
              args.callee = args.callee.caller;
              newarr = [].slice.call(args);
  
              if (typeof console.log === 'object') log.apply.call(console.log, console, newarr);
              else console.log.apply(console, newarr);
          }
      };
      (function (a) {
          function b() {}
  
          for (var c = "assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","), d; !!(d = c.pop());) {
              a[d] = a[d] || b;
          }
      })
  
      (function () {
          try {
              console.log();
              return window.console;
          } catch (a) {
              return (window.console = {});
          }
      }());
  &lt;/script&gt;
  </code></pre>
  
  <p>I have been trapped at this point in the code for about a week now and could really do with some genius' help!</p>
  
  <p>Aims:</p>
  
  <ul>
  <li><p>Add balls equivalent to the length of the image array.</p></li>
  <li><p>Each ball with have its respective image as a centred background.</p></li>
  <li><p>The balls will not leave the bounds of the canvas.</p></li>
  </ul>
  
  <p>Relevant code:</p>
  
  <ul>
  <li><p>initBalls()</p></li>
  <li><p>addBall()</p></li>
  </ul>
  
  <p>Thanks, Jason.</p>