Techniques for transferring images directly into HTML canvas games

I created a thrilling race car game and here is the code snippet:

index.html

<!DOCTYPE html>
<html>
<head>
    <title> Extreme Race Car Game </title>
    <link rel="stylesheet" type="text/css" href="style.css">
    <script>
        var ctx;

            //save the parameters to variables for easier clearing
        var x_Car = 30,
            y_Car = 95,
            width_Car = 110,
            height_Car = 55,
            imgCar = new Image();
        imgCar.src = "cars/race-car.png";

        var nrMonsters = 0,
            imgMonster = new Image();
        imgMonster.src = "Monster/yellow_monster.png";

        var width_Monster = 100;
        var height_Monster = 20;
        var x_Monster = 50;
        var y_Monster = 5;
        var speed = 1;

        // function drawMonster() {
        //     ctx.drawImage(imgMonster, x_Monster, y_Monster, width_Monster, height_Monster);
        // }
        function drawCar() {
            ctx.drawImage(imgCar, x_Car, y_Car, width_Car, height_Car);
        }

        function rand() {
            var left = 50;
            var right = 150;
            var z;
            var random = Math.random();

            if (random > 0.5) {
                 z = right;
            } else {
                 z = left;
            }
            return z;
        }

        valX = rand();

        function draw(x, y) {
           //ctx.save();
            if (valX == 50 && x_Car > 75) {
                ctx.clearRect(x + 5, -5, 150, 150);  // 95 cu 150
            } else if (valX == 50) {
                ctx.clearRect(x + 5, y, 150, 10);
            } else if (valX == 150 && x_Car < 32){
                ctx.clearRect(x + 150, -5, 260, 150);  // 95 cu 150
            } else if (valX == 150) {
                ctx.clearRect(x + 150, y, 260, 10);
            }

            ctx.drawImage(imgMonster, valX, y, width_Monster, height_Monster);
            ctx.restore();

            y += speed;
            if (y == y_Car && x_Car < 32 && valX == 50
             || y == y_Car && x_Car > 75 && valX == 150
             || y > y_Car && y < y_Car + height_Car && x_Car < 32 && valX == 50
             || y > y_Car && y < y_Car + height_Car && x_Car > 75 && valX == 150) {
                window.location.href = "you_lost_the_game.html";
                // alert("You lost the game");
            }

            var loopTimer = setTimeout("draw(" + x + ", " + y + ")", 20);

           if (y == 150 && nrMonsters < 15
            || y == 160 && nrMonsters >= 15) {
                valX = rand();
                nrMonsters++;

                console.log(nrMonsters);
                document.getElementById("numarObstacole").innerHTML  = nrMonsters;

                if (nrMonsters == 5
                 || nrMonsters == 10
                 || nrMonsters == 20
                 || nrMonsters == 25) {
                // || nrMonsters == 20 || nrMonsters == 27) {
                    speed += 1;
                } else if (nrMonsters == 15) {
                    speed += 1;
                }

                draw(0, 0);

                if (nrMonsters == 25) {
                    window.location.href = "win.html";
                }
           }

        }

        function init() {
            ctx = document.getElementById("canvas").getContext("2d");
            // audio
            // myAudio = new Audio('http://static1.grsites.com/archive/sounds/cars/cars002.wav'); 
            myAudio = new Audio("Sounds/Get low NFS.mp3");
            myAudio.addEventListener("ended", function() {
                this.currentTime = 0;
                this.play();
            }, false);
            myAudio.play(); 

            //draw wall

            draw(0, 0); 
            drawCar();

            function moveRight() {
                ctx.clearRect(x_Car, y_Car, width_Car, height_Car);
                x_Car = x_Car + 120;
                if(x_Car > 220){
                    x_Car -= 120;
                    drawCar();
                } else {
                    drawCar();
                }
            }

            function moveLeft() {
                ctx.clearRect(x_Car, y_Car, width_Car, height_Car);
                x_Car = x_Car-120;
                if (x_Car < 20) {
                    x_Car += 120;
                    drawCar();
                } else {
                    drawCar();
                }
            }

            function moveUp() {
                ctx.clearRect(x_Car, y_Car, width_Car, height_Car);
                y_Car = y_Car-20;
                drawCar();
            }

            function moveDown() {
                ctx.clearRect(x_Car, y_Car, width_Car, height_Car);
                y_Car = y_Car + 20;
                drawCar();
            }

            window.addEventListener("keypress", checkKeyPressed, false);

            function checkKeyPressed(e) {
                if (e.charCode == "97" || e.charCode == 027) {
                    moveLeft();
                }
                if (e.charCode == "100" || e.charCode== 026) {
                    moveRight();
                }
                if (e.charCode == "119" || e.charCode== 024) {
                    moveUp();
                }
                if (e.charCode == "115" || e.charCode== 025) {
                    moveDown();
                }
            }
        }

        function moveRight() {
            ctx.clearRect(x_Car, y_Car, width_Car, height_Car);
            x_Car = x_Car + 120;
            if (x_Car > 220) {
                x_Car -= 120;
                drawCar();
            } else {
                drawCar();
            }
        }

        function moveLeft() {
            ctx.clearRect(x_Car, y_Car, width_Car, height_Car);
            x_Car = x_Car - 120;
            if(x_Car < 20) {
                x_Car += 120;
                drawCar();
            } else {
                drawCar();
            }
        }

        function moveUp() {
            ctx.clearRect(x_Car, y_Car, width_Car, height_Car);
            y_Car = y_Car - 20;
            drawCar();
        }

        function moveDown() {
            ctx.clearRect(x_Car, y_Car, width_Car, height_Car);
            y_Car = y_Car + 20;
            drawCar();
        }

        window.addEventListener("keypress", checkKeyPressed, false);

        function checkKeyPressed(e) {
            if (e.charCode == "97") {
                moveLeft();
            }
            if (e.charCode == "100") {
                moveRight();
            }
            if (e.charCode == "119") {
                moveUp();
            }
            if (e.charCode == "115") {
                moveDown();
            }
        }
    </script>
</head>
<body onLoad="init();">
    <div id="moveButons">
        <table>
            <tr>
                <td></td>
                <td>
                    <input class="button" id="up" type="button" value="Move Up" onclick="moveUp()"/>
                </td>
                <td></td>
            </tr>
            <tr>
                <td>
                    <input class="button" id="left" type="button" value="Move Left" onclick="moveLeft()"/>
                </td>
                <td></td>
                <td>
                    <input class="button" id="right" type="button" value="Move Right" onclick="moveRight()"/>
                </td>
            </tr>
            <tr>
                <td></td>
                <td>
                    <input class="button" id="down" type="button" value="Move Down" onclick="moveDown()"/>
                </td>
                <td></td>
            </tr>
        </table>
    </div>
    <p class="numarObstacole">
        You have passed <span id="numarObstacole"> 0 </span> obstacles
    </p>
    <canvas id="canvas">
        Your browser doesn't support the HTML5 element canvas.
    </canvas>
</body>
</html>

style.css

* {
    margin: 0;
    padding: 0;
}

body {
    background-color: yellow;
}

#canvas {
    background: white;
    margin-left: 50%;
    position: absolute;
    left: -206px;
    width: 412px;
    height: 100%;
    background-image: url("street/street (2).jpg");
    background-position: 0px 0px;
    background-repeat: repeat-y;

    -webkit-animation: animatedBackground 5s linear infinite;
       -moz-animation: animatedBackground 5s linear infinite;
            animation: animatedBackground 5s linear infinite;
}

#moveButons {
    position: absolute;
    left: 20px;
    top: 50px;
}

@-webkit-keyframes animatedBackground {
    from {  background-position: 0 100%;  }
      to {  background-position: 0 0;     }
}
@-moz-keyframes animatedBackground {
    from {  background-position: 0 100%;  }
      to {  background-position: 0 0;     }
}
@keyframes animatedBackground {
    from {  background-position: 0 100%;  }
      to {  background-position: 0 0;     }
}

#lostGame {
    text-align: center;
    color: red;
    margin-top: 175px;
}

#win {
    text-align: center;
    color: blue;
    margin-top: 175px;
}

#canvas_lost {
    width: 320px;
    height: 240px;
    background: url("Joker/the-joker-laughing-1.jpg");
    margin-left: 50%;
    position: absolute;
    left: -160px;
}

#canvas_win {
    width: 320px;
    height: 240px;
    background: url("Joker/joker.gif");
    margin-left: 50%;
    position: absolute;
    left: -160px;
}

.button {
    color: blue;
    font-size: 17px;
    text-align: center;
    background: #6BA7FA;
    width: 100px;
}

.numarObstacole {
    position: absolute;
    color: #1F1;
    background: silver;
    font-size: 20px;
    font-family: Serif;
}

#numarObstacole {
    color: blue;
    font-size: 22px;
    font-family: sans-serif;
}

The issue may arise with the monster image trailing behind when it accelerates towards the car image.

Are there any steps I can take to resolve this?

Answer №1

The solution

It seems like the issue lies with the clearRect method in your code. Instead of manually targeting specific areas to clear on the canvas (like

ctx.clearRect(x + 150, -5, 260, 150);
), a more efficient approach would be:

// Store the canvas element in a variable
var canvas = document.getElementById("canvas");

// ctx remains the same
var ctx = canvas.getContext("2d");


function draw(x, y) {

    // Clear the entire canvas on each frame
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    ...

This way, any residue left behind by the car or monster will be removed with each update.


Next, regarding coding suggestions:

  1. To simplify handling audio playback, instead of listening for the end event, set the loop attribute to true. Consider this condensed version:
// Your current implementation
var myAudio = new Audio("Sounds/---.mp3"); 
myAudio.addEventListener("ended", function() {
    this.currentTime = 0;
    this.play();
}, false);
myAudio.play();


// A concise and optimized alternative
var myAudio = new Audio("Sounds/---.mp3");
myAudio.loop = true;  // Replays the audio upon reaching the end
myAudio.play();

  1. This section of code could be enhanced:
if (nrMonsters == 5
 || nrMonsters == 10
 || nrMonsters == 20
 || nrMonsters == 25) {
    speed += 1;
} else if (nrMonsters == 15) {
    speed += 1;
}

If do this something or else do this thing? A simple fix is available:

if (nrMonsters == 5
 || nrMonsters == 10
 || nrMonsters == 15
 || nrMonsters == 20
 || nrMonsters == 25) {
    speed += 1;
}

  1. You can improve this segment of code by removing unnecessary logic:
// Inside the moveRight() function
if (x_Car > 220) {
    x_Car -= 120;
    drawCar();
} else {
    drawCar();
}

Since the drawCar() function will be called regardless, there's no need to include it within the if block. Here's a cleaner version:

if (x_Car > 220) {
    x_Car -= 120;
}
drawCar();

  1. Avoid using leading zeroes in numeric comparisons:
// From the checkKeyPressed() function
if (e.charCode == "97" || e.charCode == 027) {  ...  }

When a number starts with zero, as in 027, JavaScript interprets it as an octal value. If that's not your intention, use proper formatting such as 0o for octal numbers. For instance:

var binal = 0b10;  // (0b)10 in binary equals 2 in decimal
var octal = 0o10;  // (0o)10 in octal equals 8 in decimal
var hexal = 0x10;  // (0x)10 in hexadecimal equals 16 in decimal

These are the optimizations I recommend for your game. Best of luck with its development! Cheers!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Floating Div Elements

Trying to solve this seemingly simple problem has been quite the challenge for me. I have a container with multiple divs added to it, and I want these divs to position themselves freely within any available white space. However, they must follow a pattern ...

How to adjust cell alignment in Handsontable

Handsontable showcases cell alignment options in the align cell demo: Horizontal Left Center Right Justify Vertical Top Middle Bottom Displayed below is a screenshot: To retrieve data, utilize the following code snippet: $('#table-wrapper&ap ...

Encountering Internal Server Error (500) while attempting to send an ajax request to the controller

I am currently attempting to send data back from my view to the controller using an ajax request. The request is formulated as follows: $("body").on("click", "#AddProduct", function () { var id = $("#ProductDrop").val(); va ...

What is the best way to prevent URL modification in Angular?

Currently, I am working on a project with a specific page (let's call it localhost:XXXX/notification-page) and we want this to be the only URL that can be accessed. Any attempt to change the URL should redirect users back to the notification-page. As ...

Angular 2: trigger a function upon the element becoming visible on the screen

How can I efficiently trigger a function in Angular 2 when an element becomes visible on the screen while maintaining good performance? Here's the scenario: I have a loop, and I want to execute a controller function when a specific element comes into ...

Utilizing the ng-required directive with the model's value in AngularJS

I need to validate a form field for both null and its value. Can anyone suggest how I can achieve this without writing a function on the controller? <form name="frm"> <input type="text" ng-model="myModel" ng-required="myModel != '' || m ...

Utilizing numerous await statements within a single asynchronous function

My async function has 3 awaits, like this: const sequenceOfCalls = async(req, res, next) =>{ await mongoQuery(); await apiCall1(); await apiCall2(); } apiCall1 uses response of mongoQuery and apiCall2 uses response of apiCall1. The issue is ...

Encourage users to activate the physical web feature in compatible web browsers

Is it possible to use JavaScript to encourage users to activate the physical web (and thus BlueTooth), similar to how APIs like "getUserMedia()" prompt users? UPDATE: Given that this technology is still in its early stages and not extensively supported, t ...

Using JQuery to specifically include only the checked rows in an array

I am trying to build a JQuery array with only the asp:gridviews that have been checked. However, I'm facing an issue where all rows are being added, regardless of their check status. How can I ensure that only checked rows are included in this array? ...

What are the recommended methods for injecting db and logger into routes in an Express application?

When working with Express and needing to pass single instance references like a logger or database to routes, I have come across three options. The first option is to attach it to the request object through a middleware: app.use(function(req,res,next){ re ...

What's the reason the element inside the <div> is not displayed when a value is selected in the dropdown box?

I am perplexed as to why the element inside the does not appear when a value is selected in the drop down box. However, it works perfectly fine in JSFiddle: JSFiddle Below is my HTML code and Jquery script that functions properly in my own system: <t ...

Is there a way to set the starting position of the overflow scroll to the middle?

Is there a way to have the overflow-x scrollbar scroll position start in the middle rather than on the left side? Currently, it always begins at the left side. Here is what it looks like now: https://i.stack.imgur.com/NN5Ty.png If anyone knows of a soluti ...

Enhancing website functionality with Regex in Javascript

So, here is the code I am working with: var patt = new RegExp("/.+/g"); var device_id = patt.exec("javascript:project_id:256, device_id:2232"); Surprisingly, after running the above code, the value of device_id is empty and I can't seem to figure ou ...

What is the most effective way to retrieve the count of users who have logged in within the past three months by utilizing Jquery

I am seeking to retrieve the count of users who have logged in the last three months utilizing a JSON API and Jquery. This is my current progress: $.getJSON('users.json', function(data) { var numberOfUserLogged = 0; var d1 = ...

Adjust the width of the navigation bar

Currently, I am attempting to center the menu bar and ensure that it perfectly fits the text. For reference, here is the website that I'm currently working on: I have already discovered a way to center the menu items as shown below: .menu { tex ...

Setting the column width and border-top in Highcharts

Hey there, I'm facing an issue with my highcharts diagram. 1) Can anyone help me adjust the column width to match the width of the month area? (I've tried changing "width" in CSS but it's not working) 2) Also, how can I remove all borders ...

What is preventing me from getting jQuery UI 1.8.20 dialog to function on JSFiddle?

My attempt to implement jQuery UI dialog in JSFiddle has been unsuccessful, consistently resulting in a dialog opening error caused by a deep-seated issue within jQuery UI: Uncaught TypeError: Cannot read property '3' of undefined. Although I am ...

Personalized Element Commands and features

UniquePage.html <div ng-controller="UniquePageCtrl"> <unique-custom-directive arg1="{{currentObj.name}}"></my-custom-directive> <div> in UniquePageCtrl.js (Controller) app.controller("UniquePageCtrl", ["$scope", function ($sc ...

Please refer to the image located in the directory that is one level above the current location

My current setup includes an image located at images\a.jpg and a script in js\a.js. Both the images and js directories are under the www document root directory. Within the script a.js, I have the following code snippet: var provider_img = $(th ...

Conducting simultaneous tests on the mobile application and web browser to ensure optimal performance

Dear friends, I am in need of some assistance. I am looking to run end-to-end tests simultaneously on a mobile app and a web browser, make alterations on one platform, and check to see the changes reflected on the other multiple times. My current plan is t ...