Hair loss snake

Page effect:

          The snake Game is developed in the intermediary mode. Our snake case is not written in an HTML file as before, but is divided into classes. A separate js represents each class, and the intermediary class is the Game class

        

1, Initialization structure

  First, we need to initialize the page. The initialization layout is not written directly into the html tag, but through the game to initialize the tree on the node

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

Games.prototype.init = function () {
    this.dom = document.createElement('table');
    var tr, td;
    //Traversing trees on rows and columns
    for (var i = 0; i < this.row; i++) {
        // Traverse the row 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 tree on node
            tr.appendChild(td);


            // Append tree on node
            this.dom.appendChild(tr);

        }
    }
    // Tree on table
    document.getElementById('app').appendChild(this.dom);
}

  Effect achieved:

2, Render the color of the snake  

          Logic of rendering snakes: snakes call the setColor method of Game class, because the essence is to render the color of table table, which is created in the initialization of Game class, so it is necessary to let Game set the method of rendering color

// How to set colors
Games.prototype.setColor = function (row, col, color) {
    // What color do you want the rows and columns of the table to set
    this.dom.getElementsByTagName('tr')[row].getElementsByTagName('td')[col].style.backgroundColor = color;
}

  At this point, let's ask the Snake class to call the setColor method of game

Snake.prototype.render = function () {
    //   Snake rendering
    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 time, there is a question: who will call snake's render? We can't call game in our Snake constructor, because the four part of the Game class has not been executed yet, and now it is undefined.

The solution is to call the timer. Because the timer is asynchronous, it will not prevent the four parts of the Game class from going

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

Effect achieved:  

3, Snake Movement

         The movement of the snake is actually that the snake is updating the body array. The essence is that the tail in the body array is deleted and the head is added, so the snake will render a 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 grow longer and longer

  Because we just told the snake how to render the color. We need to erase the previously rendered color

We set up a way for Game to erase the screen

// Clear 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 go through the three steps of the game in the timer: screen cleaning - update and rendering

 // Clear screen
        game.clear();
        // Snake Movement / update
        // Snake update speed when the snake side is long, 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 snake
        game.snake.render();

         If the snake moves in different directions, you can set a bindEvent event event for the Game, monitor keyboard events, change different directions, and judge that you can't press the key when the snake head moves downward

Games.prototype.bindEvent = function () {
    var self = this;
    // Keyboard events
    document.onkeydown = function (even) {
        switch (even.keyCode) {
            case 37:
                // Judge first. If the current direction is to move to the right, we can't press the left button at this time
                if (self.snake.direction == 'R') return;
                self.snake.changeDirection('L');
                break;
            case 38:
                // Judge first. If the current direction is moving downward, we can't press the up button at this time
                if (self.snake.direction == 'D') return;
                self.snake.changeDirection('T');
                break;
            case 39:
                // Judge first. If the current direction is to move to the left, we can't press the right button at this time
                if (self.snake.direction == 'L') return;
                self.snake.changeDirection('R');
                break;
            case 40:
                // Judge first. If the current direction is moving upward, we can't 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 corresponding direction matching. We set this.direction='R 'during Snake initialization

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, Determination of snake death

Snakes have two ways of judging death

The first is that the snake itself is beyond the table

 // Beyond 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 coincides with a part of the body

  // Hit yourself
    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 generate Food, instantiate it in Game and render it in timer

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

function Food(gameSnake) {
    var self = this;
    //    Location of food
    // The do while loop statement is used to create a row and col first, and then judge 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 snake's row and col, and then judge whether they coincide with the new random row and col from Food
        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, Snakes eat long food

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

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

Snakes eat food faster

         We set a frame number to increase automatically before touching the food, and then let the update speed of the snake increase with the length of the snake

         this.f = 0;
        game.f++;
       // Snake update speed when the snake side is long, 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 snake

7, Start game function

         We just need to write a button in html, and then locate it in the appropriate place to give it a click event. Only after we click the start button can we execute the code in Game

 <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 the pause button and table. When we click the table, the stop button appears and stops the timer in the Game. When we click the pause button, we start the timer and hide it

     btnstop.addEventListener('click', function () {
                btnstop.style.display = 'none';
                game.timer = setInterval(function () {
                    // The core of the timer is the rendering essence of the game, clear screen - Update - rendering
                    game.f++;
                    // document.getElementById('f').innerHTML =' frame No.: '+ game.f;
                    // //Render score
                    // document.getElementById('score').innerHTML =' Score: '+ game.score;
                    // Clear screen
                    game.clear();
                    // Snake Movement / update
                    // Snake update speed when the snake side is long, 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 snake
                    game.snake.render();
                    // Render food
                    game.food.render();
                }, 10);
            })

Summary:

          I was in my hometown without Internet or WIFI. In order to write this article, I set out at dawn. I walked dozens of kilometers to the town. Many bean sized blisters were worn on my feet and my shoes were glued. Originally, I wanted to sell dozens of kilograms of corn at home and take a car in the town to the Internet cafe in the city to write this article. However, the weather is not beautiful. This year's harvest is bad and the grain planted is only enough for my family, so I had to work in the brick kiln in the town to earn enough travel expenses. I only gave a penny to move a brick from the brick kiln to the tractor. For a fare of 100 yuan, I moved 10000 bricks, and ten fingers were worn out of blood. In order to save the car fare, I didn't stick Yunnan Baiyao band aid to let the blood coagulate naturally. Then I got the brick money and got on the bus from town to the city. When I came to the Internet cafe, I felt in my pocket. I didn't have three yuan for Internet access. I moved 300 bricks less. I had to run around the street and watch the people who drank mineral water. When they threw the mineral water bottle out of their hands, I rushed like a goalkeeper, afraid that the mineral water bottle would be robbed by others. Because in that case, I will write this article for a few seconds at night. Do you understand my eagerness? After many hardships, I finally collected 60 precious mineral water bottles. I wanted to get the waste purchase station and changed the Internet fee of 3 yuan. However, the waste purchase station was in the suburbs, very far from the Internet cafe. I had no extra money to take a bus. I could only trek for six hours and go in the dark. Back to the Internet cafe, the sky has gradually brightened, and finally wrote this article.  

                                           

Tags: Javascript Front-end

Posted on Sun, 21 Nov 2021 20:02:26 -0500 by hairyjim