DOM綜合案例-飛翔的小鳥

JS初學者往往有一個特點:一聽就懂,一寫就懵。
糾其原因:
1-代碼練習太少,導致根基不紮實
2-代碼練習太少,導致經驗無積累。
3-代碼練習太少,導致思路不清晰。
所以代碼一定要多多練習,無捷徑可尋,希望通過以下個案例,可以對大家學習JS有所幫助。

1- 預覽與下載

2- 完成遊戲樣式及基本結構

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            pading: 0;
            margin: 0;
        }

        body {
            user-select: none;
        }

        /* 遊戲舞臺 */
        #app {
            position: relative;
            width: 343px;
            height: 480px;
            background: url("./img/bg.jpg");
            margin: 20px auto;
            overflow: hidden;
        }

        /*  分數  */
        #score {
            position: absolute;
            width: 100%;
            left: 0;
            top: 20px;
            text-align: center;
            font-size: 0;
            z-index: 1;
        }

        /*  開場動畫  */
        .startAnimate {
            width: 236px;
            height: 77px;
            background-image: url("./img/head.jpg");
            position: absolute;
            top: 150px;
            left: calc(50% - 118px);
            animation: startAnimate 1s alternate infinite;
            z-index: 9;
        }

        @keyframes startAnimate {
            from {
                top: 120px;
            }
            to {
                top: 150px;
            }
        }

        .animate-bird {
            position: absolute;
            width: 40px;
            height: 26px;
            background-image: url("./img/bird0.png");
            right: 0;
            top: calc(50% - 13px);
            animation: bird 1s alternate infinite;
            z-index: 9;
        }

        @keyframes bird {
            from {
                background-image: url("./img/bird0.png");

            }
            to {
                background-image: url("./img/bird1.png");
            }
        }

        /*開始按鈕*/
        #start {
            position: 85px;
            height: 29px;
            position: absolute;
            left: calc(50% - 42.5px);
            top: 260px;
            cursor: pointer;
            z-index: 9;
        }
        /*  管道  */
        .pipe {
            width: 62px;
            height: 423px;
            position: absolute;
            left: 200px;
            bottom: 57px;
        }
        .pipe_up {
            position: relative;
            left: 0;
            top: 0;
            height:100px;
            background: url("./img/up_mod.png") repeat-y;
        }
        .pipe_up img{
            position: absolute;
            bottom: 0;
        }
        .pipe_down {
            position: absolute;
            left: 0;
            bottom: 0;
            height:223px;
            background: url("./img/down_mod.png") repeat-y;
        }
    </style>
</head>
<body>
<!--  遊戲舞臺  -->
<div id="app">
    <!--  分數  -->
    <div id="score">
        <img src="./img/0.jpg" alt="">
        <img src="./img/0.jpg" alt="">
        <img src="./img/0.jpg" alt="">
    </div>
    <!--  開場動畫  -->
    <div class="startAnimate">
        <div class="animate-bird"></div>
    </div>
    <!--  開始按鈕  -->
    <img id="start" src="./img/start.jpg" alt="">
    <!--  管道  -->
    <div class="pipe">
        <!--  上管道  -->
        <div class="pipe_up">
            <img src="./img/up_pipe.png" alt="">
        </div>
        <!--  下管道  -->
        <div class="pipe_down">
            <img src="./img/down_pipe.png" alt="">
        </div>
    </div>
</div>
</body>
</html>

預覽效果:https://qianduanmao.com/demo/dom/xiaoniao/1.html

3- 點擊開始按鈕進入遊戲

  • 由於管道需要需要後續動態添加,所以可以將與管道相關的元素註釋掉。
<!--  遊戲舞臺  -->
<div id="app">
    <!--  分數  -->
    <div id="score">
        <img src="./img/0.jpg" alt="">
        <img src="./img/0.jpg" alt="">
        <img src="./img/0.jpg" alt="">
    </div>
    <!--  開場動畫  -->
    <div class="startAnimate">
        <div class="animate-bird"></div>
    </div>
    <!--  開始按鈕  -->
    <img id="start" src="./img/start.jpg" alt="">
    <!--  管道註釋掉,因爲管道需要後續動態生成  -->
<!--    <div class="pipe">-->
<!--        &lt;!&ndash;  上管道  &ndash;&gt;-->
<!--        <div class="pipe_up">-->
<!--            <img src="./img/up_pipe.png" alt="">-->
<!--        </div>-->
<!--        &lt;!&ndash;  下管道  &ndash;&gt;-->
<!--        <div class="pipe_down">-->
<!--            <img src="./img/down_pipe.png" alt="">-->
<!--        </div>-->
<!--    </div>-->
</div>
  • 點擊start按鈕,隱藏開場動畫及start按鈕
// 獲得開場動畫元素
var startAnimate = document.querySelector('.startAnimate');
// 獲得開始按鈕
var start = document.querySelector('#start');
// 點擊按鈕
start.onclick = function(){
    // 隱藏開場動畫及開始按鈕
    startAnimate.style.display = this.style.display = 'none';
}

預覽效果:https://qianduanmao.com/demo/dom/xiaoniao/2.html

4- 小鳥上升及加速下落

  • 遊戲舞臺中引入小鳥圖片
<img id="bird" src="./img/bird0.png" alt="">
  • 爲小鳥圖片增加樣式
/*  小鳥  */
#bird {
    position: absolute;
    left: 30px;
    top: 50px;
    display: none;
    z-index: 10;
}
  • JS代碼更改如下:
// 獲得開場動畫元素
var startAnimate = document.querySelector('.startAnimate');
// 獲得開始按鈕
var start = document.querySelector('#start');
// +獲得小鳥元素
var bird = document.querySelector("#bird");
// +獲得後臺元素
var app = document.querySelector("#app");
// 點擊按鈕
start.onclick = function () {
    // 隱藏開場動畫及開始按鈕
    startAnimate.style.display = this.style.display = 'none';
    // + 小鳥顯示
    bird.style.display = 'block';
    // + 小鳥下落速度,正數向下速度,負數爲向上速度
    bird.speed = 0;
    // + 允許下降最大距離:57爲馬路的高度
    bird.distanceMaxDecline = app.clientHeight - 57 - bird.offsetHeight;
    // + 是否死亡,初始值爲false
    bird.isDie = false;
    // + 增加定時器
    bird.fly = setInterval(flyInterval.bind(bird), 20);
    // + 爲舞臺增加點擊事件
    app.onclick = birderRise;
}

// + 單擊舞臺的處理函數
function birderRise() {
    // 小鳥加速度設置爲-5,向上飛翔
    bird.speed = -5;
}

// + 小鳥飛翔計時器
function flyInterval() {
    // 加速度爲0.5
    this.speed += 0.5;
    // 如果速度爲正數,則下落,正數上升,設置圖片
    this.src = this.speed > 0 ? "./img/down_bird0.png":"./img/bird0.png";
    // 小鳥下落的距離
    var distanceDecline = this.offsetTop + this.speed;
    // 如果觸地則死亡
    if (distanceDecline > this.distanceMaxDecline) {
        // 設置爲下降最大距離
        this.style.top = this.distanceMaxDecline + "px";
        // 死亡
        this.isDie = true;
        // 關閉小鳥定時器
        clearInterval(this.fly);
        return;
    }
    // distanceDecline不允許小於0
    if (distanceDecline < 0) distanceDecline = 0;
    // 設置top值
    this.style.top = distanceDecline + "px";
}

預覽效果:https://qianduanmao.com/demo/dom/xiaoniao/3.html

5- 隔3s生成一次管道

  • 創建工具函數,用於生成指定範圍的整數
// 工具函數:生成指定範圍的隨機整數
function getRandom(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min);
}
  • 創建生成管道方法
// 創建管道
function createPipe(){
    var pipe = document.createElement("div");
    pipe.className = "pipe";
    pipe.score =  1;// 指定增加分值
    // 上管道寬度
    var upHeight = getRandom(60,263);
    // 下管道的高度
    var downHeight = app.clientHeight-57-100-upHeight;
    pipe.innerHTML = `
        <div style="height:${upHeight}px" class="pipe_up">
        <img src="./img/up_pipe.png" alt="">
        </div>
        <div style="height:${downHeight}px" class="pipe_down">
        <img src="./img/down_pipe.png" alt="">
        </div>
    `;
    // 將創建的管道放置在舞臺尾部
    app.appendChild(pipe);
}
  • 增加全局變量
// +記錄生成管道定時器
var pipeTimer;
  • 在start按鈕的事件處理函數中增加定時器隔3秒調用一次createPipe
// 點擊按鈕
start.onclick = function () {
    // 隱藏開場動畫及開始按鈕
    startAnimate.style.display = this.style.display = 'none';
    // 小鳥顯示
    bird.style.display = 'block';
    // 小鳥下落速度,正數向下速度,負數爲向上速度
    bird.speed = 0;
    // 允許下降最大距離:57爲馬路的高度
    bird.distanceMaxDecline = app.clientHeight - 57 - bird.offsetHeight;
    // 是否死亡,初始值爲false
    bird.isDie = false;
    // 增加定時器
    bird.fly = setInterval(flyInterval.bind(bird), 30);
    // +管道定時器
    pipeTimer = setInterval(createPipe,3000);
    // 爲舞臺增加點擊事件
    app.onclick = birderRise;
}

預覽效果:https://qianduanmao.com/demo/dom/xiaoniao/4.html

6- 管道均速移動並統計分數

  • 由於管道要動態生產,需要將管道的初始位置調整爲遊戲舞臺右側。
/*  管道  */
.pipe {
    width: 62px;
    height: 423px;
    position: absolute;
    left: 343px;/*修改爲343*/
    bottom: 57px;
}
  • 增加全局變量
// +獲得分數元素
var score = document.querySelectorAll("#score>img");
  • 增加小鳥總分數屬性
// 點擊按鈕
start.onclick = function () {
    // 隱藏開場動畫及開始按鈕
    startAnimate.style.display = this.style.display = 'none';
    // 小鳥顯示
    bird.style.display = 'block';
    // 小鳥下落速度,正數向下速度,負數爲向上速度
    bird.speed = 0;
    // 允許下降最大距離:57爲馬路的高度
    bird.distanceMaxDecline = app.clientHeight - 57 - bird.offsetHeight;
    // 是否死亡,初始值爲false
    bird.isDie = false;
    // +小鳥總分
    bird.scoreSum = 0;
    // 增加定時器
    bird.fly = setInterval(flyInterval.bind(bird), 30);
    // 管道定時器
    pipeTimer = setInterval(createPipe,3000);
    // 爲舞臺增加點擊事件
    app.onclick = birderRise;
}
  • 增加管理均速移動方法,並統計分數
// 管道移動
function pipeMove(){
    // 每次移動2像素
    var distance  = this.offsetLeft -2;
    // 讓管道開始移動
    this.style.left = distance+"px";
    // 判斷管道是否已經移出舞臺
    if(distance<-this.offsetWidth){
        // 移除定時器
        clearInterval(this.moveTimer);
        // 移除管道
        app.removeChild(this);
    }else if(distance<-(this.offsetWidth-bird.offsetLeft)){
        // 小鳥過了管道加分
        if(this.score > 0){
            bird.scoreSum+=this.score;
            score[0].src="./img/"+parseInt(bird.scoreSum/100)+".jpg";
            score[1].src="./img/"+parseInt((bird.scoreSum%100)/10)+".jpg";
            score[2].src="./img/"+parseInt(bird.scoreSum%10)+".jpg";
            this.score = 0;
        }
    }
}

  • 在createPipe函數中調用pipeMove
// 創建管道
function createPipe(){
    // 。。。
    // 。。。
    // 。。。
    // +增加定時器,讓管道均速移動
    pipe.moveTimer = setInterval(pipeMove.bind(pipe),30);
}

預覽效果:https://qianduanmao.com/demo/dom/xiaoniao/5.html

7- 讓草地進行均速移動

  • 在遊戲舞臺中增加草地元素
<!--  草地  -->
<div id="banner">
    <img src="img/banner.jpg"/>
    <img src="img/banner.jpg"/>
</div>

  • 爲草地增加樣式
/*草地*/
#banner{
    position: absolute;
    left:0;
    top:423px;
    font-size: 0;
    width: 200%;
}

  • 全局獲得草地元素,並增加移動初始值
// 獲得草地
var banner = document.querySelector("#banner");
// 向左移動的數值
banner.distanceLeft = 0;
  • 增加草地移動函數
// 草地向左移動
function bannerMove(){
    // 向左移動的數值 (距離)+2
    banner.distanceLeft -= 2;
    // 判斷最左側圖片是否消失在舞臺中
    if(banner.distanceLeft < -app.clientWidth){
        // 向左移動的距離爲0
        banner.distanceLeft = 0;
        // 將banner當中的第一個DOM元素放置到banner的尾部
        banner.appendChild(banner.firstElementChild);
    }
    banner.style.left = banner.distanceLeft+"px";
}
  • 在start按鈕的事件處理函數中增加定時器,調用bannerMove
// 草地移動
banner.timer = setInterval(bannerMove,30);

預覽效果:https://qianduanmao.com/demo/dom/xiaoniao/6.html

8- 檢測碰撞遊戲結束

  • 增加碰撞檢測函數
// 是否小鳥與柱子進行了碰撞
function crashFn(pipe){
    // 相撞:四個條件必須同時滿足
    // bird與pipe
    // 1- bird的右邊 大於等於 pipe的左邊
    // 2- bird的下邊 大於等於  pipe的上邊
    // 3- bird的左邊 小於等於  pipe的右邊
    // 4- bird的上邊 小於等於  pipe的下邊

    // bird:
    var birdLeft = bird.offsetLeft;//左邊
    var birdRight = birdLeft+bird.offsetWidth;// 右邊
    var birdTop = bird.offsetTop;// 上邊
    var birdBottom = birdTop+bird.offsetHeight;// 下邊

    // pipe
    var pipeLeft = pipe.parentNode.offsetLeft;
    var pipeRight = pipeLeft+pipe.offsetWidth;
    var pipeTop = pipe.offsetTop;
    var pipeBottom = pipeTop+pipe.offsetHeight;
    if(birdRight>=pipeLeft
       && birdBottom>=pipeTop
       && birdLeft<=pipeRight
       && birdTop<=pipeBottom){
        return true;// 相撞了
    }
    return false;// 沒有相撞
}
  • 在flyInterval函數中判斷是否碰撞
// 小鳥飛翔計時器
function flyInterval() {
    // 加速度爲0.5
    this.speed += 0.5;
    // 如果速度爲正數,則下落,正數上升,設置圖片
    this.src = this.speed > 0 ? "./img/down_bird0.png":"./img/bird0.png";
    // 小鳥下落的距離
    var distanceDecline = this.offsetTop + this.speed;
    // 如果觸地則死亡
    if (distanceDecline > this.distanceMaxDecline) {
        distanceDecline = this.distanceMaxDecline;
        // 小鳥死亡
        this.isDie = true;
    }
    // distanceDecline不允許小於0
    if (distanceDecline < 0) distanceDecline = 0;
    // 設置top值
    this.style.top = distanceDecline + "px";
    // + 小鳥未亡,檢測管道是否與小鳥相撞
    if(!this.isDie){
        var pipes = document.querySelectorAll(".pipe div");
        for(var i=0;i<pipes.length;i++){
            // 相撞
            if(crashFn(pipes[i])){
                bird.isDie = true;
                bird.className = "die";
                break;
            }
        }
    }
    // + 判斷小鳥是否死亡
    if(bird.isDie){
        // 關閉小鳥定時器
        clearInterval(this.fly);
        // 關閉管道定時器
        clearInterval(pipeTimer);
        // 關閉草地定時器
        clearInterval(banner.timer)
        // 顯示開場動畫及開始按鈕
        startAnimate.style.display = start.style.display = 'block';
    }
}
  • 增加小鳥撞擊後的樣式
/*死亡*/
.die{
    transition:0.5s;
    top:393px !important;
}
  • pipeMove函數判斷小鳥是否死亡
// + 判斷小鳥是否死亡
if(bird.isDie){
    // 關閉管道移動定時器
    clearInterval(this.moveTimer)
    // 清除管道
    app.removeChild(this);
    return;
}
  • 重置遊戲
// 點擊按鈕
start.onclick = function () {
    // + 重置分數
    score[0].src = score[1].src = score[2].src = "./img/0.jpg";
    // + 重置小鳥高度
    bird.style.top = "50px";
    // + 清除小鳥樣式
    bird.className = null;
    // 隱藏開場動畫及開始按鈕
    startAnimate.style.display = this.style.display = 'none';
    // 小鳥顯示
    bird.style.display = 'block';
    // 小鳥下落速度,正數向下速度,負數爲向上速度
    bird.speed = 0;
    // 允許下降最大距離:57爲馬路的高度
    bird.distanceMaxDecline = app.clientHeight - 57 - bird.offsetHeight;
    // 是否死亡,初始值爲false
    bird.isDie = false;
    // 小鳥總分
    bird.scoreSum = 0;
    // 增加定時器
    bird.fly = setInterval(flyInterval.bind(bird), 30);
    // 管道定時器
    pipeTimer = setInterval(createPipe, 3000);
    // 草地移動
    banner.timer = setInterval(bannerMove, 30);
    // 爲舞臺增加點擊事件
    app.onclick = birderRise;
}

預覽效果:https://qianduanmao.com/demo/dom/xiaoniao/7.html

9- 增加音樂-完整代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            pading: 0;
            margin: 0;
        }

        body {
            user-select: none;
        }

        /* 遊戲舞臺 */
        #app {
            position: relative;
            width: 343px;
            height: 480px;
            background: url("./img/bg.jpg");
            margin: 20px auto;
            overflow: hidden;
        }

        /*  分數  */
        #score {
            position: absolute;
            width: 100%;
            left: 0;
            top: 20px;
            text-align: center;
            font-size: 0;
            z-index: 1;
        }

        /*  開場動畫  */
        .startAnimate {
            width: 236px;
            height: 77px;
            background-image: url("./img/head.jpg");
            position: absolute;
            top: 150px;
            left: calc(50% - 118px);
            animation: startAnimate 1s alternate infinite;
            z-index: 9;
        }

        @keyframes startAnimate {
            from {
                top: 120px;
            }
            to {
                top: 150px;
            }
        }

        .animate-bird {
            position: absolute;
            width: 40px;
            height: 26px;
            background-image: url("./img/bird0.png");
            right: 0;
            top: calc(50% - 13px);
            animation: bird 1s alternate infinite;
            z-index: 9;
        }

        @keyframes bird {
            from {
                background-image: url("./img/bird0.png");

            }
            to {
                background-image: url("./img/bird1.png");
            }
        }

        /*開始按鈕*/
        #start {
            position: 85px;
            height: 29px;
            position: absolute;
            left: calc(50% - 42.5px);
            top: 260px;
            cursor: pointer;
            z-index: 9;
        }

        /*  管道  */
        .pipe {
            width: 62px;
            height: 423px;
            position: absolute;
            left: 343px; /*修改爲343*/
            bottom: 57px;
        }

        .pipe_up {
            position: relative;
            left: 0;
            top: 0;
            height: 100px;
            background: url("./img/up_mod.png") repeat-y;
        }

        .pipe_up img {
            position: absolute;
            bottom: 0;
        }

        .pipe_down {
            position: absolute;
            left: 0;
            bottom: 0;
            height: 223px;
            background: url("./img/down_mod.png") repeat-y;
        }

        /*  小鳥  */
        #bird {
            position: absolute;
            left: 30px;
            top: 50px;
            display: none;
            z-index: 10;
        }

        /*草地*/
        #banner {
            position: absolute;
            left: 0;
            top: 423px;
            font-size: 0;
            width: 200%;
        }

        /*死亡*/
        .die {
            transition: 0.5s;
            top: 393px !important;
        }
    </style>
</head>
<body>
<!--  遊戲舞臺  -->
<div id="app">
    <!--  分數  -->
    <div id="score">
        <img src="./img/0.jpg" alt="">
        <img src="./img/0.jpg" alt="">
        <img src="./img/0.jpg" alt="">
    </div>
    <img id="bird" src="./img/bird0.png" alt="">
    <!--  開場動畫  -->
    <div class="startAnimate">
        <div class="animate-bird"></div>
    </div>
    <!--  開始按鈕  -->
    <img id="start" src="./img/start.jpg" alt="">
    <!--  草地  -->
    <div id="banner">
        <img src="img/banner.jpg"/>
        <img src="img/banner.jpg"/>
    </div>

    <audio preload="auto"
           loop
           src="./music/game_music.mp3">
    </audio>
    <audio preload="auto"
           src="./music/game_over.mp3">
    </audio>
    <audio preload="auto"
           src="./music/bullet.mp3">
    </audio>
</div>
</body>
<script>
    var audios = document.querySelectorAll("audio");
    // 獲得開場動畫元素
    var startAnimate = document.querySelector('.startAnimate');
    // 獲得開始按鈕
    var start = document.querySelector('#start');
    // 獲得小鳥元素
    var bird = document.querySelector("#bird");
    // 獲得後臺元素
    var app = document.querySelector("#app");
    // 獲得分數元素
    var score = document.querySelectorAll("#score>img");
    // 獲得草地
    var banner = document.querySelector("#banner");
    // 向左移動的數值
    banner.distanceLeft = 0;
    // 記錄生成管道定時器
    var pipeTimer;
    // 點擊按鈕
    start.onclick = function () {
        audios[0].play();
        // 重置分數
        score[0].src = score[1].src = score[2].src = "./img/0.jpg";
        // 重置小鳥高度
        bird.style.top = "50px";
        // 清除小鳥樣式
        bird.className = null;
        // 隱藏開場動畫及開始按鈕
        startAnimate.style.display = this.style.display = 'none';
        // 小鳥顯示
        bird.style.display = 'block';
        // 小鳥下落速度,正數向下速度,負數爲向上速度
        bird.speed = 0;
        // 允許下降最大距離:57爲馬路的高度
        bird.distanceMaxDecline = app.clientHeight - 57 - bird.offsetHeight;
        // 是否死亡,初始值爲false
        bird.isDie = false;
        // 小鳥總分
        bird.scoreSum = 0;
        // 增加定時器
        bird.fly = setInterval(flyInterval.bind(bird), 30);
        // 管道定時器
        pipeTimer = setInterval(createPipe, 3000);
        // 草地移動
        banner.timer = setInterval(bannerMove, 30);
        // 爲舞臺增加點擊事件
        app.onclick = birderRise;
    }

    // 單擊舞臺的處理函數
    function birderRise() {
        audios[2].play();
        // 小鳥加速度設置爲-5,向上飛翔
        bird.speed = -5;
    }

    // 小鳥飛翔計時器
    function flyInterval() {
        // 加速度爲0.5
        this.speed += 0.5;
        // 如果速度爲正數,則下落,正數上升,設置圖片
        this.src = this.speed > 0 ? "./img/down_bird0.png" : "./img/bird0.png";
        // 小鳥下落的距離
        var distanceDecline = this.offsetTop + this.speed;
        // 如果觸地則死亡
        if (distanceDecline > this.distanceMaxDecline) {
            distanceDecline = this.distanceMaxDecline;
            // 小鳥死亡
            this.isDie = true;
        }
        // distanceDecline不允許小於0
        if (distanceDecline < 0) distanceDecline = 0;
        // 設置top值
        this.style.top = distanceDecline + "px";
        // 小鳥未亡,檢測管道是否與小鳥相撞
        if (!this.isDie) {
            var pipes = document.querySelectorAll(".pipe div");
            for (var i = 0; i < pipes.length; i++) {
                // 相撞
                if (crashFn(pipes[i])) {
                    bird.isDie = true;
                    bird.className = "die";
                    break;
                }
            }
        }
        // 判斷小鳥是否死亡
        if (bird.isDie) {
            audios[0].pause();
            audios[1].play();
            // 關閉小鳥定時器
            clearInterval(this.fly);
            // 關閉管道定時器
            clearInterval(pipeTimer);
            // 關閉草地定時器
            clearInterval(banner.timer);
            // 顯示開場動畫及開始按鈕
            startAnimate.style.display = start.style.display = 'block';
        }

    }

    // 創建管道
    function createPipe() {
        var pipe = document.createElement("div");
        pipe.className = "pipe";
        pipe.score = 1;// 指定增加分值
        // 上管道寬度
        var upHeight = getRandom(60, 263);
        // 下管道的高度
        var downHeight = app.clientHeight - 57 - 100 - upHeight;
        pipe.innerHTML = `
            <div style="height:${upHeight}px" class="pipe_up">
               <img src="./img/up_pipe.png" alt="">
            </div>
            <div style="height:${downHeight}px" class="pipe_down">
               <img src="./img/down_pipe.png" alt="">
            </div>
        `;
        // 將創建的管道放置在舞臺尾部
        app.appendChild(pipe);
        // 增加定時器,讓管道均速移動
        pipe.moveTimer = setInterval(pipeMove.bind(pipe), 30);
    }

    // 管道移動
    function pipeMove() {
        // 判斷小鳥是否死亡
        if (bird.isDie) {
            // 關閉管道移動定時器
            clearInterval(this.moveTimer)
            // 清除管道
            app.removeChild(this);
            return;
        }
        // 每次移動2像素
        var distance = this.offsetLeft - 2;
        // 讓管道開始移動
        this.style.left = distance + "px";
        // 判斷管道是否已經移出舞臺
        if (distance < -this.offsetWidth) {
            // 移除定時器
            clearInterval(this.moveTimer);
            // 移除管道
            app.removeChild(this);
        } else if (distance < -(this.offsetWidth - bird.offsetLeft)) {
            // 小鳥過了管道加分
            if (this.score > 0) {
                bird.scoreSum += this.score;
                score[0].src = "./img/" + parseInt(bird.scoreSum / 100) + ".jpg";
                score[1].src = "./img/" + parseInt((bird.scoreSum % 100) / 10) + ".jpg";
                score[2].src = "./img/" + parseInt(bird.scoreSum % 10) + ".jpg";
                this.score = 0;
            }
        }
    }

    // 草地向左移動
    function bannerMove() {
        // 向左移動的數值 (距離)+2
        banner.distanceLeft -= 2;
        // 判斷最左側圖片是否消失在舞臺中
        if (banner.distanceLeft < -app.clientWidth) {
            // 向左移動的距離爲0
            banner.distanceLeft = 0;
            // 將banner當中的第一個DOM元素放置到banner的尾部
            banner.appendChild(banner.firstElementChild);
        }
        banner.style.left = banner.distanceLeft + "px";
    }

    // 是否小鳥與柱子進行了碰撞
    function crashFn(pipe) {
        // 相撞:四個條件必須同時滿足
        // bird與pipe
        // 1- bird的右邊 大於等於 pipe的左邊
        // 2- bird的下邊 大於等於  pipe的上邊
        // 3- bird的左邊 小於等於  pipe的右邊
        // 4- bird的上邊 小於等於  pipe的下邊

        // bird:
        var birdLeft = bird.offsetLeft;//左邊
        var birdRight = birdLeft + bird.offsetWidth;// 右邊
        var birdTop = bird.offsetTop;// 上邊
        var birdBottom = birdTop + bird.offsetHeight;// 下邊

        // pipe
        var pipeLeft = pipe.parentNode.offsetLeft;
        var pipeRight = pipeLeft + pipe.offsetWidth;
        var pipeTop = pipe.offsetTop;
        var pipeBottom = pipeTop + pipe.offsetHeight;
        if (birdRight >= pipeLeft
            && birdBottom >= pipeTop
            && birdLeft <= pipeRight
            && birdTop <= pipeBottom) {
            return true;// 相撞了
        }
        return false;// 沒有相撞
    }

    // 工具函數:生成指定範圍的隨機整數
    function getRandom(min, max) {
        return Math.floor(Math.random() * (max - min + 1) + min);
    }
</script>
</html>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章