How to make a JavaScript game

JavaScript offers a plethora of exciting possibilities, including the development of games. Indeed, in addition to enhancing the visual appeal of our websites, we can leverage JavaScript to design various types of games.

Now, let’s explore the process of developing a game utilizing HTML and JavaScript.

In order to develop the game, we will utilize the HTML Canvas. Therefore, it is essential to first grasp the concept of HTML Canvas.

HTML Canvas

<Canvas> represents one of the numerous categories of HTML elements. Essentially, it is employed for rendering graphics dynamically through scripting languages, primarily JavaScript. This element serves as a graphics container, facilitating the drawing of actual graphics within it, necessitating the use of a scripting language like JavaScript. A wide array of methods and functions is available, which can be utilized to create paths and various shapes, including circles, rectangles, and more, in addition to incorporating images.

Canvas elements can be used for many other things. Some of them are given below:

  • It can be used to draw text.
  • It can be used to draw graphics.
  • It can be used to move the graphics like bounce a boll, to animate anything else.
  • It can provide interaction; for example, it can respond to several kinds of JavaScript events.

Let’s explore the process of creating a canvas through a practical example:

Syntax for creating Canvas

Example

<canvas id="myfirstCanvas" width="100" height="50"></canvas>

Example

Example

<!DOCTYPE html>

<html>

<body>



<canvas id="myfirstCanvas" width="400" height="200"

style="border:4px solid #000000;"> 

<!--anvas element does not contain any border, so to add border we can use style tag.-->

</canvas>

</body>

</html>

Output

We have established the gaming environment utilizing the canvas element. This approach is particularly effective for building HTML and JavaScript gaming applications, as it offers nearly all the necessary features needed for game development.

.getContext("2d")

This refers to a native object associated with the <canvas> element, specifically the getContext("2d") object. It encompasses all the necessary methods, functions, and properties essential for rendering graphics in <canvas>.

Let’s commence our game development journey by establishing a playable area and setting up for rendering graphics.

Step 1: Gaming area

In order to establish the gaming space, we will utilize the Canvas element, as previously mentioned.

Program

Example

<!DOCTYPE html>

<html>

<head>

<style>

canvas {

    border: 1px solid #d3d3d3;

    background-color: #f1f1f1;

}

</style>

</head>

<body onload="startGame()">

<script>



function startGame() {

    myGameArea.start();

}



var  myGameArea = {

    canvas : document.createElement("canvas"),

    start : function() {

        this.canvas.width = 480;

        this.canvas.height = 270;

        this.context = this.canvas.getContext("2d");

        document.body.insertBefore(this.canvas, document.body.childNodes[0]);

    }

}



</script>



<p>This is our gaming area</p>



</body>

</html>

Explanation of the given program

In the preceding program, we have defined a function named "startGame;" where we subsequently call the start method associated with the mygameArea object. This "start" method is responsible for generating a canvas and adding it to the body element as its first child node.

Output

Step 2: Game Component

In this phase, we will create a component utilizing a constructor, which will enable us to incorporate that component into our gaming environment.

The object constructor is referred to as "component," and we will create our initial component, which will be named "mygamecomponent:"

Let's explore the process of developing a game component by utilizing the following example:

Example

<!DOCTYPE html>

<html>

<head>

<style>

canvas {

    border:1px solid #d3d3d3;

    background-color: #f1f1f1;

}

</style>

</head>

<body onload="startGame()">

<script>



var myGameComponent;



function startGame() {

    myGameArea.start();

    myGameComponent = new component(30, 20, "blue", 20, 120);

}



var myGameArea = {

    canvas : document.createElement("canvas"),

    start : function() {

        this.canvas.width = 480;

        this.canvas.height = 270;

        this.context = this.canvas.getContext("2d");

        document.body.insertBefore(this.canvas, document.body.childNodes[0]);

    }

}



function component(width, height, color, a, b) {

    this.width = width;

    this.height = height;

    this.a = a;

    this.b = b;    

    ctx = myGameArea.context;

    ctx.fillStyle = color;

    ctx.fillRect(this.a, this.b, this.width, this.height);

}



</script>



<p>As you can see above we have added a component to our game, a blue rectangle!</p>



</body>

</html>

Explanation of program

In the preceding program, we instantiated an object called "mygameComponent" within the "myGamestart;" function to develop our game component.

Output

Step 3: Frames

In order to enhance the vibrancy of our game and prepare it for dynamic action, we need to update the gaming environment at a frequency of 50 frames per second. For instance, films typically operate with a minimum refresh rate of 60 frames per second.

To begin with, we need to define a function named "updateMyGame." Within this function's object, we will implement a time interval that triggers the function updateMyGame; every 20 milliseconds, translating to a frequency of 50 executions per second. Additionally, we must incorporate a function labeled clear that will be responsible for clearing the entire gaming area, also referred to as the complete canvas.

Within the "component" constructor, we will invoke a method designated for managing the rendering of the component, referred to as the "Update" function.

The function UpdateMyGame; invokes both the clear; and update; methods.

As a consequence of all the aforementioned efforts, our game element is rendered onto the canvas and refreshed at a frequency of 50 frames per second.

This can be illustrated through the subsequent example:

Program

Example

<!DOCTYPE html>

<html>

<head>

<style>

canvas {

    border:1px solid #d3d3d3;

    background-color: #f1f1f1;

}

</style>

</head>

<body onload="startGame()">

<script>



var myGameComponent;



function startGame() {

    myGameArea.start();

    myGameComponent = new component(30, 20, "blue", 20, 120);

}



var myGameArea = {

    canvas : document.createElement("canvas"),

    start : function() {

        this.canvas.width = 480;

        this.canvas.height = 270;

        this.context = this.canvas.getContext("2d");

        document.body.insertBefore(this.canvas, document.body.childNodes[0]);

    this.interval = setInterval(updateGameArea, 20);

    },

    clear : function() {

        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

    }

}



function component(width, height, color, a, b) {

    this.width = width;

    this.height = height;

    this.a = a;

    this.b = b;   

    this.update = function(){ 

    ctx = myGameArea.context;

    ctx.fillStyle = color;

    ctx.fillRect(this.a, this.b, this.width, this.height);

}

}



function updateGameArea() {

    myGameArea.clear();

    myGameComponent.update();

}

</script>



<p>The above game component, the blue rectangle actually getting drawn 50 times in a second</p>



</body>

</html>

Output

Step: 4 Adding Movement to component

To demonstrate that the blue rectangle is being rendered 50 times per second, we will modify the "a" position (on the horizontal axis) by 1 pixel each time the "updateGameArea" function is called.

Example

function updateGameArea() {

    myGameArea.clear();

    myGameComponent.a += 1

    myGameComponent.update();

}

Change the Position

The coordinates A and B can be utilized to modify the location or to place our game element within the gaming environment.

Example

function startGame() {

  myGameArea.start();

  myGameComponent= new component(30, 30, "red", 2, 2);

Step 5: Creating Controls buttons

A game requires controls in order to facilitate gameplay or to manage its components effectively.

In this section, we will develop two control buttons that will manage the movement of our rectangular box. To achieve this, we will need to implement multiple functions corresponding to each button.

In the constructor of the component, we need to establish two new properties, which we will refer to as speed A and speed B. These properties will serve as indicators for speed.

Additionally, we need to introduce a new method named "newPos;" within the component's constructor. This method will utilize the properties speedA and speedB to relocate the component from its current position to a different location within the game area or canvas. The "newPos;" function will be invoked from within the "updatemygame;" function, specifically right before the component is rendered.

Example

Example

<!DOCTYPE html>

<html>

<head>

<style>

canvas {

    border:1px solid #d3d3d3;

    background-color: #f1f1f1;

}

</style>

</head>

<body onload="startGame()">

<script>



var myGameComponent;



function startGame() {

    myGameArea.start();

    myGameComponent = new component(30, 20, "blue", 20, 120);

}



var myGameArea = {

    canvas : document.createElement("canvas"),

    start : function() {

        this.canvas.width = 480;

        this.canvas.height = 270;

        this.context = this.canvas.getContext("2d");

        document.body.insertBefore(this.canvas, document.body.childNodes[0]);

    this.interval = setInterval(updateGameArea, 20);

    },

    clear : function() {

        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

    }

}



function component(width, height, color, a, b) {

    this.width = width;

    this.height = height;

    this.speedA = 0;

    this.speedB = 0;

    this.a = a;

    this.b = b;   

    this.update = function(){ 

    ctx = myGameArea.context;

    ctx.fillStyle = color;

    ctx.fillRect(this.a, this.b, this.width, this.height);

}

this.newPos = function() {

        this.a += this.speedA;

        this.b += this.speedB;        

    }  

}



function updateGameArea() {

    myGameArea.clear();

    myGameComponent.newPos();

    myGameComponent.update();

}

    

    function moveup() {

    myGameComponent.speedB -= 1; 

}



function movedown() {

    myGameComponent.speedB += 1; 

}



</script>

<div style="text-align:center;width:480px;">

  <button onclick="moveup()">UP</button><br>

  <button onclick="movedown()">DOWN</button>

</div>



</body>

</html>

Output

Step 6: Creating some obstacles

It is widely understood that a game lacks substance if it does not incorporate challenges or obstacles.

Let's explore the process of generating obstacles by developing a new component and integrating it into the gaming environment.

Example:

Example

var myGamecomponent;

var myfirstObstacle;



function startGame() {

  myGamecomponent = new component(30, 30, "red", 10, 120);

  myfirstObstacle = new component(50, 200, "red", 300, 120);

  myGameArea.start();

}



function updateGameArea() {

  myGameArea.clear();

  myfirstObstacle.update();

  myGamecomponent.newPos();

  myGamecomponent.update();

}

By utilizing the method outlined previously in the program, we have the capability to generate an unlimited number of constraints or obstacles according to our requirements.

Note: it is also essential to update all components (or obstacles) in every frame.

Output

Providing the movement to the obstacles

In the context of gaming, if there are barriers present, the experience can become uninteresting if those barriers remain fixed in place.

In order to enable movement for our obstacles, it is essential to modify the "myfirstObstacle.x" property during each update cycle.

Example:

Example

<!DOCTYPE html>

<html>

<head>

<style>

canvas {

    border:1px solid #d3d3d3;

    background-color: #f1f1f1;

}

</style>

</head>

<body onload="startGame()">

<script>

var myfirstObstacle;

var myGameComponent;



function startGame() {

    myGameArea.start();

    myGameComponent = new component(30, 20, "blue", 20, 120);

      myfirstObstacle = new component(50, 200, "red", 300, 120);

}



var myGameArea = {

    canvas : document.createElement("canvas"),

    start : function() {

        this.canvas.width = 480;

        this.canvas.height = 270;

        this.context = this.canvas.getContext("2d");

        document.body.insertBefore(this.canvas, document.body.childNodes[0]);

    this.interval = setInterval(updateGameArea, 20);

    },

    clear : function() {

        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

    }

}



function component(width, height, color, a, b) {

    this.width = width;

    this.height = height;

    this.speedA = 0;

    this.speedB = 0;

    this.a = a;

    this.b = b;   

    this.update = function(){ 

    ctx = myGameArea.context;

    ctx.fillStyle = color;

    ctx.fillRect(this.a, this.b, this.width, this.height);

}

this.newPos = function() {

        this.a += this.speedA;

        this.b += this.speedB;        

    }  

}



function updateGameArea() {

    myGameArea.clear();

    myfirstObstacle.update();

    myfirstObstacle.a += -1;

    myGameComponent.newPos();

    myGameComponent.update();

}

    

    function moveup() {

    myGameComponent.speedB -= 1; 

}



function movedown() {

    myGameComponent.speedB += 1; 

}



</script>

<div style="text-align:center;width:480px;">

  <button onclick="moveup()">UP</button><br>

  <button onclick="movedown()">DOWN</button>

</div>

<p>The above game component, the blue rectangle actually  geting drawn 50 times in a second</p>



</body>

</html>

What if you hit with the obstacle

It is commonly understood that in any gaming experience, if a player encounters an obstacle, the game concludes.

To achieve this, we must implement a new method within the constructor of the component that will detect collisions between our blue box and other constraints (or any other components) right from the game's onset. This method needs to be invoked continuously with each frame update (essentially, it should be called 50 times per second). Additionally, we will need to incorporate the stop; method into the mygamearea object, which will terminate the 20-millisecond interval.

Program

Example

<!DOCTYPE html>

<html>

<head>

<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

<style>

canvas {

    border:1px solid #d3d3d3;

    background-color: #f1f1f1;

}

</style>

</head>

<body onload="startGame()">

<script>



var myGamecomponent1;

var Obstacle;



function startGame() {

    myGamecomponent1 = new component(30, 30, "blue", 10, 120);

    Obstacle  = new component(30, 200, "red", 300, 120);    

    myGameArea.start();

}



var myGameArea = {

    canvas : document.createElement("canvas"),

    start : function() {

        this.canvas.width = 480;

        this.canvas.height = 270;

        this.context = this.canvas.getContext("2d");

        document.body.insertBefore(this.canvas, document.body.childNodes[0]);

        this.frameNo = 0;

        this.interval = setInterval(updateGameArea, 20);



    },

    clear : function() {

        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

    },

    stop : function() {

        clearInterval(this.interval);

    }

}



function component(width, height, color, x, y) {

    this.width = width;

    this.height = height;

    this.speedX = 0;

    this.speedY = 0;    

    this.x = x;

    this.y = y;    

    this.update = function() {

        ctx = myGameArea.context;

        ctx.fillStyle = color;

        ctx.fillRect(this.x, this.y, this.width, this.height);

    }

    this.crashWith = function(otherobj) {

        var myleft = this.x;

        var myright = this.x + (this.width);

        var mytop = this.y;

        var mybottom = this.y + (this.height);

        var otherleft = otherobj.x;

        var otherright = otherobj.x + (otherobj.width);

        var othertop = otherobj.y;

        var otherbottom = otherobj.y + (otherobj.height);

        var crash = true;

        if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {

            crash = false;

        }

        return crash;

    }

}



function updateGameArea() {

    if (myGamecomponent1.crashWith(Obstacle)) {

        myGameArea.stop();

    } else {

        myGameArea.clear();

        Obstacle.x += -1;

        Obstacle.update();

        myGamecomponent1.x += myGamecomponent1.speedX;

        myGamecomponent1.y += myGamecomponent1.speedY;    

        myGamecomponent1.update();

    }

}



function moveup() {

    myGamecomponent1.speedY = -1; 

}



function movedown() {

    myGamecomponent1.speedY = 1; 

}







function clearmove() {

    myGamecomponent1.speedX = 0; 

    myGamecomponent1.speedY = 0; 

}

</script>

<div style="text-align:center;width:480px;">

  <button onmousedown="moveup()" onmouseup="clearmove()" ontouchstart="moveup()">UP</button><br><br>

  <button onmousedown="movedown()" onmouseup="clearmove()" ontouchstart="movedown()">DOWN</button>

</div>

<p>When the blue box touches the obstacle,the game will stop.</p>

</body>

</html>

Output

Creating the obstacles of random size

To enhance the challenge and excitement of our game, we should incorporate obstacles of varying sizes at random positions. This will require the player to maneuver the blue box consistently in diverse directions to steer clear of these obstacles.

Program

Example

<!DOCTYPE html>

<html>

<head>

<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

<style>

canvas {

    border:1px solid #d3d3d3;

    background-color: #f1f1f1;

}

</style>

</head>

<body onload="startGame()">

<script>



var myGamecomponents;

var myObstacles = [];



function startGame() {

    myGamecomponents = new component(50, 30, "blue", 20, 120);

    myGameArea.start();

}



var myGameArea = {

    canvas : document.createElement("canvas"),

    start : function() {

        this.canvas.width = 480;

        this.canvas.height = 270;

        this.context = this.canvas.getContext("2d");

        document.body.insertBefore(this.canvas, document.body.childNodes[0]);

        this.frameNo = 0;

        this.interval = setInterval(updateGameArea, 20);

        },

    clear : function() {

        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

    },

    stop : function() {

        clearInterval(this.interval);

    }    

}



function component(width, height, color, a, b) {

    this.width = width;

    this.height = height;

    this.speedA = 0;

    this.speedB = 0;    

    this.a = a;

    this.b = b;    

    this.update = function() {

        ctx = myGameArea.context;

        ctx.fillStyle = color;

        ctx.fillRect(this.a, this.b, this.width, this.height);

    }

    this.newPos = function() {

        this.a += this.speedA;

        this.b += this.speedB;        

    }    

    this.crashWith = function(otherobj) {

        var myleft = this.a;

        var myright = this.a + (this.width);

        var mytop = this.b;

        var mybottom = this.b + (this.height);

        var otherleft = otherobj.a;

        var otherright = otherobj.a + (otherobj.width);

        var othertop = otherobj.b;

        var otherbottom = otherobj.b + (otherobj.height);

        var crash = true;

        if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {

            crash = false;

        }

        return crash;

    }

}



function updateGameArea() {

    var a, height, gap, minHeight, maxHeight, minGap, maxGap;

    for (i = 0; i < myObstacles.length; i += 1) {

        if (myGamecomponents.crashWith(myObstacles[i])) {

            myGameArea.stop();

            return;

        } 

    }

    myGameArea.clear();

    myGameArea.frameNo += 1;

    if (myGameArea.frameNo == 1 || everyinterval(150)) {

        a = myGameArea.canvas.width;

        minHeight = 20;

        maxHeight = 200;

        height = Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight);

        minGap = 50;

        maxGap = 200;

        gap = Math.floor(Math.random()*(maxGap-minGap+1)+minGap);

        myObstacles.push(new component(30, height, "black", a, 0));

        myObstacles.push(new component(20, a - height - gap, "red", a, height + gap));

    }

    for (i = 0; i < myObstacles.length; i += 1) {

        myObstacles[i].a += -1;

        myObstacles[i].update();

    }

    myGamecomponents.newPos();    

    myGamecomponents.update();

}



function everyinterval(n) {

    if ((myGameArea.frameNo / n) % 1 == 0) {return true;}

    return false;

}



function moveup() {

    myGamecomponents.speedB = -1; 

}



function movedown() {

    myGamecomponents.speedB = 1; 

}







function clearmove() {

    myGamecomponents.speedA = 0; 

    myGamecomponents.speedB = 0; 

}

</script>

<div style="text-align:center;width:480px;">

  <button onmousedown="moveup()" onmouseup="clearmove()" ontouchstart="moveup()">UP</button><br><br>

  <button onmousedown="movedown()" onmouseup="clearmove()" ontouchstart="movedown()">DOWN</button> <br>  

</div>

<p>Our game almost completed, but there is one important feature is left that is Score</p>

</body>

</html>

Output

Step 7: Displaying User Score

There are various approaches to show the user's score; however, to maintain simplicity in this game, we will opt for one of the most straightforward methods available.

In this approach, it is essential to first establish a new variable, such as "userscore," and additionally, we must develop a separate component dedicated to showcasing the user score.

It is widely recognized that inscribing text on a canvas differs significantly from the process of rendering or drawing a rectangular box on the same canvas. Therefore, it becomes essential to call the constructor of the component with an extra parameter that indicates the specific type of component being created; in this scenario, the type is designated as "text."

Within the constructor of the component, we will evaluate the type of the component, for instance, determining whether it is of the type "text." After verifying the component's type, we will proceed to utilize the "fillText" method.

At last, we will utilize the FrameNo property to tally the score. To achieve this, it is necessary to adjust certain portions of the "updateGameArea;" function that will employ the FrameNo property and display the score on the canvas.

Program

Example

<!DOCTYPE html>

<html>

<head>

<style>

canvas {

    border:1px solid #d3d3d3;

    background-color: #f1f1f1;

}

</style>

</head>

<body onload="startGame()">

<script>



var myGamecomponents;

var myObstacles = [];

var UserScore;



function startGame() {

    myGamecomponents = new component(50, 30, "blue", 20, 120);

      UserScore = new component("30px", "Consolas", "black", 280, 30, "text");

    myGameArea.start();

}



var myGameArea = {

    canvas : document.createElement("canvas"),

    start : function() {

        this.canvas.width = 480;

        this.canvas.height = 270;

        this.context = this.canvas.getContext("2d");

        document.body.insertBefore(this.canvas, document.body.childNodes[0]);

        this.frameNo = 0;

        this.interval = setInterval(updateGameArea, 20);

        },

    clear : function() {

        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

    },

    stop : function() {

        clearInterval(this.interval);

    }    

}



function component(width, height, color, a, b, type) {

    this.type = type;

    this.width = width;

    this.height = height;

    this.speedA = 0;

    this.speedB = 0;    

    this.a = a;

    this.b = b;    

    this.update = function() {

        ctx = myGameArea.context;

        if (this.type == "text") {

      ctx.font = this.width + " " + this.height;

      ctx.fillStyle = color;

      ctx.fillText(this.text, this.a, this.b);

    } else {

        ctx.fillStyle = color;

        ctx.fillRect(this.a, this.b, this.width, this.height);

    }

}

    this.newPos = function() {

        this.a += this.speedA;

        this.b += this.speedB;        

    }    

    this.crashWith = function(otherobj) {

        var myleft = this.a;

        var myright = this.a + (this.width);

        var mytop = this.b;

        var mybottom = this.b + (this.height);

        var otherleft = otherobj.a;

        var otherright = otherobj.a + (otherobj.width);

        var othertop = otherobj.b;

        var otherbottom = otherobj.b + (otherobj.height);

        var crash = true;

        if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {

            crash = false;

        }

        return crash;

    }

}



function updateGameArea() {

    var a, height, gap, minHeight, maxHeight, minGap, maxGap;

    for (i = 0; i < myObstacles.length; i += 1) {

        if (myGamecomponents.crashWith(myObstacles[i])) {

            myGameArea.stop();

            return;

        } 

    }

    myGameArea.clear();

    myGameArea.frameNo += 1;

    if (myGameArea.frameNo == 1 || everyinterval(150)) {

        a = myGameArea.canvas.width;

        minHeight = 20;

        maxHeight = 200;

        height = Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight);

        minGap = 50;

        maxGap = 200;

        gap = Math.floor(Math.random()*(maxGap-minGap+1)+minGap);

        myObstacles.push(new component(20, height, "black", a, 0));

        myObstacles.push(new component(30, a - height - gap, "red", a, height + gap));

    }

    for (i = 0; i < myObstacles.length; i += 1) {

        myObstacles[i].a += -1;

        myObstacles[i].newPos();

        myObstacles[i].update();

                          }

               UserScore.text = "SCORE: " + myGameArea.frameNo;

                 UserScore.update();

    myGamecomponents.newPos();    

    myGamecomponents.update();

}



function everyinterval(n) {

    if ((myGameArea.frameNo / n) % 1 == 0) {return true;}

    return false;

}



function moveup() {

    myGamecomponents.speedB = -1; 

}



function movedown() {

    myGamecomponents.speedB = 1; 

}

function clearmove() {

    myGamecomponents.speedA = 0; 

    myGamecomponents.speedB = 0; 

}

</script>

<div style="text-align:center;width:480px;">

  <button onmousedown="moveup()" onmouseup="clearmove()" ontouchstart="moveup()">UP</button><br><br>

  <button onmousedown="movedown()" onmouseup="clearmove()" ontouchstart="movedown()">DOWN</button> <br>  

</div>

<p>Our  game completed</p>



</body>

</html>

Output

Note: You can also add many other features to this game to make it more attractive. For example, background images, sound effects, etc.

Input Required

This code uses input(). Please provide values below: