VUEはゆるい鳥を実装します~~~

ゆるい鳥は誰もがアプリでプレイした非常にシンプルな小さなゲームです。ここでは、VUEを使用してFlappyBirdのシンプルなPCバージョンを実装しています~~~~~

このゲームを実装するには、最初にゲームインターフェイスのどの部分を移動する必要があるかを分析します。

1. 1つ目はもちろん、上下に動く鳥です。

2.水平方向に移動する背景画像により、鳥は水平方向に飛んでいるように見えます。

3.画面の右端から入ったパイプの列。

これは非常に明確です。上記の3つのコンテンツを法律に従って移動させてから、ルール境界の判断とスコアリングを追加すると、完全なゲームを取得できます。だからそれは少しずつ解決されます。


最初にいくつかの定数と変数を定義しましょう:

let rafId = null; // requestAnimationFrame的ID
let startSpeed = 1;
const SPEED = 0.04; // 加速度
const UP = 5.0; // 速度累加上限
const UP_SUM = 30; // 按一次跳跃的高度
const BIRD_WIDTH = 50; // 小鸟图片宽50px
const PIPE_DISTANCE = 350; // 管道之间的横向距离
let id = 0; // 管道唯一id,从0开始计数

...

data() {
    return {
      start: false,
      clientWidth: 0,
      clientHeight: 0,
      spaceHeight: [240, 200, 160], // 上管道与下管道之间的距离
      pipeArr: [], // 管道数组
      score: 0, // 得分
      jumpSum: 0, // 当前跳跃相对高度
      jumpFlag: false, // true-按下空格键跳跃上升阶段;false-自由落体阶段
      dropBirdImg: require("@/assets/img/bird/bird0_0.png"),
      flyBirdImg: require("@/assets/img/bird/bird0_2.png"),
      gameOver: false, // 游戏失败的flag,用于停止动画帧
    };
},

1.上下に動く鳥

鳥とパイプの位置を別々に制御するために、要素の配置は位置を採用します:絶対

鳥自体はdiv + background画像であり、インターフェイスで初期位置を定義します。

<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;
      // 小鸟初始位置
      position: absolute;
      left: 300px;
      top: 300px;
}

その後、何も操作せずに、鳥は初期位置から「落下」します。鳥の落下は、ますます速く落下するプロセスです。ここでは、物理的な重力加速度の式を使用せず、単純にシミュレートしました。曲線の加速プロセス。これは連続アニメーションであるため、このアクションをアニメーションフレーム、つまりrequestAnimationFrameに配置し、各フレームの関数をloop()として定義します。

したがって、ループ関数で、親要素のoffsetTopとclientHeightに従って、鳥が画面の上下の境界線に触れたかどうかを判断します。触れている場合はゲームオーバーです。そうでない場合は、style.topを追加して許可します。鳥が落ちる。

loop() {
      let _this = this;
      if (_this.jumpFlag) {
        // 小鸟跳跃
        _this.jump();
      }
      let top = _this.$refs.bird.offsetTop;
      if (top > _this.clientHeight - BIRD_WIDTH || top <= 0) {
        // 碰到边界,游戏结束
        _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"; // 模拟加速坠落
        if (startSpeed < UP) {
          startSpeed += SPEED;
        }
      }
      _this.pipesMove(); // 管道移动
}

ゲームでは、プレイヤーがスペースバーを押すと、鳥が一定の距離をジャンプします。this.jumpFlag[true / false]を使用して、この状態を記録します。押すと、trueに設定されます。ループ機能では、鳥のjump()、in一定の距離にジャンプした後、jumpFlagがfalseに設定され、鳥が落下し始めます。

したがって、ジャンプ機能は簡単に実装できます。

jump() {
      let _this = this;
      _this.$refs.bird.style.background = `url('${_this.flyBirdImg}') no-repeat center/contain`;
      if (_this.jumpSum > UP_SUM) {
        // 到顶部就落下
        _this.jumpFlag = false;
        _this.jumpSum = 0;
        startSpeed = 1;
      } else {
        _this.$refs.bird.style.top = _this.$refs.bird.offsetTop - 8 + "px";
        _this.jumpSum += 8;
      }
}

2.水平移動の背景画像

これは比較的簡単です。つまり、背景位置の無限ループスイッチで十分であり、位置は自分でダウンロードした背景画像素材の幅に応じて決定されます。

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

これらの2つの手順の後、飛んでいる鳥を取得できます。次に示すように、document.onkeydownを使用してスペースバーを監視し、jumpFlagを切り替えます。

3.右から左に移動してパイプに入ります

パイプラインは2つの上部と下部のdivで構成され、それぞれの上部と下部のdivの間にギャップがあります:-xxと下部:-yy。

まず、ランダムギャップパイプを生成する機能を実現します。パイプはpipeArrオブジェクト配列に格納されます。

addPipe(id) {
      let obj = {};
      let top_num = this.sum(10, 170);
      let height = this.spaceHeight[
        Math.floor(Math.random() * this.spaceHeight.length)
      ]; // 随机选取间隙值
      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) {
      // 随机n-m之间的数字
      return Math.floor(Math.random() * (m - n) + n);
}

次に、パイプを移動する必要があります。つまり、loop()内のパイプ移動関数pipesMove()は、関数全体が次のように実装されます。

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++) {
        // 判断一下小鸟是否接触到了管道,小鸟50*50,left:300px;管道宽100px;管道进入范围right是width-450到width-300
        if (
          _this.pipeArr[i].right >= _this.clientWidth - 450 &&
          _this.pipeArr[i].right <= _this.clientWidth - 300
        ) {
          // 该管道进入了小鸟触碰范围
          let bird_top = _this.$refs.bird.offsetTop;
          // 12是小鸟图片素材上下有空白间隙
          if (
            bird_top <= _this.clientHeight / 2 - _this.pipeArr[i].top - 12 ||
            bird_top >=
              _this.clientHeight / 2 + _this.pipeArr[i].bottom - BIRD_WIDTH + 12
          ) {
            // 碰到了管道
            _this.resetGame();
            return;
          }
        }
        if (_this.pipeArr[i].right === _this.clientWidth - 300 && _this.pipeArr[i].right === _this.clientWidth - 301) { // 当某个管道刚好在小鸟左边,证明小鸟通过该管道,根据管道id算出小鸟得分
          _this.score = _this.pipeArr[i].id + 1;
        }
        _this.pipeArr[i].right = _this.pipeArr[i].right + 2; // 管道每帧移动2px
      }
}

ここでは5つのことが行われます。

(1)パイプが左画面から出た後、左端のパイプをShift()します。

(2)右端のパイプが画面の右側から一定の距離になったら、新しいパイプを追加します。

(3)ループトラバーサルでは、鳥が特定のパイプの範囲に入ったかどうかを判断し、鳥の上部が上下のパイプに触れたかどうかを判断します。触れた場合、鳥は失われます。

(4)鳥の左側にあるパイプがある場合、鳥は無事通過したことが証明され、スコアは+1です。

(5)各パイプは2pxピクセル移動し、値は右の属性に記録されます。

DOM:スタイルで正しく設定することにより、パイプを水平方向に移動させることができます。

<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;
          }
        }
}

上記は、合計200行以上のコードであるゆるい鳥を実現するためのvueのアイデアとコアコードです。私の意見では、難しさは主にパイプの動き、タッチの決定、スコアの計算に集中しています。もちろん、最適化できるコードにはまだ多くの欠陥があり、お互いに励まし合っています~~

 

 

 

おすすめ

転載: blog.csdn.net/denglouhen/article/details/114933374