JS implements the snake game

JS implements the snake game

Page effect:

The Snake game is developed using the mediator model. Our Snake case is not written in one HTML file like before, but is split into classes. Separate js represents each class, and the mediator class is the Game class.

1. Initialization structure

First we need to initialize the page. The initialization layout is not written directly in the HTML tag, but initialized through the game node tree

We set up a table with 20 rows and 20 columns, using this.row to represent rows and this.col to represent columns.

Games.prototype.init = function () {
    this.dom = document.createElement('table');
    var tr, td;
    //Traverse the row and column tree for (var i = 0; i < this.row; i++) {
        // Traverse the rows and create a tree on the node tr = document.createElement('tr');
 
        for (var j = 0; j < this.col; j++) {
            // Traverse the column and create a tree on the node td = document.createElement('td');
            // Append the node to the tree tr.appendChild(td);
 
 
            // Append the node to the tree this.dom.appendChild(tr);
 
        }
    }
    // Tree on the table document.getElementById('app').appendChild(this.dom);
}

Result:

2. Rendering the Snake’s Color

Logic for rendering snakes: The snake class calls the setColor method of the Game class, because the essence is to render the color of the table. The table is created when the Game class is initialized, so it is reasonable to let Game set the method for rendering the color.

// Method to set color Games.prototype.setColor = function (row, col, color) {
    // Set the color of the row and column of the table this.dom.getElementsByTagName('tr')[row].getElementsByTagName('td')[col].style.backgroundColor = color;
}

At this point we let the Snake class call the setColor method of game

Snake.prototype.render = function () {
    // Rendering of snake game.setColor(this.body[0].row, this.body[0].col, 'pink');
    // Snake body for (var i = 1; i < this.body.length; i++) {
        game.setColor(this.body[i].row, this.body[i].col, 'skyblue');
    }
}

At this point there is a question, who will call Snake's render? We can't get game by calling it in our Snake's own constructor, because the four steps of the Game class have not been executed yet, so it is now undefined

The solution is to call the timer, because the timer is asynchronous, so it will not prevent the four steps of the Game class from running.

    this.timer = setInterval(function () {
        // The core of the timer is the essence of game rendering, clear screen - update - render // Render snake game.snake.render();
    }, 20);

Result:

3. Snake Movement

The movement of the snake is actually the update of the body array. The essence is to delete the tail of the body array and add the head, so the snake will render the new state.

Snake.prototype.update = function () {
 
    // The current direction receives willdirection
    this.direction = this.willDirection;
    switch (this.direction) {
        case 'R':
            this.body.unshift({ 'row': this.body[0].row, 'col': this.body[0].col + 1 });
            break;
        case 'D':
            this.body.unshift({ 'row': this.body[0].row + 1, 'col': this.body[0].col });
            break;
        case 'L':
            this.body.unshift({ 'row': this.body[0].row, 'col': this.body[0].col - 1 });
            break;
        case 'T':
            this.body.unshift({ 'row': this.body[0].row - 1, 'col': this.body[0].col });
            break;
    }

At this point you will find that the snake will get longer and longer

Because we just told the snake how to render the color, we need to erase the previous rendering

We set a method to erase the screen for Game

// Clear the screen Games.prototype.clear = function () {
    for (var i = 0; i < this.row; i++) {
        for (var j = 0; j < this.col; j++) {
            this.dom.getElementsByTagName('tr')[i].getElementsByTagName('td')[j].style.backgroundColor = '#fff';
            this.dom.getElementsByTagName('tr')[i].getElementsByTagName('td')[j].innerHTML = '';
        }
    }
}

Next we will perform the three steps of the game in the timer: clear screen-update and render

 // Clear the screen game.clear();
        //Snake movement/update //Snake update speed When the snake side is longer, the speed increases var during = game.snake.body.length < 30 ? 30 - game.snake.body.length : 1;
        // Snake update game.f % during == 0 && game.snake.update();
        // Render the snake game.snake.render();

The snake moves in different directions. You can set a bindEvent event for Game to monitor keyboard events, change different directions, and determine that the up key cannot be pressed when the snake head moves downward.

Games.prototype.bindEvent = function () {
    var self = this;
    //Keyboard event document.onkeydown = function (even) {
        switch (even.keyCode) {
            case 37:
                // First judge, if the current direction is moving to the right, we cannot press the left button at this time if (self.snake.direction == 'R') return;
                self.snake.changeDirection('L');
                break;
            case 38:
                // First judge, if the current direction is moving downward, we cannot press the up key at this time if (self.snake.direction == 'D') return;
                self.snake.changeDirection('T');
                break;
            case 39:
                // First judge, if the current direction is moving to the left, we cannot press the right button at this time if (self.snake.direction == 'L') return;
                self.snake.changeDirection('R');
                break;
            case 40:
                // First judge, if the current direction is moving upward, we cannot press the key at this time if (self.snake.direction == 'T') return;
                self.snake.changeDirection('D');
                break;
        }
    }
}

At this time, the Snake class must also have a corresponding direction match. We set a this.direction='R' when initializing Snake.

Snake.prototype.update = function () {
 
    // The current direction receives willdirection
    this.direction = this.willDirection;
    switch (this.direction) {
        case 'R':
            this.body.unshift({ 'row': this.body[0].row, 'col': this.body[0].col + 1 });
            break;
        case 'D':
            this.body.unshift({ 'row': this.body[0].row + 1, 'col': this.body[0].col });
            break;
        case 'L':
            this.body.unshift({ 'row': this.body[0].row, 'col': this.body[0].col - 1 });
            break;
        case 'T':
            this.body.unshift({ 'row': this.body[0].row - 1, 'col': this.body[0].col });
            break;
    }

4. How to determine the death of a snake There are two ways to determine the death of a snake

The first is that the snake itself exceeds the table part

 // The part that exceeds the edge of the table if (this.body[0].col > game.col - 1 || this.body[0].row > game.row - 1 || this.body[0].col < 0 || this.body[0].row < 0) {
        alert('Game over, your current score is ' + game.score);
        clearInterval(game.timer);
        this.body.shift();
        clearInterval(game.timer);
    }

The second is that the snake itself overlaps with a part of its body.

  // hit itself for (var i = 1; i < this.body.length; i++) {
        if (this.body[0].col == this.body[i].col && this.body[0].row == this.body[i].row) {
            alert('Game over, your current score is ' + game.score);
            this.body.shift();
            clearInterval(game.timer);
        }
    }

5. Creation of Food

At this point we create a Food class to produce food, instantiate it in Game, and render it in a timer

When we randomly generate the row and col of food, we first check whether it is on the snake.

function Food(gameSnake) {
    var self = this;
    // Location of food // The do-while loop statement creates a row and col first and then determines whether the row and col are on the snake. do {
        this.row = parseInt(Math.random() * gameSnake.row);
        this.col = parseInt(Math.random() * gameSnake.col);
    } while ((function () {
        // Traverse the row and col of the snake and then compare them with the newly randomly generated row and col of Food to see if they overlap for (var i = 0; i < gameSnake.snake.body.length; i++) {
            if (gameSnake.snake.body[i].row == self.row && gameSnake.snake.body[i].col == self.col) {
                return true;
            }
 
        }
        return false;
    })())
 
    console.log(this.row, this.col);
}
 
Food.prototype.render = function () {
    game.setHTML(this.row, this.col, '♥');
}

6. The length of the food that snakes eat

When the snake moves, it will add an element to the head of the array body and delete an element at the tail. Therefore, after the snake head touches the food, we only need to keep the tail intact.

   if (this.body[0].row == game.food.row && this.body[0].col == game.food.col) {
        // Create new food game.food = new Food(game);
        // Return the frame number to 0
        // Add score game.score++;
        game.f = 0;
    } else {
        this.body.pop();
    }

Snakes eat food faster

We set a frame number that increments until it hits food, and then let the snake update faster as the snake's length increases.

         this.f = 0;
        game.f++;
       // Update speed of the snake. When the snake's side is longer, the speed increases var during = game.snake.body.length < 30 ? 30 - game.snake.body.length : 1;
        // Snake update game.f % during == 0 && game.snake.update();
        // Render the snake

7. Start Game Function

We just need to write a button in HTML and put it in the right place through positioning, give it a click event, and only after we click the start button will the code in Game be executed.

 <div id="app"></div>
    <div class="startgame"><img src="images/btn1.gif" alt=""></div>
    <div class="stopgame"><img src="images/btn4.png" alt=""></div>
    <script>
        var game = null;
        var btnstart = document.querySelector('.startgame');
        var btnstop = document.querySelector('.stopgame')
        btnstart.addEventListener('click', function () {
            btnstart.style.display = 'none';
            game = new Games();
            // console.log(table);
            var table = document.querySelector('table');
            table.addEventListener('click', function () {
                clearInterval(game.timer);
                btnstop.style.display = 'block';
            })

8. Pause/resume game function

We give a click event to both the pause button and the table. When we click on the table, the stop button appears and stops the timer in the Game. When we click on the pause button, the timer starts and hides itself.

     btnstop.addEventListener('click', function () {
                btnstop.style.display = 'none';
                game.timer = setInterval(function () {
                    // The core of the timer is the essence of game rendering, clear screen - update - render game.f++;
                    // document.getElementById('f').innerHTML = 'Frame number:' + game.f;
                    // // Render score // document.getElementById('score').innerHTML = 'Score:' + game.score;
                    // Clear the screen game.clear();
                    //Snake movement/update //Snake update speed When the snake side is longer, the speed increases var during = game.snake.body.length < 30 ? 30 - game.snake.body.length : 1;
                    // Snake update game.f % during == 0 && game.snake.update();
                    // Render the snake game.snake.render();
                    // Render food game.food.render();
                }, 10);
            })

This concludes this article about implementing the Snake game in JS. I hope it will be helpful for everyone’s study, and I also hope that everyone will support 123WORDPRESS.COM.

You may also be interested in:
  • JavaScript exquisite snake implementation process
  • JavaScript to achieve the idea of ​​​​snake game
  • JavaScript implementation of classic snake game
  • JS practical object-oriented snake game example

<<:  Summary of English names of Chinese fonts

>>:  SQL implementation of LeetCode (178. Score ranking)

Recommend

IIS configuration of win server 2019 server and simple publishing of website

1. First remotely connect to the server 2. Open S...

Two ways to build Docker images

Table of contents Update the image from an existi...

HTML left, center, right adaptive layout (using calc css expression)

In the latest HTML standard, there is a calc CSS e...

A brief introduction to MySQL storage engine

1. MySql Architecture Before introducing the stor...

Example code of vue icon selector

Source: http://www.ruoyi.vip/ import Vue from ...

Detailed explanation of how to use Node.js to implement hot reload page

Preface Not long ago, I combined browser-sync+gul...

Mysql 8.0.18 hash join test (recommended)

Hash Join Hash Join does not require any indexes ...

How to use nginx as a load balancer for mysql

Note: The nginx version must be 1.9 or above. Whe...

Linux installation MySQL5.6.24 usage instructions

Linux installation MySQL notes 1. Before installi...

Detailed explanation of 5 solutions for CSS intermediate adaptive layout

Preface When making a page, we often encounter co...

Detailed explanation of the middleman mode of Angular components

Table of contents 1. Middleman Model 2. Examples ...

Implementation of CSS sticky footer classic layout

What is a sticky footer layout? Our common web pa...

Native js to implement 2048 game

2048 mini game, for your reference, the specific ...

CSS multi-column layout solution

1. Fixed width + adaptive Expected effect: fixed ...