VUE implements a Flappy Bird game sample code

VUE implements a Flappy Bird game sample code

Flappy Bird is a very simple little game that everyone has played on the app. Here we use VUE to implement a simple PC version of Flappy Bird for entertainment~~~~~

To realize this game, let's first analyze which parts of the game interface need to be animated:

1. The first one is of course the bird that moves up and down;

2. A horizontally moving background image makes the bird appear to be flying horizontally;

3. Rows of pipes entering from the right side of the screen.

This is very clear. We make the above three parts move according to the rules, and then add rule boundary judgment and scoring, and we can get a complete game. So let’s solve it piece by piece.

Let's first define some constants and variables:

let rafId = null; // requestAnimationFrame ID
let startSpeed ​​= 1;
const SPEED = 0.04; // acceleration const UP = 5.0; // upper limit of speed accumulation const UP_SUM = 30; // height of one jump const BIRD_WIDTH = 50; // bird picture width 50px
const PIPE_DISTANCE = 350; // Horizontal distance between pipes let id = 0; // Unique id of the pipe, counting starts from 0...
 
data() {
    return {
      start: false,
      clientWidth: 0,
      clientHeight: 0,
      spaceHeight: [240, 200, 160], // The distance between the upper pipe and the lower pipepipeArr: [], // Pipe arrayscore: 0, // ScorejumpSum: 0, // Current jump relative heightjumpFlag: false, // true-press the space bar to jump in the ascending stage; false-free fall stagedropBirdImg: require("@/assets/img/bird/bird0_0.png"),
      flyBirdImg: require("@/assets/img/bird/bird0_2.png"),
      gameOver: false, // flag indicating game failure, used to stop animation frames};
},

1. Birds that move up and down

In order to control the position of the bird and the pipe respectively, the elements are positioned using position: absolute

The bird itself is a div + background image, and then define its initial position in the interface:

<div class="bird" id="bird" ref="bird"></div>
 
 #bird {
      height: 50px;
      width: 50px;
      border-radius: 50%;
      background: url("~assets/img/bird/bird0_1.png") no-repeat center/contain;
      // Initial position of the bird position: absolute;
      left: 300px;
      top: 300px;
}

Then, without any operation, the bird starts to "fall" from its initial position. The bird falls faster and faster. Here I did not use the physical formula of gravity acceleration, but simply simulated a curve acceleration process. This is a continuous animation, so put this action in the animation frame, that is, requestAnimationFrame, and the function of each frame is defined as loop().

Therefore, in the loop function, offsetTop and the clientHeight of the parent element are used to determine whether the bird has touched the upper and lower boundaries of the screen. If so, the game ends; if not, style.top is increased to make the bird fall.

loop() {
      let _this = this;
      if (_this.jumpFlag) {
        // The bird jumps_this.jump();
      }
      let top = _this.$refs.bird.offsetTop;
      if (top > _this.clientHeight - BIRD_WIDTH || top <= 0) {
        //Hit the border, the game ends_this.resetGame();
      } else if (!_this.jumpFlag) {
        _this.$refs.bird.style.background = `url('${_this.dropBirdImg}') no-repeat center/contain`;
        _this.$refs.bird.style.top = top + startSpeed ​​* startSpeed ​​+ "px"; // Simulate accelerated fall if (startSpeed ​​< UP) {
          startSpeed ​​+= SPEED;
        }
      }
      _this.pipesMove(); // Pipeline movement}

In the game, when the player presses the space bar, the bird will jump up a certain distance. This state is recorded using this.jumpFlag[true/false]. When pressed, it is set to true. In the loop function, the bird jumps(). After jumping to a certain distance, jumpFlag is set to false and the bird begins to fall.

Therefore, the jump function is easy to implement:

jump() {
      let _this = this;
      _this.$refs.bird.style.background = `url('${_this.flyBirdImg}') no-repeat center/contain`;
      if (_this.jumpSum > UP_SUM) {
        // Fall down when reaching the top_this.jumpFlag = false;
        _this.jumpSum = 0;
        startSpeed ​​= 1;
      } else {
        _this.$refs.bird.style.top = _this.$refs.bird.offsetTop - 8 + "px";
        _this.jumpSum += 8;
      }
}

2. Background image that moves horizontally

This is relatively simple. Just switch background-position in an infinite loop. The position is determined by the width of the background image material you downloaded.

animation: bgMove 8s linear infinite;
      @keyframes bgMove {
        0% {
          background-position: 805px 0;
        }
        100% {
          background-position: 0 0;
        }
}

After these two steps, we can get a flying bird. Use document.onkeydown to listen to the space bar to switch jumpFlag, as shown below:

3. Move from right to left and enter the pipe

The pipeline is composed of two divs, each of which has a gap in the middle through different top: -xx and bottom: -yy.

First, implement a function to generate a random gap pipe, which is stored in the pipeArr object array:

addPipe(id) {
      let obj = {};
      let top_num = this.sum(10, 170);
      let height = this.spaceHeight[
        Math.floor(Math.random() * this.spaceHeight.length)
      ]; // Randomly select gap value let bottom_num = height - top_num;
      obj.top = top_num;
      obj.id = id;
      obj.right = -(PIPE_DISTANCE / 2);
      obj.bottom = bottom_num;
      this.pipeArr.push(obj);
},
sum(m, n) {
      // Random numbers between nm return Math.floor(Math.random() * (m - n) + n);
}

Then we need to move the pipe, that is, the pipe moving function pipesMove() in loop(). The whole function is implemented as follows:

pipesMove() {
      let _this = this;
      if (_this.pipeArr.length === 0) {
        return;
      }
      let right0 = _this.pipeArr[0].right;
      if (right0 > this.clientWidth + 300) {
        this.pipeArr.shift();
      }
      let right_last = _this.pipeArr[_this.pipeArr.length - 1].right;
      if (right_last >= PIPE_DISTANCE / 2) {
        id++;
        this.addPipe(id);
      }
      for (let i = 0; i < _this.pipeArr.length; i++) {
        // Determine whether the bird has touched the pipe. The bird is 50*50, left: 300px; the pipe is 100px wide; the pipe entry range right is width-450 to width-300
        if (
          _this.pipeArr[i].right >= _this.clientWidth - 450 &&
          _this.pipeArr[i].right <= _this.clientWidth - 300
        ) {
          // The pipe has entered the bird's touch range let bird_top = _this.$refs.bird.offsetTop;
          // 12 is the bird image material with blank spaces above and below if (
            bird_top <= _this.clientHeight / 2 - _this.pipeArr[i].top - 12 ||
            bird_top >=
              _this.clientHeight / 2 + _this.pipeArr[i].bottom - BIRD_WIDTH + 12
          ) {
            // hit the pipe_this.resetGame();
            return;
          }
        }
        if (_this.pipeArr[i].right === _this.clientWidth - 300 && _this.pipeArr[i].right === _this.clientWidth - 301) { // When a pipe is just to the left of the bird, it proves that the bird has passed through the pipe. Calculate the bird's score based on the pipe id _this.score = _this.pipeArr[i].id + 1;
        }
        _this.pipeArr[i].right = _this.pipeArr[i].right + 2; // The pipe moves 2px per frame
      }
}

Five things are done here:

(1) After the pipe leaves the left screen, shift() the leftmost pipe;

(2) After the rightmost pipe is a certain distance away from the right side of the screen, a new pipe is added;

(3) During the loop, determine whether the bird has entered the range of a certain pipe and whether the bird's top touches the upper and lower pipes. If it does, the game loses.

(4) If a pipe is located on the left side of the bird, it means the bird has successfully passed through and the score is +1.

(5) Each channel moves 2px pixels, and the value is recorded in the right attribute.

By setting right in DOM:style, the pipe can be moved horizontally.

<section class="pipes-wrap" ref="pipes">
          <div
            class="pipe-item"
            v-for="(item, index) in pipeArr"
            :key="item.id"
            :id="'pipe' + index"
            :style="'right:' + item.right + 'px;'"
          >
            <div
              class="pipe pipe-top"
              :style="'top:-' + item.top + 'px;'"
            ></div>
            <div
              class="pipe pipe-bottom"
              :style="'bottom:-' + item.bottom + 'px;'"
            ></div>
          </div>
</section>
 
.pipes-wrap {
        position: relative;
        height: 100%;
        overflow: hidden;
        .pipe-item {
          position: absolute;
          height: 100%;
          width: 100px;
          .pipe {
            width: 100%;
            height: 50%;
            position: relative;
          }
          .pipe-top {
            background: url('"~assets/img/bird/pipe_down.png') no-repeat;
            background-size: 100px;
            background-position: bottom;
          }
          .pipe-bottom {
            background: url('"~assets/img/bird/pipe_up.png') no-repeat;
            background-size: 100px;
            background-position: top;
          }
        }
} 

The above is the idea and core code of Vue's implementation of Flappy Bird, with a total of more than 200 lines of code. In my opinion, the difficulty lies mainly in the movement of the pipes, touch determination and score calculation. Of course, there are still many shortcomings in the code that can be optimized. Let's encourage each other~~

You may also be interested in:
  • Pure JavaScript to implement flappy bird game example code
  • C++ version of simple Flappy bird
  • C language simplified version of flappy bird game
  • Python implements Flappy Bird source code
  • Implementing flappy bird game in C language
  • Unity implements Flappy Bird game development practice
  • Java implementation of Flappy Bird game source code
  • Implementing Flappy Bird game in C language
  • Use pygame to write Flappy bird game
  • Pygame object-oriented flying bird implementation (Flappy bird)

<<:  How to add custom system services to CentOS7 systemd

>>:  Detailed explanation of the implementation process of dual-master synchronization of partial tables in MySQL 5.7

Recommend

VMware15/16 Detailed steps to unlock VMware and install MacOS

VMware version: VMware-workstation-full-16 VMware...

Windows cannot start MySQL service and reports error 1067 solution

Suddenly when I logged into MySQL, it said that a...

Linux Network System Introduction

Table of contents Network Information Modify the ...

Detailed explanation of jQuery chain calls

Table of contents Chain calls A small case Chain ...

Detailed steps for installing MySQL using cluster rpm

Install MySQL database a) Download the MySQL sour...

Graphic tutorial on installing Ubuntu 18.04 on VMware 15 virtual machine

In the past few years, I have been moving back an...

Using CSS to implement loading animation of Android system

There are two common loading icons on the web, on...

Advantages and disadvantages of common MySQL storage engines

Table of contents View all storage engines InnoDB...

Mysql implements null value first/last method example

Preface We already know that MySQL uses the SQL S...

SQL fuzzy query report: ORA-00909: invalid number of parameters solution

When using Oracle database for fuzzy query, The c...

Detailed explanation of the available environment variables in Docker Compose

Several parts of Compose deal with environment va...

MySQL 8.0.12 Installation and Configuration Tutorial

This article records the detailed tutorial for in...

How to implement the strategy pattern in Javascript

Table of contents Overview Code Implementation Su...

How to query the intersection of time periods in Mysql

Mysql query time period intersection Usage scenar...