Water drop

Today I would like to share a project on how to add gravity to canvas using JavaScript.
When it comes to game development, gravity and player movement are among some of the most important concepts. Today we will be looking at how to add gravity to circular (arc) objects in JavaScript.

HTML Skeleton

First, let’s start with the HTML skeleton needed for this project. You can use the template below as the skeleton:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Gravity Practice</title>
    <style>
        body{
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
    <canvas></canvas>
    <script src="script.js"></script>
</body>
</html>

In the above template, we added metadata for the viewport to ensure that the document can easily resize according to the user’s device.
At the head of the document, we added its title and basic CSS to prevent unwanted paddings and margins.

The &lt; canvas &gt; element and a &lt; script &gt; element with the link to the JavaScript file we will require are added to the document’s body.
Create a “script.js” file and open it in any of your favorite editors.
We’re all set to code now!

JavaScript

First and foremost, we add an onload function to ensure all the HTML loads before executing the code.

window.onload = () =>{
    
}

Next, we need to get the canvas element from the HTML document and give it all the necessary functions required to manipulate the canvas.

let canvas = document.querySelector("canvas");//Gets canvas element
let ctx = canvas.getContext("2d"); //Adds context to the canvas element

Next, we can use the code below to set the canvas’s height and width to that of the user’s device.

canvas.width = innerWidth; //Sets canvas width to screen width
canvas.height = innerHeight; //Sets canvas height to screen height

The above code gets the width and height of the screen and assigns it to the canvas’s width and height.

Before we can control and impart gravity to objects, we must first add them to the canvas.

It is generally good practice to create a class to define all the parameters and functions of the object.

For this project, we want to make simple circles. Our parameters are the x position, y position, radius, starting angle, and ending angle. We also want to add color (For visual appeal) and friction (For realistic gravity) to the circle.

Use the code below to create a class containing all the parameters:

class Circle{
        constructor(x,y,r, dy, friction, color){
            this.x = x;
            this.y = y; 
            this.r = r;
            this.dy = dy;
            this.friction = friction;
            this.color = color;
        }
}

Above, we created the class and added a constructor to allow several instances.

Drawing The Object

Now we need to add a function to draw the circle.

draw(){
            ctx.beginPath(); //Starting an independent path
            ctx.fillStyle = this.color; //Setting the color of the circle
            ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2); //Drawing the circle
            ctx.fill(); //Displaying the circle
            ctx.closePath(); //Closing its path
        }

The above code might seem intimidating, but it is relatively simple. 

  • First, we need to start a new path for our object. That prevents it from being attached to any other object already in the canvas (if there are any). 
  • Then we set the color of our object. 
  • Then we define the coordinates, radius, and angles of our object.
  • Finally, we draw it and close its path. 

Note The x and y coordinates work a little differently than what you may expect. Use the images below for added guidance.

Canvas coordinates system
Usual mathematical coordinate system

Adding Gravity to the Object

To emulate gravity, we need to make the object move downwards with accelerating speed and lose energy every time it touches the floor (Bottom of the canvas).

Let’s construct a method in the circle class that makes the object drop down all the time and lose energy when it touches the ground.

move(){
            this.draw(); //Draw the object in its current position
            if (this.y >= canvas.height - this.r){ //Check if the object is on the canvas floor.
                this.dy *= -1 * this.friction; //Reverse the movement and reduce its energy.
            }
            else{
                this.dy+=1; //Move down.
            }
            this.y += this.dy;
        }

The above code checks if the object is in or below the canvas. If it is in the canvas, we decrease the value of its y position, making it move down. If it is below the canvas, we reverse the value of y, making it move up.

That is all we need to do for the class. Next, we will create several instances of it and animate the objects.

Creating Instances of the Class

We will be using variables and an array to make several circles and animate their movement.

let circles = []; //Creating an array to hold all the instances. 

Next, we will use a for loop to make many instances of the circle class that we will animate.

for (var i = 0; i < 100; i++){
        circles.push(new Circle(Math.random()*canvas.width, Math.random()*canvas.height, Math.floor(Math.random()*30), 1, 0.9, randomColor()));
        
    }

Above, we are using a for loop to create 100 instances of the circle class.

For the x and y parameters, we assign a random position inside of the canvas, for the radius we get a random number between 0 and 30, the y-velocity we set to 1, the friction we set to 0.9 (Friction should be any number between 0 and 1. The smaller the number the heavier the object), and the color we assign it to a function that generates random colors.

Generating Random Colors

Use the function below to create random colors.

function randomColor(){
        return `rgb(${Math.floor(Math.random()*256)}, ${Math.floor(Math.random()*256)}, ${Math.floor(Math.random()*256)})`;
    }

The function above returns a string containing a random RGB value.

Animating the Objects

Finally, the last step in our project will be to animate the objects and see the output.

function animate(){
        requestAnimationFrame(animate); //Calling the animate function several times.
        ctx.clearRect(0,0,canvas.width,canvas.height); //Deleting what was previously on the canvas.
        circles.forEach(circle => {
            circle.move(); Looping through the array and moving the circles.
        });
    
    }
animate(); //Calling the animate function.

And just like that, we have successfully emulated gravity on canvas! Cheers!

View the full source code on GitHub: https://github.com/edilson-z/Canvas-Gravity

View the final output: https://edilson-z.github.io/Canvas-Gravity/

Leave a Reply

Your email address will not be published.