DEV Community

Brian Montana
Brian Montana

Posted on

Canvas 101: Multiple Shapes and Resets

This tutorial will build off the previous post I made; Canvas 101: Rotating Shape, focusing on manipulating an array populated with objects created from a class.

The last tutorial we used the Square class to build an object that was updated over time with the requestAnimationFramemethod. Now we'll create multiple Square instances, animate them across the canvas, and reset their position when they are completely off the screen.

To begin let's fork this pen to start:

First we will update the Square class with xVelocity in the deconstructed object of the constructor. We'll use this to move our square across the canvas, and rotate it as it moves. Setting a default value 0.1, or another similar smaller value, in the constructor we'll set the xVelocity to a random value using its default value as the minimum and 1 as the maximum random value for xVelocity.

this.xVelocity = Math.random() * (1 - xVelocity) + xVelocity;

Now let's check out the movement function, right now we're incrementing the value by 0.1, but with the randomly generated xVelocity we can increment it by the xVelocity value over time. Every time you refresh you'll see a different speed. The square will continue to move off the canvas but we can include a check for the current position of the square and reset it to the left side of the canvas using this check shape.xPosition > canvasWidth + shape.width. While doing this we'll want to set the new position to -shape.width, placing it just outside the canvas, so it moves into the canvas instead of appearing on the edge. Here's the final update for the movement function.

function movement(shape) {
  if(shape.xPosition > canvasWidth + shape.width) {
    shape.xPosition = -shape.width;
  }
  shape.rotate += shape.xVelocity / 15;
  shape.xPosition += shape.xVelocity;
}

Awesome! We're seeing the Square instance being animated and rendered across the canvas! Now we can setup an array and create multiple instances of Square. Create an array at the top const squares = []; and a value for the total count let squareCount = 50; Now we have an array to push generated instances of Square, while randomizing it's xPosition, and yPosition. The randomizing will use the same minimum and maximum threshold constraints in xVelocity, we can think of it like this Math.random() * (max - min) + min. To finalize it we'll use a for loop to populate our squares array with the limit of squareCount.

for (let i = 0; i < squareCount; i++) {
  squares.push(
    new Square({
      width: 40,
      height: 40,
      xPosition:
        Math.random() * (canvasWidth * 0.9 - canvasWidth * 0.1) +
        canvasWidth * 0.1,
      yPosition:
        Math.random() * (canvasHeight * 0.9 - canvasHeight * 0.1) +
        canvasHeight * 0.1
    })
  );
}

Since the squares array is populated we'll need to update the render function to determine the updated values for each Square instance in the squares array. Let's use the forEach method provided by the Array object to update each element's values with the movement function, then drawing the results on the canvas. Each Square instance will draw on top of the last one, so the last element in the array will be drawn on top of all the previous elements.

function render() {
  context.fillStyle = "lightsalmon";
  context.fillRect(0, 0, canvasWidth, canvasHeight);
  squares.forEach(square => {
    movement(square);
    context.save();
    context.fillStyle = "salmon";
    context.translate(square.xPosition, square.yPosition);
    context.rotate(square.rotate);
    context.fillRect(
      -square.width / 2,
      -square.height / 2,
      square.width,
      square.height
    );
    context.restore();
  });
  window.requestAnimationFrame(render);
}

That should be it! Now all the squares will animate across the canvas and reset their position when they go off screen. See the results in the pen below :D

Top comments (0)