“This is the third day of my participation in the First Challenge 2022. For details: First Challenge 2022”


I’ll put the 0 out front

Red envelopes, also known as lucky money, are gifts of money wrapped in red paper given to children during the Lunar New Year. It is said that during the Ming and Qing dynasties, lucky money was mostly given to children with red strings. After the Republic of China, it evolved to be wrapped in red paper. Traditional Chinese red envelope culture in the folk, communities, companies also follow such rites. Apart from the Spring Festival, it is also customary to give red envelopes on other happy occasions, such as weddings and new store openings.

In this issue, we created a red envelope rain game with code, as shown below. After reading this article, I believe you can also complete such a small game design.

1 Preparations

Build the project using Vue. The process for

  1. vue init webpack vue-demo
  2. cd vue-demo
  3. cnpm install # npm install

Download some festive pictures from the Internet as the background and red envelope style, these styles can be selected, to the students who want to live fully enough freedom.

Design HTML+CSS styles

The HTML style is very simple, mainly divided into two parts: red envelope rain and grab red envelope panel.

<! -- Rain of red envelopes -->
<div id="wrapper"></div>

<! -- Grab red envelope panel -->
<div id="panel">
	<div id="hb">
    	<span id="text">{{ result }}</span>
        <div id="btn" @click="gameOn">Continue to grab red envelopes</div>
    </div>
</div>
Copy the code

CSS styles are slightly more complex and are presented in the complete code below. One of the least used is the Annimation animation rendering style

animation: dropDowm 3s forwards; /* Rotate animation */
@keyframes dropDowm {
  0% {
    top: 0px;
    transform: translateY(-100%) rotate(0deg);
  }
  100% {
    top: 110%;
    transform: translateY(0%) rotate(360deg); }}Copy the code

Here, the common parameters of Annimation are as follows:

  • Animation-name: indicates the animation name of the keyframe
  • Animation-duration: animation execution time
  • Animation-timing -function: animation speed function
  • Animation-delay: indicates the animation delay time
  • Animation-rotund-count: number of animation executions
  • Animation-direction: indicates the animation execution directionalternate(Interval movement),reverse(Reverse motion),reverse-alternate(Reverse interval motion)
  • Animation-fill-mode: Specifies the style to be applied to an element when the animation does not play (when the animation is complete, or when the animation has a delay before it starts playing), containingforwards(Animation stops at the position of last keyframe),backwards(the first key frame of the animation executes immediately),both(The first keyframe also stops at the last keyframe)

After the design is completed, the running results are shown in the figure below, which are background and panel respectively.

Design JavaScript logic

The logic of the program is shown below

Graph TD A[start] --> B B --> C{ } C - - - > D (display the amount of the grab) C - n - > E (continue) D - > F {red envelopes to set number? } E -->F{Does the number of red packets reach the set value? } F -- yes --> G(display game results) F -- no --> B

The most critical thing above is to monitor the user’s behavior of grabbing red envelopes and judge whether they have grabbed red envelopes. The design of the monitoring function is as follows. If the red envelopes are successfully grabbed, the total amount will be automatically accumulated.

mouseHandler(e) {
      var event = e || window.event,
        money = event.target.dataset.money;
      if (money) {
        this.result = "Congratulations on getting the red envelope." + money + "Yuan";
        for (var i = 0, len = this.imgList.length; i < len; i++) {
          this.imgList[i].style.animationPlayState = "paused";
        }
        panel.style.display = "block";
        this.totalMoney += Number(money); }}Copy the code

Next, we need to consider how to let the red envelope randomly drop, the core code is as follows:

 for (var i = 0; i < num; i++) {
        let img = new Image();
        img.src = this.imgUrl;
        // Randomly set the distribution of red packets
        img.style.left = this.ranNum(0.window.innerWidth) + "px";
        let delay = this.ranNum(0.100) / 10;
        // Set the red envelope time
        img.style.animationDelay = delay + "s";
        if (this.delayTime < delay) {
          this.delayTime = delay;
          this.lastImg = img;
        }
        // Set the amount of each red envelope
        img.dataset.money = this.ranNum(0.1000) / 100;
Copy the code

The other functions basically serve these two core functions, so I won’t go into details here.

4 Complete Code

<template>
  <div id="app">
    <! -- Rain of red envelopes -->
    <div id="wrapper"></div>
    <! -- Grab red envelope panel -->
    <div id="panel">
      <div id="hb">
        <span id="text">{{ result }}</span>
        <div id="btn" @click="gameOn">Continue to grab red envelopes</div>
      </div>
    </div>
  </div>
</template>
Copy the code
<script>
export default {
  name: "App".data() {
    return {
      totalMoney: 0.// The total amount of the red packets
      delayTime: 0./ / delay
      lastImg: null.// The last dropped image
      imgList: null.// A random sequence of red packets
      result: "".// Game results
      imgUrl: require("./assets/hongbao.jpg"),}; },methods: {
    // @breif: Start the game
    start() {
      let dom = this.createDom(20);
      this.imgList = document.getElementsByTagName("img");
      document.getElementById("wrapper").appendChild(dom);
    },
    // @breif: Create a red envelope sequence
    createDom(num) {
      // Create a document fragment
      let frag = document.createDocumentFragment();
      for (var i = 0; i < num; i++) {
        let img = new Image();
        img.src = this.imgUrl;
        // Randomly set the distribution of red packets
        img.style.left = this.ranNum(0.window.innerWidth) + "px";
        let delay = this.ranNum(0.100) / 10;
        // Set the red envelope time
        img.style.animationDelay = delay + "s";
        if (this.delayTime < delay) {
          this.delayTime = delay;
          this.lastImg = img;
        }
        // Set the amount of each red envelope
        img.dataset.money = this.ranNum(0.1000) / 100;
        frag.appendChild(img);
      }
      return frag;
    },
    // @breif: Keep playing
    gameOn() {
      document.getElementById("panel").style.display = "none";
      for (let i = 0, len = this.imgList.length; i < len; i++) {
        this.imgList[i].style.animationPlayState = "running"; }},// Listen for mouse events
    mouseHandler(e) {
      var event = e || window.event,
        money = event.target.dataset.money;
      if (money) {
        this.result = "Congratulations on getting the red envelope." + money + "Yuan";
        for (var i = 0, len = this.imgList.length; i < len; i++) {
          this.imgList[i].style.animationPlayState = "paused";
        }
        panel.style.display = "block";
        this.totalMoney += Number(money); }},// Listen for animation events
    annimationHandler(e) {
      document.getElementById("panel").style.display = "block";
      this.result = "Congratulations on the total." + this.totalMoney.toFixed(2) + "Yuan";
    },

    // @breif: generates random numbers between min and Max
    ranNum(min, max) {
      return Math.ceil(Math.random() * (max - min) + min); }},mounted() {
    this.start();
    window.addEventListener("mousedown".this.mouseHandler);
    this.lastImg.addEventListener("webkitAnimationEnd".this.annimationHandler); }}; </script>Copy the code
<style>
* {
  padding: 0;
  margin: 0;
}

body {
  height: 100%;
  width: 100%;
  background: url("./assets/background.jpg");
  background-size: cover;
  overflow: hidden;
}

#wrapper img {
  position: absolute;
  transform: translateY(-100%); /* Drop animation */
  animation: dropDowm 3s forwards; /* Rotate animation */
}
@keyframes dropDowm {
  0% {
    top: 0px;
    transform: translateY(-100%) rotate(0deg);
  }
  100% {
    top: 110%;
    transform: translateY(0%) rotate(360deg); }}#panel {
  display: none;
}

#panel::before {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0.0.0.0.5);
}

#hb {
  width: 350px;
  height: 450px;
  border-radius: 20px;
  background-color: #e7223e;
  color: #fad755;
  position: fixed;
  left: 50%;
  top: 50%;
  margin-top: -225px;
  margin-left: -175px;
  font-size: 30px;
  font-weight: 900;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
#btn {
  background-color: #fad755;
  color: #e7223e;
  font-size: 18px;
  margin-top: 10px;
  padding: 10px;
  border: none;
  outline: none;
  cursor: pointer;
}
</style>
Copy the code