DEV Community

Cover image for How To Make Car Game Using Vanilla JavaScript (Beginners)
Emmanuel C. Okolie
Emmanuel C. Okolie

Posted on

How To Make Car Game Using Vanilla JavaScript (Beginners)

Introduction

Growing up as a child, I've always wanted to make games. Especially the car game! I love car games, so as a developer I found out that you can be a beginner in Programming with little knowledge of some programming languages and be able to build a simple car game.

In this tutorial, we are going to see the step-by-step way, to make a car game using HTML, CSS, and JavaScript! And we will be precise.

Without wasting Your time, Let's Jump into this Guide!

Prerequisites

The prerequisites for making a car game using vanilla JavaScript are as follows:

  1. HTML & CSS: You need to know this base! cause it’s the view that people see and interact with. so before jumping on the guide, you should the basic programming languages HTML And CSS.
  2. Vanilla JavaScript: Here you need to know how to use plain JavaScript that doesn’t contain OOP.

Note: You should at least be conversant with functions using vanilla Js. Once you've met these requirements, you may go on to proceed and make your car using vanilla JavaScript:

Now you are good to go!


Step By Step On How To Make A Car Game

Step 1: Make An HTML Page
Now The first thing to do is this, have an index.html page.
Note: This is the first page to run when you load it on your browser. so in the index page, you’ll create links using the link tag <link> to link to other pages in the folder such as the style.css page, etc. The remaining code snippet will be the view, it contains classes and ID’s used for easy targeting of the CSS and JavaScript classes. The index.html has the following code snippet below.

  <!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="css/fontawesome/css/all.min.css">
    <link rel="stylesheet" href="css/style.css">
    <title>3D Car Drive!</title>
  </head>
  <body onload="done()">
    <div id="scoreDiv">
      <span id="score">0</span>
      <img src="https://image.ibb.co/jRAp0y/coin.png" id="cn">
    </div>
    <div class="gameHome" id="startPage">
      <div id="gameTitle">3D Car Drive!</div>
      <button onclick="ld()" id="playBtn">
          <span style="font-size:18px">Loading Assets<br>Please Wait...<br>This may take a few seconds for first time</span>
      </button><br>
      <div id="ldc"><div id="loading"></div></div>
      <p>Rotate your phone & tilt left/right or tap left/right side of screen to move the car<br>Use left/right arrow key on your PC</p>
    </div>

    <div id="mainContainer" style="background:#0f0" >
        <img id="city" src="https://image.ibb.co/jCGU0y/cty.jpg">
        <canvas id="myCanvas" style="/*background:#9de732*/" ></canvas>
    </div>
    <img class="aImg" id="t1" src="https://image.ibb.co/dZi5Ly/t1.png">
    <img class="aImg" id="t2" src="https://image.ibb.co/jajjDJ/t2.png">
    <img class="aImg" id="t3" src="https://image.ibb.co/it4jDJ/t5.png">
    <img class="aImg" id="t4" src="https://image.ibb.co/ksy0nd/t4.png">
    <img class="aImg" id="c1" src="https://image.ibb.co/f4v7YJ/c2.png">


    <script src="js/script.js"></script>

  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

After Running the HTML snippet what you’ll see in the view after refreshing your web browser would look like this!

HTML View From Emmykolic

So without wasting time the next thing is to write the CSS code for the HTML. After writing the CSS code, the above view won’t be seen until you’ve added the JavaScript!

Step 2: Make A CSS Page
Secondly, what you should do is create a page and call it style.css what this page does it’s responsible for the beautification of our Car Game. and it is the page that holds the ID’s and classes in the index.html, then it’s targeted in the style.css.
Below is the code snippet for the style.css

body{
    margin:0;
    height:100vh;
    width:100vw;
}

#mainContainer {
    position:absolute;
    top:0;
    left:0;
    transform-origin:0% 0%;
    width:100%;
    transform:  translateX(0px) rotate(0deg);
    overflow: hidden;
}

#city {
    position:absolute;
    top:0;
    left:0;
    height:30vw;
    width:100%;
    z-index:-1;
    display: block;
}

#myCanvas {
    background:transparent;
    z-index: 100;
}

.aImg {
    display:none;
}

#mainContainer {
    display:none;
}

#scoreDiv {
    position:absolute;
    right:0;
    background:transparent;
    display:inline-block;
    border:3px solid red;
    padding:3px 50px 3px 10px;
    border-radius:20px;
    font-weight:700;
    font-size:24px;
    height:30px;
    margin:10px;
    z-index:1000;
    transform-origin:100% 0%;
}

#cn {
    height:52px;
    width:52px;
    background:red;
    position:absolute;
    right:-8px;
    top:-8px;
    border-radius:50%;
}

.gameHome {
    position:absolute;
    top:0;
    left:0;
    background:#fff;
    height:100vh;
    width:100vw;
    transform-origin:0% 0%;
    text-align:center;
}

#gameTitle {
    text-align:center;
    font-family:cursive;
    font-size:35px;
    margin-top:50px;
    font-weight:800;
}

#playBtn {
    font-size:20px;
    display:inline-block;
    background:#1642ea;
    color:#fff;
    padding:3px 25px;
    margin-top: 100px;
    border:none;
    border-radius:10px;
    box-shadow:3px 4px #000;
    outline:none;
}

#gameConf {
    width:50%;
    height:100%;
    background:red;
}

#gameDifficulty {
    width:100%;
    height:50%;
    background:blue;
    padding:0;
    margin:0;
}

.diffOpt {
    background:green
    font-family:cursive;
    font-size:20px;
    text-align:center;
}

#loading {
    height:60px;
    width:60px;
    background:transparent;
    display:inline-block;
    border:10px solid transparent;
    border-bottom-color:red;
    border-left-color:red;
    border-radius:50%;
    animation:ld 1s linear infinite;
}
Enter fullscreen mode Exit fullscreen mode

After running the CSS code Snippet below is the View you’ll see.

CSS View From Emmykolic

The reason for this view is that CSS works hand-in-hand with JavaScript. In this case, no matter how you click on that button it won’t respond because there’s no JavaScript yet.

Step 3: Make A JavaScript Page
Lastly, create a page and name it script.js script.js will contain a lot of JavaScript that will work with the ID’s and classes as well! This Javascript plays a vital role in the accomplishment of this car game. Below is the JavaScript code snippet.

(function(){
    "use strict"
    var hw = window.innerWidth || 360;
    var hh = window.innerHeight || 560;
    var gameHome = document.getElementById("startPage");
    var scoreDiv = document.getElementById("scoreDiv");
    if(hh > hw){
        gameHome.style.height = hw+"px";
        gameHome.style.width = hh+"px";
        gameHome.style.transform = "translateX("+hw+"px) rotate(90deg)";
        scoreDiv.style.bottom = 0;
        scoreDiv.style.transform = "rotate(90deg) translateX(40px)";
    }
})();

var ld;
var loaded = false;

function done(){
    document.getElementById("ldc").innerHTML="";
    document.getElementById("ldc").style.display = "none";
    document.getElementById("playBtn").innerHTML = "PLAY";
    loaded = true;
}

(function(){
    var w = window.innerWidth || 360;
    var h = window.innerHeight || 560;

    if(h > w){
        var nh = h;
        h = w;
        w = nh;
        document.getElementById("mainContainer").style.transform = "translateX("+(h)+"px) rotate(90deg)";
    }
    document.getElementById("mainContainer").style.width = w+"px";
    document.getElementById("mainContainer").style.height = h+"px";

    document.getElementById("city").style.height = h*.3+"px";
    document.getElementById("city").style.width = w+"px";

    var c = document.getElementById("myCanvas");
    c.height = h;
    c.width = w;

    var ctx = c.getContext("2d");

function loadGame(){
    "use strict";

    var roadWidth = 5*w/36;
    var roadTop = h-h*0.7;
    var roadLeft = (w-roadWidth)/2;
    var roadConstant = roadLeft/(h-roadTop);
    var score = 0;
    var scoreC = document.getElementById("score");
    function updateScore(ds){
        score+=ds;
        scoreC.textContent = score;
    }
    updateScore(0);

    var rso = [];
    var ratio = 0.8;
    var totalRso = 20;
    var maxHF = h*(1-ratio)/(2.25*(1-Math.pow(ratio,totalRso)));
    var maxH = maxHF;
    var totalHeight = 0.7*h;
    var minWidth = 1;
    var maxWidth = 26;
    var dif = maxWidth - minWidth;
    var changedHeight = totalHeight-maxH*ratio;
    var cnst1 = Math.pow(ratio,totalRso)/(1-ratio);
    var stp = h-totalHeight;
    var tMaxH = h*20/36;
    var treeCnst = tMaxH/roadLeft;

    var gameDifficulty = 100;



    function TreeBuilder(src,src2,start,left){
        this.src = treeSrc[src];
        this.src2 = treeSrc[src2];
        this.y = start;
        this.x = 0;
        this.h = 0;
        this.w = 0;
        this.dy = 0.01;
        this.r = 1.009;
        this.left = left;
    }

    TreeBuilder.prototype.draw = function(){
        this.y += this.dy;
        this.dy *= this.r;
        this.x = (h-this.y)*roadConstant - this.w - this.w*this.left;
        this.h = (roadLeft-this.x-this.w*this.left)*treeCnst;
        this.w = this.h*2/3;

        ctx.drawImage(this.src,this.x,this.y-this.h,this.w,this.h);
        ctx.drawImage(this.src2,w-this.x-this.w,this.y-this.h,this.w,this.h);

        if(this.y >= h){
            this.y = stp;
            this.h = 0;
            this.w = 0;
            this.left = Math.random()*3;
            this.dy = 0.5;
        }
    }

    function _i(x){
        return document.getElementById(x);
    }
    var treeSrc = [_i("t1"),_i("t2"),_i("t3"),_i("t4")];

    var trees = [];
    for(var n = 0; n < ((h*0.7)/50-2); n++){
        trees.push(new TreeBuilder(Math.floor(Math.random()*4),Math.floor(Math.random()*4),stp+n*50,2));
    }


    var carWCnst = roadLeft*2/totalHeight;
    var carW = (w > 560) ? 120 : 90;
    var carH = carW*2/3;

    function CarBuilder(src,start,lane){
        this.src = carSrc[src];
        this.y = start;
        this.x = 0;
        this.h = 0;
        this.w = 0;
        this.dy = 0.5;
        this.lane = lane;
    }

    CarBuilder.prototype.draw = function(){
        this.dy *= 1.01;
        this.y += this.dy;
        this.x = (carWCnst/2)*(h-this.y)+(w-(carWCnst*(h-this.y)))*this.lane/8;
        this.w = carW-carW*carWCnst*(h-this.y)/w;
        this.h = 1.7*this.w/3;

        ctx.drawImage(this.src,this.x,this.y-this.h,this.w,this.h);
        if(this.y >= h-20){
            if(Math.abs(this.x-cx) <= carH && Math.abs(this.y-h+carH) <= carH){
                clearInterval(intv);
                setTimeout(function(){
                    document.getElementById("mainContainer").style.display = "none";
                    document.getElementById("startPage").style.display = "block";
                },1000);
            }
        }
        if(this.y >= h+100){
            this.y = stp;
            this.h = 0;
            this.w = 0;
            this.left = Math.random()*3;
            this.dy = 0.5;
            this.lane = 1+Math.random()*5;
        }
    }

    var carSrc = [_i("c1"),_i("c1"),_i("c1")];

    var cars = [];
    for(var n = 0; n < ((h*0.7+100)/gameDifficulty); n++){
        cars.push(new CarBuilder(Math.floor(Math.random()*3),stp+n*gameDifficulty,1));
    }

    //Coin.....
    var coinW = (w > 560) ? 75 : 60;
    function CoinBuilder(start,lane){
        this.src = coinSrc;
        this.y = start;
        this.x = 0;
        this.h = 0;
        this.w = 0;
        this.dy = 0.5;
        this.lane = lane;
    }

    CoinBuilder.prototype.draw = function(){
        this.dy *= 1.01;
        this.y += this.dy;
        this.x = (carWCnst/2)*(h-this.y)+(w-(carWCnst*(h-this.y)))*this.lane/8;
        this.w = coinW-coinW*carWCnst*(h-this.y)/w;
        this.h = this.w;

        ctx.drawImage(this.src,this.x,this.y-this.h,this.w,this.h);
        if(this.y >= h-20){
            if(Math.abs(this.x-cx) <= coinW && Math.abs(this.y-h+coinW) <= coinW){
                this.y = stp;
                this.h = 0;
                this.w = 0;
                this.left = Math.random()*3;
                this.dy = 0.5;
                this.lane = Math.floor(1+Math.random()*5);
                updateScore(1);
            }
        }
        if(this.y >= h+100){
            this.y = stp;
            this.h = 0;
            this.w = 0;
            this.left = Math.random()*3;
            this.dy = 0.5;
            this.lane = Math.floor(1+Math.random()*5);
        }
    }

    var coinSrc = _i("cn");

    var coins = [];
    for(var n = 0; n < ((h*0.7+100)/(gameDifficulty-50)); n++){
        coins.push(new CoinBuilder(stp+n*(gameDifficulty-50),6));
    }



    //End Coin...



    function rectPoints(n,ho){
        n = totalRso-n-1;
        var y1 = stp+maxH*cnst1*(Math.pow(1/ratio,n)-1);
        var x1 = roadLeft-roadConstant*(y1-stp);
        var y2 = y1;
        var x2 = x1 + minWidth+(y1-stp)*dif/totalHeight;
        var y3 = y1 + maxH*cnst1*(Math.pow(1/ratio,n+1)-1);
        var x3 = roadLeft-roadConstant*(y3-stp);
        var y4 = y3;
        var x4 = x3 + minWidth+(y3-stp)*dif/totalHeight;

        return [x1,y1,x2,y2,x4,y4,x3,y3];
    }


    for(var n = 0; n < totalRso; n++){
        rso.push(rectPoints(n,h));
        rso\[n\][8] = (n%2==0) ? "#000" : "#fff";
    }

    function draw(){
        ctx.beginPath();
        ctx.moveTo((w-roadWidth)/2,stp);
        ctx.lineTo((w-roadWidth)/2+roadWidth,stp);
        ctx.lineTo(w,h);
        ctx.lineTo(0,h);
        ctx.fillStyle="#555";
        ctx.fill();
        ctx.closePath();
        for(var n = 0; n < totalRso; n++){
            ctx.beginPath();
            ctx.moveTo(rso\[n\][0],rso\[n\][1]);
            ctx.lineTo(rso\[n\][2],rso\[n\][3]);
            ctx.lineTo(rso\[n\][4],rso\[n\][5]);
            ctx.lineTo(rso\[n\][6],rso\[n\][7]);
            ctx.lineTo(rso\[n\][0],rso\[n\][1]);
            ctx.lineWidth = 2;
            ctx.fillStyle = rso\[n\][8];//"rgb("+Math.floor(Math.random()*255)+","+Math.floor(Math.random()*255)+","+Math.floor(Math.random()*255)+")";
            ctx.fill();
            ctx.closePath();

            ctx.beginPath();
            ctx.moveTo(w-rso\[n\][0],rso\[n\][1]);
            ctx.lineTo(w-rso\[n\][2],rso\[n\][3]);
            ctx.lineTo(w-rso\[n\][4],rso\[n\][5]);
            ctx.lineTo(w-rso\[n\][6],rso\[n\][7]);
            ctx.lineTo(w-rso\[n\][0],rso\[n\][1]);
            ctx.lineWidth = 2;
            ctx.fillStyle = rso\[n\][8];//"rgb("+Math.floor(Math.random()*255)+","+Math.floor(Math.random()*255)+","+Math.floor(Math.random()*255)+")";
            ctx.fill();
            ctx.closePath();


        }

    }

    var cx = (w-carW)/2;
    var cl = false, cr = false;
    var car = _i("c1");
    var ms = 3*w/560;
    function drawCar(){
        if(cl) if(cx+carW+50 < w) cx+=ms;
        if(cr) if(cx-50 > 0) cx-=ms;
        ctx.drawImage(car,cx,h-carH,carW,carH);
    }


    var m = 0;
    var intv = setInterval(function(){
        try{
        ctx.clearRect(0,0,w,h);
        maxH+=0.5;
        changedHeight = maxH*cnst1*(Math.pow(1/ratio,totalRso-1)-1);//maxH*(1-Math.pow(ratio,totalRso-5))/(1-ratio);
        if(changedHeight >= totalHeight){
            maxH = maxHF;
            m++;
        }
        for(var n = 0; n < totalRso; n++){
            rso[n]=rectPoints(n,h-totalHeight+changedHeight);
            if(m%2==0) rso\[n\][8] = (n%2==0) ? "#000" : "#fff";
            else rso\[n\][8] = (n%2==1) ? "#000" : "#fff";
        }
        draw();
        for(var n = 0; n < trees.length; n++){
            trees[n].draw();
        }

        for(var n = 0; n < coins.length; n++){
            coins[n].draw();
        }

        for(var n = 0; n < cars.length; n++){
            cars[n].draw();
        }


        drawCar();
        }catch(err){

        }

    },10)
    //draw();

    //Game Control

    //Touch
    function getTouch(e){
        e.preventDefault();
        var to = e.changedTouches[0];
        var ty = parseInt(to.clientY);
        if(ty>(h/2)){
            cl = true;
        }
        else{
            cr = true;
        }
    }
    function getTouchEnd(){
        cl = false;
        cr = false;
    }

    c.removeEventListener("touchstart",getTouch);
    c.removeEventListener("touchend",getTouchEnd);
    c.addEventListener("touchstart",getTouch);
    c.addEventListener("touchend",getTouchEnd);
    //Key..
    function getKey(e){
        e.preventDefault();
        var ty = e.keyCode;
        if(ty===39){
            cr = false;
            cl = true;
        }
        else if(ty===37){
            cl = false;
            cr = true;
        }
    }
    function getKeyEnd(e){
        var ty = e.keyCode;
        if(ty === 39) cl = false;
        else if(ty === 37) cr = false;
    }

    document.body.removeEventListener("keydown",getKey);
    document.body.removeEventListener("keyup",getKeyEnd);
    document.body.addEventListener("keydown",getKey);
    document.body.addEventListener("keyup",getKeyEnd);
    //Accelarometre

    function driveCar(e){
        var y = e.accelerationIncludingGravity.y;

        if(y > 0){
            if(cx+carW+50 < w) cx += y*ms;
        }
        else{
            if(cx-50 > 0) cx += y*ms;
        }
    }

    if(window.DeviceMotionEvent){
        window.removeEventListener("devicemotion",driveCar)
           window.addEventListener("devicemotion",driveCar,false)
    }
    //End
}
ld = function(){
    if(loaded){
        document.getElementById("startPage").style.display = "none";
        document.getElementById("mainContainer").style.display = "block";
        loadGame();
    }
}
})();
Enter fullscreen mode Exit fullscreen mode

Below is the view you'll see immediately after you apply the JavaScript Snippet above. But the difference between this view and the previous one is that the button is now clickable.


View From Emmykolic

So After implementing this code correctly Below is what you’ll see on your screen.

A Short video of the car game

Conclusion

Wow, we have come to the end of this Guide. Hope you’ve gained a measure of value from it. Briefly, we have seen the step-by-step way, to build a car game.

Note: the entire JavaScript code is called vanilla JavaScript cause I didn’t use any Library or Framework to write any line!

Please follow me on my various social media platforms, and feel free to send me an email when necessary!

Without wasting much of your time till next time, bye.


About The Author

Full-stack Laravel developer Emmanuel Okolie has 2+ years of experience in software development. He has developed full-fledged skills by combining software development, writing, and instructing others in what he does.

His stacks include ReactJ, Laravel, PHP, JavaScript, and other languages and frameworks.
As a freelancer, he creates websites for clients and writes technical guides to show people how to do what he does.

If given the chance, Emmanuel Okolie would enjoy speaking with you. Please go to and follow him on his website, Facebook, Github, LinkedIn, and Twitter.

Top comments (2)

Collapse
 
petarov profile image
Petar G. Petrov

Great job, man! Cheers

Collapse
 
emmykolic profile image
Emmanuel C. Okolie

Thank you so much man!

Will love to hear more from you!