html+vue+vant 接雨滴小游戏

html+vue+vant 接雨滴小游戏。
倒计时3秒后,开始15秒接雨滴游戏,通过点击水滴获得水滴。
效果如下:


接雨滴小游戏.gif

问题:

  1. ios不能自动播放bgm
    解决ios内置浏览器不允许自动播放音乐,需通过WeixinJSBridgeReady()实现自动触发。

  2. 连续点击水滴,点击音效只触发一次,之后不生效(同时播放多种音效)?
    解决:不使用audio组件,使用AudioContext,生成音频实例。

  3. 点击水滴后消失,添加‘+1’效果?
    解决:找到所点击的水滴元素添加样式,100ms后移除

document.getElementById(`li${index}`).classList.add("disappear");
setTimeout(() => {
  document.getElementById(`li${index}`).remove(); // 点击后移除
}, 100);
  1. h5长按点击出现保存到本地等信息?
    解决:在所需要禁用该功能的图片上添加css属性:pointer-events: none;
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport"
    content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no,viewport-fit=cover" />
  <meta content="yes" name="apple-mobile-web-app-capable" />
  <meta content="black" name="apple-mobile-web-app-status-bar-style" />
  <title>接雨滴游戏</title>
  <link rel="stylesheet" href="https://unpkg.com/vant@2.12/lib/index.css"/>
  <style>
    [v-cloak] {
      display: none;
    }

    * {
      margin: 0;
      padding: 0;
      -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
      /* webkit是苹果浏览器引擎,tap点击,highlight背景高亮,color颜色,颜色用数值调节。 */
    }

    #app {
      width: 100vw;
      height: 100vh;
      overflow: scroll;
      background: #383e37;
    }

    .bg {
      position: relative;
      width: 100%;
      height: 100%;
      background-image: linear-gradient(#1c0476,
          #2833c4,
          #3558f0,
          #5f94fe,
          #8399fd,
          #f5c6ed,
          #faeefa);
      overflow: hidden;
    }

    .drop {
      -webkit-animation: aim_drop 5s linear 1 forwards;
      animation: aim_drop 5s linear 1 forwards;
    }

    @keyframes aim_drop {
      0% {
        -webkit-transform: translateY(0);
        transform: translateY(0);
      }

      100% {
        -webkit-transform: translateY(120vh);
        transform: translateY(120vh);
      }
    }

    .ser_home {
      width: 100%;
      height: 100%;
    }

    .drop_rain{
      display: block;
      position: relative;
      overflow: hidden;
      width: 100%;
      height: 100%;
    }

    li {
      position: absolute;
      animation: all 3s linear;
      top: -100px;
      z-index: 10;
      list-style: none;
      width: 47px;
      height: 74px;
      display: block;
      background: url("./images/drop.png") no-repeat;
    }

    .count_animation {
      width: 100%;
      text-align: center;
      color: #fff;
      animation: animation 1s linear 5;
      animation-fill-mode: forwards;
    }

    @keyframes animation {
      0% {
        font-size: 10rem;
        opacity: 1;
      }

      100% {
        font-size: 8rem;
        opacity: 0;
      }
    }

    .flex {
      position: relative;
      top: 20px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      color: #fff;
      font-weight: bold;
    }

    .info {
      width: 60px;
      padding: 10px 20px;
      text-align: center;
      font-size: 14px;
      z-index: 99;
    }

    .left {
      color: #fff;
      background-image: linear-gradient(#4ac3fa, #368ff3);
      border-radius: 0 20px 35px 5px;
      box-shadow: 0px 3px 2px #52dafc;
    }

    .right {
      color: #9791e3;
      background-image: linear-gradient(#fcf8fe, #e5cded);
      border-radius: 20px 0 5px 35px;
      box-shadow: 0px 3px 2px #e7d6f8;
    }

    .text {
      font-size: 24px;
    }

    .disappear {
      opacity: 0.5;
    }

    .disappear::before {
      content: "+1";
      color: #fff;
      font-size: 1rem;
    }
    img {
      pointer-events: none;
    }
  </style>
</head>

<body>
  <div id="app" v-cloak>
    <div class="bg">
      <!-- 3s倒计时bgm -->
      <audio src="bgm1.mp3" controls canplaythrough hidden preload id="audioCountdown" ref="audioCountdown"></audio>
      <!-- 游戏bgm -->
      <audio src="bgm2.mp3" controls canplaythrough hidden preload loop id="audioGame" ref="audioGame"></audio>
      <div class="flex">
        <div class="info left">
          <div>获得水滴</div>
          <div class="text">{{ clickNum }}g</div>
        </div>
        <div class="info right">
          <div>剩余时间</div>
          <div class="text">{{ count_15 }}s</div>
        </div>
      </div>
      <!-- 倒计时3s -->
      <div v-if="countDownTimer_3" style="text-align: center">
        <span class="count_animation">{{ count_3 }}</span>
      </div>
      <template v-else>
        <div class="ser_home">
          <ul class="drop_rain" id="drop_rain">
            <template v-for="(item, index) in liParams">
              <li
                :id="`li${index}`"
                :style="{ left: item.left, animationDuration: item.durTime, webkitAnimationDuration: item.durTime}"
                :class="item.cls"
                :data-index="index"
                @webkitAnimationEnd="removeDom"
                @click="touch(index)">
              </li>
            </template>
          </ul>
        </div>
      </template>
    </div>
  </div>
  <script src="https://unpkg.com/vue@2.6/dist/vue.min.js"></script>
  <script src="https://unpkg.com/vant@2.12/lib/vant.min.js"></script>
  <script>
    window.onload = () => {
     // 兼容低版本系统
     var AudioContext = window.AudioContext || window.webkitAudioContext;
      var audioContext = new AudioContext()
      new Vue({
        el: "#app",
        data() {
          return {
            liParams: [],
            timer: null,
            duration: 15000, // 定义游戏时间15s

            countDownTimer_3: null,
            count_3: 0,
            countDownTimer_15: null,
            count_15: 15,
            clickNum: 0,
            AudioSource: {}
          };
        },
        created() {
        },
        mounted() {
          this.countDown_3();
        },
        methods: {
          countDown_3() {
            this.audioAutoPlay('audioCountdown') // 倒计时bgm开始
            const TIME_COUNT = 3;
            if (!this.countDownTimer_3) {
              this.count_3 = TIME_COUNT;
              this.countDownTimer_3 = setInterval(() => {
                if (this.count_3 > 1 && this.count_3 <= TIME_COUNT) {
                  // 限制倒计时区间
                  this.count_3--;
                } else {
                  clearInterval(this.countDownTimer_3); // 删除定时器
                  this.countDownTimer_3 = null;
                  this.count_3 = 0;
                  this.audioAutoPlay('audioGame') // bgm播放
                  this.countDown_15(); // 15s倒计时开始
                  this.startGame();
                }
              }, 1000);
            }
          },

          // 15s倒计时
          countDown_15() {
            const TIME_COUNT = 15;
            if (!this.countDownTimer_15) {
              this.count_15 = TIME_COUNT;
              this.countDownTimer_15 = setInterval(() => {
                if (this.count_15 > 1 && this.count_15 <= TIME_COUNT) {
                  // 限制倒计时区间
                  this.count_15--;
                } else {
                  clearInterval(this.countDownTimer_15); // 删除定时器
                  this.countDownTimer_15 = null;
                  this.count_15 = 0;
                  setTimeout(() => {
                    this.sumitResult(); // 提交成绩
                  }, 2000);
                }
              }, 1000);
            }
          },
          // 点击水滴
          touch(index) {
            this.play('bgm3') // 点击音效
            this.clickNum++;
            document.getElementById(`li${index}`).classList.add("disappear");
            setTimeout(() => {
              document.getElementById(`li${index}`).remove(); // 点击后移除
            }, 100);
          },
          /**
           * 开启游戏动画
           */
          startGame() {
            let win = document.documentElement.clientWidth || document.body.clientWidth;
            let left = parseInt(Math.random() * (win - 50) + 0);
            let durTime = Math.random() * 2 + 3.2 + "s"; // 下落速度
            this.liParams.push({
              left: left + "px",
              cls: "drop",
              durTime: durTime,
            });
            setTimeout(() => {
              // 多少时间结束
              clearTimeout(this.timer);
              return;
            }, this.duration);

            this.timer = setTimeout(() => {
              this.startGame();
            }, 300);
          },
          /**
           * 回收dom节点
           */
          removeDom(e) {
            let target = e.currentTarget;
            document.querySelector("#drop_rain").removeChild(target);
          },
          sumitResult() {
            this.$dialog({
              title: "游戏结束",
              message: `恭喜你获得了<span style="color: red;font-size: 2rem;">${this.clickNum}g</span>水滴~`,
            });
            this.audioAutoPause('audioGame') // 暂停bgm
          },

          // 音频播放
          async play(music) {
            let source = audioContext.createBufferSource()
            if (!this.AudioSource[music]) {
              const res = await fetch(`${music}.mp3`)
              const arraybuffer = await res.arrayBuffer() // 获取arraybuffer文件流
              const audioBuffer = await audioContext.decodeAudioData(arraybuffer)
              this.AudioSource[music] = audioBuffer;
            }
            source.connect(audioContext.destination) //连接上实例
            source.buffer = this.AudioSource[music]
            source.start()
          },

          // 播放bgm
          audioAutoPlay(id) {
            var audio = document.getElementById(id)
            play = function () {
              setTimeout(function () {
                audio.play();
              }, 200);
              document.removeEventListener('touchstart', play, false);
            }
            audio.load()
            setTimeout(function () {
              audio.play();
            }, 200);

            // 监听在微信浏览器中页面加载完毕触发
            document.addEventListener('WeixinJSBridgeReady', function () {
              play();
            }, false);

            // 监听用户触摸到页面后触发
            document.addEventListener('touchstart', play, false);
          },

          // 暂停bgm
          audioAutoPause(id) {
            var audio = document.getElementById(id),
            pause = function () {
              audio.pause();
              document.removeEventListener('touchstart', pause, false);
            };
            audio.pause();

            document.addEventListener('WeixinJSBridgeReady', function () {
              pause();
            }, false);

            document.addEventListener('touchstart', pause, false);
          }
        },
      });
    };
  </script>
</body>

</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355