VUE+Canvas implements the game of God of Wealth receiving ingots

VUE+Canvas implements the game of God of Wealth receiving ingots

Welcome to the previous canvas game series:

《VUE implements a Flappy Bird~~~》

Guess the Word Game

《VUE+Canvas realizes desktop pinball brick-breaking game》

《VUE+Canvas implements a typing game of Thunder Fighter》

As the title suggests, everyone has played this game and it can be seen everywhere. Use the left and right direction keys to control the movement of the God of Wealth and catch the gold ingots falling from the sky. When the time is up, the game ends. Let’s take a look at the effect first:

Compared to the previous Thunder Fighter that fired bullets flying everywhere, the movement trajectory of the elements this time is very simple, with vertical jewels and horizontally moving God of Wealth. Similar to the previous code, here are the key steps:

1. The God of Wealth moves horizontally with keyboard control

This is very simple, similar to the control of the slider in "VUE+Canvas to realize the desktop pinball brick elimination game":

drawCaishen() {
      let _this = this;
      _this.ctx.save();
      _this.ctx.drawImage(
        _this.caishenImg,
        _this.caishen.x,
        _this.caishen.y,
        120,
        120
      );
      _this.ctx.restore();
},
moveCaishen() {
      this.caishen.x += this.caishen.dx;
      if (this.caishen.x > this.clientWidth - 120) {
        this.caishen.x = this.clientWidth - 120;
      } else if (this.caishen.x < 0) {
        this.caishen.x = 0;
      }
}

2. Jewels that fall from the sky

This is also very simple, but it should be noted that the initial x value of the jewels cannot be randomly taken from 0 to clientWidth, because it is easy to cause the jewels to pile up together, affecting the playability of the game, so the jewels are best scattered on different tracks. Here we divide the canvas width into 5 tracks. When the jewels are initially drawn, we scatter them on the track, and the y value is randomly set at a certain height to create a staggered appearance. Then the newly generated jewels are generated according to the track distribution to avoid the jewels being crowded together.

generateTreasure() {
      let _this = this;
      if (_this.treasureArr.length < MaxNum) {
        let random = Math.floor(Math.random() * TreasureNames.length);
        let channel = _this.getRandomArbitrary(1, 5);
        _this.treasureArr.push({
          x: _this.channelWidth * (1 / 2 + (channel - 1)) - 30,
          y: 0,
          name: TreasureNames[random],
          speed: _this.getRandomArbitrary(2, 4)
        });
      }
},
filterTreasure(item) {
      let _this = this;
      if (
        item.x <= _this.caishen.x + 110 &&
        item.x >= _this.caishen.x &&
        item.y > _this.caishen.y
      ) {
        // Determine the touching range with the God of Wealth_this.score += _this.treasureObj[item.name].score;
        return false;
      }
      if (item.y >= _this.clientHeight) {
        return false;
      }
      return true;
},
drawTreasure() {
      let _this = this;
      _this.treasureArr = _this.treasureArr.filter(_this.filterTreasure);
      _this.treasureArr.forEach(item => {
        _this.ctx.drawImage(
          _this.treasureObj[item.name].src,
          item.x,
          item.y,
          60,
          60
        );
        item.y += item.speed;
      });
},
getRandomArbitrary(min, max) {
      return Math.random() * (max - min) + min;
}

Here we use the filter function to filter out the jewels that should disappear. If we use the for+splice+i-- method, it will cause jitter.

Then give each jewel a random movement speed, and when the jewel enters the picture range of the God of Wealth, the corresponding score is accumulated.

3. Countdown ring

Set the countdown to 30s. Then in the requestAnimationFrame callback, calculate whether the difference in milliseconds between the current time and the last timestamp is greater than 1000 to calculate the seconds. Then take another timestamp to accumulate progress to achieve smooth movement of the ring.

drawCountDown() {
      // Draw the progress ring let _this = this;
      _this.progress += Date.now() - _this.timeTag2;
      _this.timeTag2 = Date.now();
      _this.ctx.beginPath();
      _this.ctx.moveTo(50, 50);
      _this.ctx.arc(
        50,
        50,
        40,
        Math.PI * 1.5,
        Math.PI * (1.5 + 2 * (_this.progress / (countDownInit * 1000))),
        false
      );
      _this.ctx.closePath();
      _this.ctx.fillStyle = "yellow";
      _this.ctx.fill();
 
      // Draw a filled circle_this.ctx.beginPath();
      _this.ctx.arc(50, 50, 30, 0, Math.PI * 2);
      _this.ctx.closePath();
      _this.ctx.fillStyle = "#fff";
      _this.ctx.fill();
 
      //Fill text_this.ctx.font = "bold 16px Microsoft YaHei";
      _this.ctx.fillStyle = "#333";
      _this.ctx.textAlign = "center";
      _this.ctx.textBaseline = "middle";
      _this.ctx.moveTo(50, 50);
      _this.ctx.fillText(_this.countDown + "s", 50, 50);
    }
(function animloop() {
        _this.ctx.clearRect(0, 0, _this.clientWidth, _this.clientHeight);
        _this.loop();
        animationId = window.requestAnimationFrame(animloop);
        if (_this.countDown === 0) {
          _this.gameOver = true;
          window.cancelAnimationFrame(animationId);
        }
        if (Date.now() - _this.timeTag >= 1000) {
          _this.countDown--;
          _this.timeTag = Date.now();
        }
})();

At this point, a very simple game of the God of Wealth catching gold ingots has been completed. Of course, in order to increase the difficulty, you can set up a segment of dropping bombs continuously. The principle is the same as the movement of jewels.

The following is the full code for your reference:

<template>
  <div class="caishen">
    <canvas id="caishen" width="1200" height="750"></canvas>
    <div class="container" v-if="gameOver">
      <div class="dialog">
        <p class="once-again">Congratulations! </p>
        <p class="once-again">Treasures in this round: {{ score }} points</p>
      </div>
    </div>
  </div>
</template>
 
<script>
const TreasureNames = [
  "yuanbao",
  "tongqian",
  "jintiao",
  "shuijin_red",
  "shuijin_blue",
  "fudai"
];
let animationId = null;
let countDownInit = 0;
const MaxNum = 5;
export default {
  name: "CaiShen",
  data() {
    return {
      score: 0,
      ctx: null,
      caishenImg: null,
      clientWidth: 0,
      clientHeight: 0,
      channelWidth: 0,
      caishen:
        x: 0,
        y: 0,
        speed: 8,
        dx: 0
      },
      progress: 0,
      countDown: 30,
      timeTag: Date.now(),
      timeTag2: Date.now(),
      treasureArr: [],
      gameOver: false,
      treasureObj: {
        yuanbao:
          score: 5,
          src: null
        },
        Tongqian:
          score: 2,
          src: null
        },
        jintiao:
          score: 10,
          src: null
        },
        shuijin_red:
          score: 20,
          src: null
        },
        shuijin_blue: {
          score: 15,
          src: null
        },
        fudai:
          score: 8,
          src: null
        }
      }
    };
  },
  mounted() {
    let _this = this;
    let container = document.getElementById("caishen");
    _this.ctx = container.getContext("2d");
    _this.clientWidth = container.width;
    _this.clientHeight = container.height;
    _this.channelWidth = Math.floor(_this.clientWidth / 5);
    _this.caishenImg = new Image();
    _this.caishenImg.src = require("@/assets/img/caishen/财神爷.png");
 
    _this.initTreasures();
    countDownInit = _this.countDown;
    _this.caishen.x = _this.clientWidth / 2 - 60;
    _this.caishen.y = _this.clientHeight - 120;
    document.onkeydown = function(e) {
      let key = window.event.keyCode;
      if (key === 37) {
        //Left button_this.caishen.dx = -_this.caishen.speed;
      } else if (key === 39) {
        //Right button_this.caishen.dx = _this.caishen.speed;
      }
    };
    document.onkeyup = function(e) {
      _this.caishen.dx = 0;
    };
    _this.caishenImg.onload = function() {
      (function animloop() {
        _this.ctx.clearRect(0, 0, _this.clientWidth, _this.clientHeight);
        _this.loop();
        animationId = window.requestAnimationFrame(animloop);
        if (_this.countDown === 0) {
          _this.gameOver = true;
          window.cancelAnimationFrame(animationId);
        }
        if (Date.now() - _this.timeTag >= 1000) {
          _this.countDown--;
          _this.timeTag = Date.now();
        }
      })();
    };
  },
  methods: {
    initTreasures() {
      let _this = this;
      Object.keys(_this.treasureObj).forEach(key => {
        _this.treasureObj[key].src = new Image();
        _this.treasureObj[
          key
        ].src.src = require(`@/assets/img/caishen/${key}.png`);
      });
      for (let i = 0; i < MaxNum; i++) {
        let random = Math.floor(Math.random() * TreasureNames.length);
        _this.treasureArr.push({
          x: _this.channelWidth * (1 / 2 + i) - 30,
          y: _this.getRandomArbitrary(0, 20),
          name: TreasureNames[random],
          speed: _this.getRandomArbitrary(2, 4)
        });
      }
    },
    loop() {
      let _this = this;
      _this.drawCountDown();
      _this.drawCaishen();
      _this.moveCaishen();
      _this.generateTreasure();
      _this.drawTreasure();
      _this.drawScore();
    },
    drawCaishen() {
      let _this = this;
      _this.ctx.save();
      _this.ctx.drawImage(
        _this.caishenImg,
        _this.caishen.x,
        _this.caishen.y,
        120,
        120
      );
      _this.ctx.restore();
    },
    moveCaishen() {
      this.caishen.x += this.caishen.dx;
      if (this.caishen.x > this.clientWidth - 120) {
        this.caishen.x = this.clientWidth - 120;
      } else if (this.caishen.x < 0) {
        this.caishen.x = 0;
      }
    },
    drawScore() {
      let _this = this;
      _this.ctx.beginPath();
      _this.ctx.fillStyle = "#fff";
      _this.ctx.textAlign = "center";
      _this.ctx.textBaseline = "middle";
      _this.ctx.fillText(_this.score + "分", 30, _this.clientHeight - 10);
      _this.ctx.closePath();
    },
    drawCountDown() {
      // Draw the progress ring let _this = this;
      _this.progress += Date.now() - _this.timeTag2;
      _this.timeTag2 = Date.now();
      _this.ctx.beginPath();
      _this.ctx.moveTo(50, 50);
      _this.ctx.arc(
        50,
        50,
        40,
        Math.PI * 1.5,
        Math.PI * (1.5 + 2 * (_this.progress / (countDownInit * 1000))),
        false
      );
      _this.ctx.closePath();
      _this.ctx.fillStyle = "yellow";
      _this.ctx.fill();
 
      // Draw a filled circle_this.ctx.beginPath();
      _this.ctx.arc(50, 50, 30, 0, Math.PI * 2);
      _this.ctx.closePath();
      _this.ctx.fillStyle = "#fff";
      _this.ctx.fill();
 
      //Fill text_this.ctx.font = "bold 16px Microsoft YaHei";
      _this.ctx.fillStyle = "#333";
      _this.ctx.textAlign = "center";
      _this.ctx.textBaseline = "middle";
      _this.ctx.moveTo(50, 50);
      _this.ctx.fillText(_this.countDown + "s", 50, 50);
    },
    filterTreasure(item) {
      let _this = this;
      if (
        item.x <= _this.caishen.x + 110 &&
        item.x >= _this.caishen.x &&
        item.y > _this.caishen.y
      ) {
        // Determine the touching range with the God of Wealth_this.score += _this.treasureObj[item.name].score;
        return false;
      }
      if (item.y >= _this.clientHeight) {
        return false;
      }
      return true;
    },
    drawTreasure() {
      let _this = this;
      _this.treasureArr = _this.treasureArr.filter(_this.filterTreasure);
      _this.treasureArr.forEach(item => {
        _this.ctx.drawImage(
          _this.treasureObj[item.name].src,
          item.x,
          item.y,
          60,
          60
        );
        item.y += item.speed;
      });
    },
    getRandomArbitrary(min, max) {
      return Math.random() * (max - min) + min;
    },
    generateTreasure() {
      let _this = this;
      if (_this.treasureArr.length < MaxNum) {
        let random = Math.floor(Math.random() * TreasureNames.length);
        let channel = _this.getRandomArbitrary(1, 5);
        _this.treasureArr.push({
          x: _this.channelWidth * (1 / 2 + (channel - 1)) - 30,
          y: 0,
          name: TreasureNames[random],
          speed: _this.getRandomArbitrary(2, 4)
        });
      }
    }
  }
};
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
#caishen
  background-color: #b00600;
  background-image: url("~assets/img/caishen/brick-wall.png");
}
.container {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.3);
  text-align: center;
  font-size: 0;
  white-space: nowrap;
  overflow:auto;
}
.container:after {
  content: "";
  display: inline-block;
  height: 100%;
  vertical-align: middle;
}
.dialog {
  width: 400px;
  height: 300px;
  background: rgba(255, 255, 255, 0.5);
  box-shadow: 3px 3px 6px 3px rgba(0, 0, 0, 0.3);
  display: inline-block;
  vertical-align: middle;
  text-align: left;
  font-size: 28px;
  color: #fff;
  font-weight: 600;
  border-radius: 10px;
  white-space: normal;
  text-align: center;
  .once-again-btn {
    background: #1f9a9a;
    border: none;
    color: #fff;
  }
}
</style>

This is the end of this article about VUE+Canvas realizing the God of Wealth receiving ingots game. For more relevant Vue receiving ingots game content, please search 123WORDPRESS.COM's previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Vue uses Canvas to generate random sized and non-overlapping circles
  • Vue uses canvas to realize image compression upload
  • How to draw the timeline with vue+canvas
  • VUE+Canvas realizes the whole process of a simple Gobang game
  • How to use VUE and Canvas to implement a Thunder Fighter typing game
  • VUE+Canvas implements the sample code of the desktop pinball brick-breaking game
  • Vue uses the mouse to draw a rectangle on Canvas
  • Vue uses canvas to implement mobile handwritten signature
  • Vue+canvas realizes puzzle game
  • Vue uses canvas handwriting input to recognize Chinese

<<:  Code analysis of user variables in mysql query statements

>>:  Linux CentOS6.9 installation graphic tutorial under VMware

Recommend

MySQL data backup and restore sample code

1. Data backup 1. Use mysqldump command to back u...

Detailed explanation of Mysql's concurrent parameter adjustment

Table of contents Query cache optimization Overvi...

How to install Nginx and configure multiple domain names

Nginx Installation CentOS 6.x yum does not have n...

How to set the page you are viewing to not allow Baidu to save its snapshot

Today, when I searched for a page on Baidu, becaus...

How to use async and await in JS

Table of contents 1. async 2. await: 3. Comprehen...

MySQL 5.7 installation and configuration tutorial under CentOS7 64 bit

Installation environment: CentOS7 64-bit MINI ver...

How to configure the My.ini file when installing MySQL5.6.17 database

I recently used the MySql database when developin...

How to insert video into HTML and make it compatible with all browsers

There are two most commonly used methods to insert...

How to implement n-grid layout in CSS

Common application scenarios The interfaces of cu...

One line of code teaches you how to hide Linux processes

Friends always ask me how to hide Linux processes...

Vue example code using transition component animation effect

Transition document address defines a background ...

Detailed explanation of nginx configuration file interpretation

The nginx configuration file is mainly divided in...