Develop a small game with HTML5

Time:2021-11-18

Effect drawing first

Develop a small game with HTML5

Preparation before starting

  1. game.html
  2. js/Create insidegame.js
  3. images/There are three pictures inside, a background picture (background. PNG), a hero picture (hero. PNG) and a monster picture (monster. PNG)

staygame.htmlWrite the following lines of simple HTML code:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Simple Canvas Game</title>
    </head>
    <body>
        <script></script>
    </body>
</html>

We aregame.htmlIntroducedgame.jsFile, yes, all the rest of the work is in operationgame.js, add the JS code of the game.

Create canvas

In game.js, we first need to create a canvas for the game stage:

var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 512;
canvas.height = 480;
document.body.appendChild(canvas);

Here, an element is created and set through JScanvasWidth and height, and finally add them to the < body > label.var ctx = canvas.getContext("2d");MediumctxVariables will be used later. For specific canvas usage, see the link here:

https://developer.mozilla.org/en/canvas_tutorial

Prepare pictures

The game needs to load the three pictures stored under the images folder:

// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
    bgReady = true;
};
bgImage.src = "images/background.png";

// Hero image
var heroReady = false;
var heroImage = new Image();
heroImage.onload = function () {
    heroReady = true;
};
heroImage.src = "images/hero.png";

// Monster image
var monsterReady = false;
var monsterImage = new Image();
monsterImage.onload = function () {
    monsterReady = true;
};
monsterImage.src = "images/monster.png";

The above three pictures are loaded by creating a simple picture object. Three variables similar to bgready are used to identify whether the picture has been loaded. If the picture is drawn before the picture is loaded, an error will be reported. If you’re not surenew Image()What the hell is it? You canbgImage.src = "images/background.png";Later useconsole.log(bgImage);To see, you will see something similar:

<img >

Game object

We need to define some objects so that we can use them later:

var hero = {
    speed: 256 // movement in pixels per second
};
var monster = {};
var monstersCaught = 0;

Since heroes catch monsters, we have to have oneheroandmonsterObject. andheroThere is onespeedProperty controls how many pixels he moves per second. Monsters will not move during the game, so you don’t need to set properties for the time being.monstersCaughtIt is used to store the number of times the monster is caught. Of course, the initial value is 0.

Process user input

The game is for people to play, so how do we know what the user did in the process? Pressed the keyboard? Click the mouse? These are the user’s input when playing the game, so once we capture these inputs, we can process the user’s input according to the game logic:

// Handle keyboard controls
var keysDown = {};

addEventListener("keydown", function (e) {
    keysDown[e.keyCode] = true;
}, false);

addEventListener("keyup", function (e) {
    delete keysDown[e.keyCode];
}, false);

Here, we just listen to the input of two users:

  1. keydown
  2. keyup

Then we save the user’s input first, and there is no immediate response. For this purpose, we usekeysDownThis object is used to save the key value pressed by the user(keyCode), if the pressed key value is in this object, we will handle it accordingly.

In front-end development, users usually trigger click events before executing animation or initiating asynchronous requests

Start a game

At the end of the game, we need to start a new round of the game, sogame.jsadd toresetfunction

// Reset the game when the player catches a monster
var reset = function () {
    hero.x = canvas.width / 2;
    hero.y = canvas.height / 2;


    // Throw the monster somewhere on the screen randomly
    monster.x = 32 + (Math.random() * (canvas.width - 64));
    monster.y = 32 + (Math.random() * (canvas.height - 64));

};

reset()Function is used to start a new round and game. In this method, we put the hero back in the center of the canvas and the monster in a random place.

Update Object

During the game, whether the user is playing (with correct input status) or the game is over, we need to update the game object in time:

var update = function (modifier) {
    if (38 in keysDown) { // Player holding up
        hero.y -= hero.speed * modifier;
    }
    if (40 in keysDown) { // Player holding down
        hero.y += hero.speed * modifier;
    }
    if (37 in keysDown) { // Player holding left
        hero.x -= hero.speed * modifier;
    }
    if (39 in keysDown) { // Player holding right
        hero.x += hero.speed * modifier;
    }

    // Are they touching?
    if (
        hero.x <= (monster.x + 32)
        && monster.x <= (hero.x + 32)
        && hero.y <= (monster.y + 32)
        && monster.y <= (hero.y + 32)
    ) {

        ++monstersCaught;
        reset();
    }


};

updateThe function is responsible for updating each object of the game and will be called repeatedly regularly. First, it is responsible for checking that the user is currently holding down the middle arrow key, and then moving the hero in the corresponding direction.

It’s a bit of a mental effort. Maybe it’s from thismodifierVariable. You canbehindTo be achievedmainWe can see its source in the method, but it is necessary to explain it in detail here. It is a factor that starts with 1 and changes over time. For example, after 1 second, its value is 1, and the hero’s speed will be multiplied by 1, that is, 256 pixels per second; If half a second, its value is 0.5, and the hero’s speed is multiplied by 0.5, that is, the hero moves at half the normal speed in half a second. In theory, because of thisupdateFunctions are called very quickly and frequently, somodifierThe value of will be very small, but with this factor, no matter how fast our code runs, it can ensure that the hero’s moving speed is constant.

Here we need to explain the following basis for judging monsters and Heroes:

 if (
        hero.x <= (monster.x + 31)
        && monster.x <= (hero.x + 31)
        && hero.y <= (monster.y + 32)
        && monster.y <= (hero.y + 32)
    )

above31,32ByheroandmonsterIt depends on the size of the picture. Our hero picture is32x32, monster picture is30x32Therefore, the above judgment conditions can be obtained according to the law that the coordinates are located in the center of the picture.

Now the hero’s movement is based on user input (pressupperlowerLeftrightKey), then it’s time to check the events triggered during the movement, that is, the hero meets the monster. This is the winning point of the game,monstersCaught +1Then start a new round.

Render Objects

The code written before is in the preparatory work and dealing with the state of some games. Now we will get to the point: we need to draw everything

// Draw everything
var render = function () {
    if (bgReady) {
        ctx.drawImage(bgImage, 0, 0);
    }

    if (heroReady) {
        ctx.drawImage(heroImage, hero.x, hero.y);
    }

    if (monsterReady) {
        ctx.drawImage(monsterImage, monster.x, monster.y);
    }

    // Score
    ctx.fillStyle = "rgb(250, 250, 250)";
    ctx.font = "24px Helvetica";
    ctx.textAlign = "left";
    ctx.textBaseline = "top";
    ctx.fillText("Goblins caught: " + monstersCaught, 32, 32);
};

therectxThis is the variable we created earlier. Then usecanvasofdrawImage()The first is, of course, to draw the background. Then draw heroes and monsters in the same way. The order in this process is particular, because the later painted objects will cover the previous objects.

After that, we changedCanvasThe style of the drawing context and callfillTextTo draw the text, that is, the part of the scoreboard. There are no other complex animation effects and fighting scenes in this game. The drawing part is completed

Main loop function

After we draw the picture, what we need to implement next is the loop structure of the game, so we put it inmainIn the function:

// The main game loop
var main = function () {
    var now = Date.now();

    var delta = now - then;
    //console.log(delta);
    update(delta / 1000);
    render();

    then = now;

    // Request to do this again ASAP
    requestAnimationFrame(main);
};

The main function above controls the flow of the whole game. First, get the current time to calculate the time difference (how many milliseconds have passed since the last main function was called). obtainmodifierThen divide by 1000 (that is, the number of milliseconds in 1 second) and pass it inupdateFunction. Last callrenderFunction and save the time of this time.

Set requestanimationframe()

On topmainFunction, we passrequestAnimationFrame()CalledmainFunction, so we need to declare:

var w = window;
requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;


There are so many here||, for nothing else, just considering the problem of browser compatibility.

Finally, start the game

Everything is ready, only due to the east wind. At this point, all the game codes are basically finished. What we need to do now is to call the corresponding function to start the game:

// Let's play this game!
var then = Date.now();
reset();
main();

Here, the code is finished. First, set an initial time variablethenUsed to run firstmainFunction use. Then callresetFunction to start a new round of the game (if you remember, this function is to put the hero in the middle of the screen and put the monster in a random place so that the hero can catch it)

Open with browsergame.html, start playing games!

Further thinking

In the process of playing the game, you will find that every timeheroCapturemonsterheroBack tocanvasRight in the middle of the canvas. So what we need to do now is toheroSnap tomonsterLet’s go when we’re readyheroStay in the captured position, no longer backcanvasRight in the middle.

This phenomenon is mainly due toresetIn functionhero.xandhero.yIt’s dead, so one of the easiest ways is toresetParameters passed in:

var reset = function (x,y) {
    hero.x = x;
    hero.y = x;
};

Then inupdatecallresetPass in the parameters of the capture location when:

var update = function (modifier) {

        //...other codes

        ++monstersCaught;
        reset(heor.x,hero.y);

};


Finally, at the beginning of the gameheroPut oncanvasIn the middle:

var then = Date.now();
reset(canvas.width / 2,canvas.height / 2);
main();

be accomplished!

Hapyy Hacking