最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

VUE實(shí)現(xiàn)一個(gè)Flappy Bird游戲的示例代碼

 更新時(shí)間:2021年04月15日 08:58:45   作者:登樓痕  
這篇文章主要介紹了VUE實(shí)現(xiàn)一個(gè)Flappy Bird的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

Flappy Bird是一個(gè)非常簡(jiǎn)單的小游戲,在app上大家都玩過(guò)。這里就用VUE來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的PC版Flappy Bird,娛樂(lè)一下~~~~~

要實(shí)現(xiàn)這個(gè)游戲,首先來(lái)分析一下游戲界面里哪幾塊東西需要?jiǎng)悠饋?lái):

1、第一當(dāng)然就是上下移動(dòng)的小鳥;

2、橫向移動(dòng)的背景圖,讓小鳥看起來(lái)在橫向飛行;

3、從畫面右端進(jìn)入的一排排管道。

這樣很明確了,我們讓上面3塊內(nèi)容按照規(guī)律運(yùn)動(dòng)起來(lái),然后再加上規(guī)則邊界判斷和計(jì)分,就可以得到一個(gè)完整的游戲。所以就一塊塊來(lái)解決。

先來(lái)定義一些常量和變量:

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開(kāi)始計(jì)數(shù)
 
...
 
data() {
    return {
      start: false,
      clientWidth: 0,
      clientHeight: 0,
      spaceHeight: [240, 200, 160], // 上管道與下管道之間的距離
      pipeArr: [], // 管道數(shù)組
      score: 0, // 得分
      jumpSum: 0, // 當(dāng)前跳躍相對(duì)高度
      jumpFlag: false, // true-按下空格鍵跳躍上升階段;false-自由落體階段
      dropBirdImg: require("@/assets/img/bird/bird0_0.png"),
      flyBirdImg: require("@/assets/img/bird/bird0_2.png"),
      gameOver: false, // 游戲失敗的flag,用于停止動(dòng)畫幀
    };
},

1、上下移動(dòng)的小鳥

為了分別控制小鳥和管道的位置,元素定位均采用position: absolute

小鳥本身就是個(gè)div+背景圖,然后定義一下在界面里的初始位置:

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

然后,在什么都不操作的情況下,小鳥從初始位置開(kāi)始"墜落",小鳥的墜落是一個(gè)越落越快的過(guò)程,在這里我沒(méi)有用物理的重力加速度公式,只是簡(jiǎn)單模擬了一個(gè)曲線加速過(guò)程。這是一個(gè)持續(xù)的動(dòng)畫,所以把這個(gè)動(dòng)作放在動(dòng)畫幀里,即requestAnimationFrame,每一幀的函數(shù)定義為loop()。

所以在loop函數(shù)中,根據(jù)offsetTop和父元素的clientHeight來(lái)判斷小鳥是否觸碰到了畫面的上下邊界,是則游戲結(jié)束;否,則增加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) {
        // 碰到邊界,游戲結(jié)束
        _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(); // 管道移動(dòng)
}

游戲中,玩家按下空格鍵,小鳥會(huì)向上跳躍一段距離,用this.jumpFlag[true/false]來(lái)記錄這一狀態(tài),當(dāng)按下時(shí),置為true,loop函數(shù)中小鳥jump(),在jump到一定距離后,jumpFlag置為false,小鳥開(kāi)始?jí)嬄洹?/p>

所以,jump函數(shù)很容易實(shí)現(xiàn):

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、橫向移動(dòng)的背景圖

這個(gè)比較簡(jiǎn)單,就是background-position無(wú)限循環(huán)切換就行了,位置根據(jù)自己下載的背景圖素材寬度決定。

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

經(jīng)過(guò)這兩步,我們就可以得到一個(gè)正在飛行的小鳥了,用document.onkeydown監(jiān)聽(tīng)空格鍵來(lái)切換jumpFlag,如下圖:

3、從右往左一移動(dòng)進(jìn)入管道

管道是由上下兩個(gè)div組成,每個(gè)div通過(guò)不同的top: -xx和bottom: -yy實(shí)現(xiàn)中間有間隙。

首先實(shí)現(xiàn)生成一個(gè)隨機(jī)間隙管道的函數(shù),管道存放在pipeArr對(duì)象數(shù)組中:

addPipe(id) {
      let obj = {};
      let top_num = this.sum(10, 170);
      let height = this.spaceHeight[
        Math.floor(Math.random() * this.spaceHeight.length)
      ]; // 隨機(jī)選取間隙值
      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) {
      // 隨機(jī)n-m之間的數(shù)字
      return Math.floor(Math.random() * (m - n) + n);
}

然后需要將管道移動(dòng)起來(lái),即loop()中管道移動(dòng)函數(shù)pipesMove(),整個(gè)函數(shù)實(shí)現(xiàn)如下:

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;管道進(jìn)入范圍right是width-450到width-300
        if (
          _this.pipeArr[i].right >= _this.clientWidth - 450 &&
          _this.pipeArr[i].right <= _this.clientWidth - 300
        ) {
          // 該管道進(jìn)入了小鳥觸碰范圍
          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) { // 當(dāng)某個(gè)管道剛好在小鳥左邊,證明小鳥通過(guò)該管道,根據(jù)管道id算出小鳥得分
          _this.score = _this.pipeArr[i].id + 1;
        }
        _this.pipeArr[i].right = _this.pipeArr[i].right + 2; // 管道每幀移動(dòng)2px
      }
}

這里做了五件事:

(1)管道出了左邊畫面后shift()最左的管道;

(2)最右的管道離畫面右側(cè)一定距離后,加入新的一根管道;

(3)循環(huán)遍歷中,判斷小鳥是否進(jìn)入了某一根管道的范圍,判斷小鳥top是否有觸碰到上下管道,觸碰則輸;

(4)當(dāng)某一個(gè)管道剛好位于小鳥左側(cè)時(shí),證明小鳥成功通過(guò),分?jǐn)?shù)+1;

(5)每個(gè)管道移動(dòng)2px像素,數(shù)值記錄在right屬性里。

通過(guò)DOM里:style設(shè)置right就可以使得管道橫向移動(dòng)了

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

以上就是vue實(shí)現(xiàn)flappy bird的思路和核心代碼了,總共也就兩百多行代碼。在我看來(lái),難點(diǎn)主要集中在管道的移動(dòng)、觸碰判定以及分?jǐn)?shù)計(jì)算上。當(dāng)然代碼里還有很多可以優(yōu)化的不足點(diǎn),共勉~~

相關(guān)文章

  • 詳解vue2.0+vue-video-player實(shí)現(xiàn)hls播放全過(guò)程

    詳解vue2.0+vue-video-player實(shí)現(xiàn)hls播放全過(guò)程

    這篇文章主要介紹了詳解vue2.0+vue-video-player實(shí)現(xiàn)hls播放全過(guò)程,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • Vue Element前端應(yīng)用開(kāi)發(fā)之圖標(biāo)的維護(hù)和使用

    Vue Element前端應(yīng)用開(kāi)發(fā)之圖標(biāo)的維護(hù)和使用

    在Vue Element前端應(yīng)用中,圖標(biāo)是必不可少點(diǎn)綴界面的元素,Element界面組件里面提供了很多常見(jiàn)的圖標(biāo),因此考慮擴(kuò)展更多圖標(biāo),引入了vue-awesome組件,它利用了Font Awesome的內(nèi)置圖標(biāo),實(shí)現(xiàn)了更多圖標(biāo)的整合,可以在項(xiàng)目中使用更多的圖標(biāo)元素了
    2021-05-05
  • vue項(xiàng)目實(shí)現(xiàn)通過(guò)ip地址訪問(wèn)和localhost訪問(wèn)方式

    vue項(xiàng)目實(shí)現(xiàn)通過(guò)ip地址訪問(wèn)和localhost訪問(wèn)方式

    這篇文章主要介紹了vue項(xiàng)目實(shí)現(xiàn)通過(guò)ip地址訪問(wèn)和localhost訪問(wèn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • Vue實(shí)現(xiàn)錄制屏幕并本地保存功能

    Vue實(shí)現(xiàn)錄制屏幕并本地保存功能

    這篇文章主要介紹了Vue實(shí)現(xiàn)錄制屏幕功能并本地保存,這里用的是用的是HBuilder?X開(kāi)發(fā),結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • vue源碼學(xué)習(xí)之Object.defineProperty對(duì)象屬性監(jiān)聽(tīng)

    vue源碼學(xué)習(xí)之Object.defineProperty對(duì)象屬性監(jiān)聽(tīng)

    這篇文章主要介紹了vue源碼學(xué)習(xí)之Object.defineProperty對(duì)象屬性監(jiān)聽(tīng),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • vue瀑布流組件實(shí)現(xiàn)上拉加載更多

    vue瀑布流組件實(shí)現(xiàn)上拉加載更多

    這篇文章主要為大家詳細(xì)介紹了vue瀑布流組件實(shí)現(xiàn)上拉加載更多,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • vue.js使用v-if實(shí)現(xiàn)顯示與隱藏功能示例

    vue.js使用v-if實(shí)現(xiàn)顯示與隱藏功能示例

    這篇文章主要介紹了vue.js使用v-if實(shí)現(xiàn)顯示與隱藏功能,結(jié)合簡(jiǎn)單實(shí)例形式分析了使用v-if進(jìn)行判斷實(shí)現(xiàn)元素的顯示與隱藏功能,需要的朋友可以參考下
    2018-07-07
  • 基于vue2的canvas時(shí)鐘倒計(jì)時(shí)組件步驟解析

    基于vue2的canvas時(shí)鐘倒計(jì)時(shí)組件步驟解析

    今天給大家介紹一款基于vue2的canvas時(shí)鐘倒計(jì)時(shí)組件,這個(gè)時(shí)鐘倒計(jì)時(shí)組件采用canvas動(dòng)畫的炫酷動(dòng)畫效果形式,根據(jù)剩余時(shí)間的多少變換顏色和旋轉(zhuǎn)扇形的速度,適合搶購(gòu)、拍賣、下注等業(yè)務(wù)場(chǎng)景,且對(duì)移動(dòng)端友好,需要的朋友可以參考下
    2018-11-11
  • vue如何獲取點(diǎn)擊事件源的方法

    vue如何獲取點(diǎn)擊事件源的方法

    本篇文章主要介紹了vue如何獲取點(diǎn)擊事件源的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • vue項(xiàng)目如何實(shí)現(xiàn)Echarts在label中獲取點(diǎn)擊事件

    vue項(xiàng)目如何實(shí)現(xiàn)Echarts在label中獲取點(diǎn)擊事件

    這篇文章主要介紹了vue項(xiàng)目如何實(shí)現(xiàn)Echarts在label中獲取點(diǎn)擊事件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10

最新評(píng)論

七台河市| 霸州市| 台东县| 淳安县| 屏山县| 北宁市| 方山县| 稻城县| 常山县| 衡山县| 河西区| 武穴市| 当涂县| 蒲城县| 揭阳市| 萨迦县| 富阳市| 彝良县| 河西区| 都安| 东乡县| 黑水县| 奇台县| 岑溪市| 安仁县| 仙桃市| 巴彦淖尔市| 翁源县| 开江县| 柳林县| 海安县| 和龙市| 南召县| 应城市| 承德市| 固阳县| 湟中县| 辽阳县| 阳江市| 任丘市| 和硕县|