Home >Web Front-end >JS Tutorial >Detailed explanation of the whole process of implementing Fly Bird game using js

Detailed explanation of the whole process of implementing Fly Bird game using js

零下一度
零下一度Original
2017-06-26 11:21:544108browse

1. Analyze the page structure and clarify the requirements and functions

The game has three interfaces, namely the start interface, the game interface and the game end interface.

1.1 Start interface


##start.gif
  • The background of the game

  • The game title moves up and down and the bird with flapping wings

  • Start button, click to enter the game interface

  • The ground that keeps moving

    1.2 Game interface

##play.gif
    Score showing the number of obstacles crossed
  • The moving obstacles are the upper pipe and the lower pipe
  • Click on the game interface, The bird flies upward and then falls under the action of gravity.
  • When the bird collides with the pipe, the end interface pops up and the bird falls to the ground at the same time
  • 1.3 End interface

  • Game over Prompt panel
  • OK button
  • 2. Develop the "Start interface" ”

Considering the moving effect of the grass, we add two grass fields to the page

2.1 HTML

<!DOCTYPE html><html><head><meta charset="utf-8" /><title>Fly Bird</title><link rel="stylesheet" type="text/css" href="css/index.css?1.1.11"/></head><body><div id="wrapBg">  <!--游戏背景--><div id="headTitle"> <!--开始标题--><img id="headBird" src="img/bird0.png" alt="小鸟" /> <!--标题中的小鸟--></div><button id="startBtn" ></button> <!--开始按钮--><div id="grassLand1"></div> <!--草地1--><div id="grassLand2"></div> <!--草地2--></div></body></html>

2.2 CSS

#wrapBg{/*游戏背景*/width: 343px;height: 480px; margin: 0 auto;background-image:url(../img/bg.jpg);position: relative;top: 100px;overflow: hidden;
}#headTitle{/*开始标题*/width: 236px;height: 77px;background-image: url(../img/head.jpg);position: absolute; left: 53px; top: 100px;
}#headBird{/*开始标题中的小鸟*/float:right;margin-top: 25px;
}#startBtn{/*开始按钮*/width: 85px;height: 29px;padding: 0;margin: 0;background-image: url(../img/start.jpg);position: absolute;left: 129px;top: 250px;
}#grassLand1{/*草地1*/height: 14px;width: 343px;background-image: url(../img/banner.jpg);position: absolute;top: 423px;
}#grassLand2{/*草地2*/height: 14px;width: 343px;background-image: url(../img/banner.jpg);position: absolute;top: 423px;left: 343px;
}

WrapBg in overflow:hidden commented out page effect

Start interface.jpg
2.3 JS

The effect of the bird flapping its wings You need to use the principle of frame-by-frame animation

Frame-by-frame animation is a common form of animation (Frame By Frame). Its principle is to decompose animation actions in "continuous key frames", that is Draw different content frame by frame on each frame of the timeline to animate it by playing it continuously.

bird1.png
##bird0.png
2.3.1 Start the swing of the title
        var jsHeadTitle = document.getElementById("headTitle");// 获取标题var jsHeadBird = document.getElementById("headBird"); // 获取标题中小鸟var Y = 3;//标题的摆动幅度var index = 0;var imgArr = ["img/bird0.png","img/bird1.png"] //将小鸟图片路径放入一个数组,利用逐帧动画的原理做出小鸟翅膀摆动的样子var headWaveTimer = setInterval(headWave,200); //设置标题上下摆动的定时器function headWave() {
            Y *= -1;
            jsHeadTitle.style.top = jsHeadTitle.offsetTop + Y + "px";
            jsHeadBird.src = imgArr[index++];if (index == 2) {
                index = 0;
            }
        }
2.3.2 The moving grass
        var jsGrassLand1 = document.getElementById("grassLand1"); //获取草地1
        var jsGrassLand2 = document.getElementById("grassLand2"); //获取草地2

        var landTimer = setInterval(landRun,30); //让草地动起来的定时器
        function landRun() {
            if (jsGrassLand1.offsetLeft <= -343) {jsGrassLand1.style.left = "343px";
            }
            if (jsGrassLand2.offsetLeft <= -343) {jsGrassLand2.style.left = "343px";
            }jsGrassLand1.style.left = jsGrassLand1.offsetLeft - 3 + "px";jsGrassLand2.style.left = jsGrassLand2.offsetLeft - 3 + "px";
        }
2.3.3 Start button
        var jsStartBtn = document.getElementById("startBtn");
        jsStartBtn.onclick = function() { //为start按键添加点击事件处理程序
            jsHeadTitle.style.display = "none"; //隐藏标题
            clearInterval(headWaveTimer); //关闭让标题摆动的定时器
            jsStartBtn.style.display = "none"; //隐藏按键//待添加功能//点击开始按键进入游戏界面
        }
The completed effect (commented out wrapBg overflow:hidden)

##start01.gif

Next we develop the "game interface"
3 . Development of "Game Interface"


There are three elements in the game interface, namely "bird", "obstacle", and "score". We create the corresponding objects in turn.

3.1 Bird

First, create the bird object, bird.js file.

var bird = {flyTimer:null,//小鸟飞翔定时器
    wingTimer:null,//小鸟翅膀摆动定时器

    div:document.createElement("div"),showBird:function(parentObj) {this.div.style.width = "40px";this.div.style.height = "28px";this.div.style.backgroundImage = "url(img/bird0.png)";this.div.style.backgroundRepeat = "no-repeat";this.div.style.position = "absolute";this.div.style.left = "50px";this.div.style.top = "200px";this.div.style.zIndex = "1";

        parentObj.appendChild(this.div);  //将小鸟DIV插入游戏界面中
    },fallSpeed: 0, //小鸟下落速度
    flyBird: function(){ //控制小鸟飞翔下落的函数
        bird.flyTimer = setInterval(fly,40);function fly() {
            bird.div.style.top = bird.div.offsetTop + bird.fallSpeed++ + "px";if (bird.div.offsetTop < 0) {  
                bird.fallSpeed = 2; //这里用于控制小鸟不要飞出界面
            }if (bird.div.offsetTop >= 395) {
                bird.fallSpeed = 0;
                clearInterval(bird.flyTimer); //一旦飞到地面,清除定时器
                clearInterval(bird.wingTimer); //清除翅膀摆动定时器
            }if (bird.fallSpeed > 12) {
                bird.fallSpeed = 12;  //鸟的最大下落速度控制在12
            }
        }
    },wingWave: function() { //控制小鸟煽动翅膀的函数var up = ["url(img/up_bird0.png)", "url(img/up_bird1.png)"];var down = ["url(img/down_bird0.png)", "url(img/down_bird1.png)"];var i = 0, j = 0;
        bird.wingTimer = setInterval(wing,120);//逐帧动画,小鸟煽动翅膀function wing() {if (bird.fallSpeed > 0) {
                bird.div.style.backgroundImage = down[i++];if (i==2) {i = 0}
            }if (bird.fallSpeed < 0) {
                bird.div.style.backgroundImage = up[j++];if (j==2) {j = 0}
            }
        }
    },    
};

Next, load the bird when the start button is clicked. (Added based on the previous code)

jsStartBtn.onclick = function() { //为start按键添加点击事件处理程序
    jsHeadTitle.style.display = "none"; //隐藏标题
    clearInterval(headWaveTimer); //关闭让标题摆动的定时器
    jsStartBtn.style.display = "none"; //隐藏按键
    bird.showBird(jsWrapBg); //插入小鸟到界面中
    bird.flyBird(); //控制小鸟飞翔下落
    bird.wingWave(); //逐帧动画,小鸟煽动翅膀
    jsWrapBg.onclick = function(){
        bird.fallSpeed = -8;
    };//待添加功能//点击开始按键进入游戏界面
}

The effect after adding the bird

##play01.gif

3.2 Obstacles (upper pipe and lower pipe)
##block diagram.png

Obstacles are divided into upper pipes and lower pipes, as shown in the schematic diagram The structure shown is nested, so that the shape of the generated obstacle can be changed by randomly setting the height of DownDiv2 and gapHeight
block.js
function Block() {this.upDivWrap = null;this.downDivWrap = null;this.downHeight = baseObj.randomNum(0,150);//随机生成0-150之间的数,用于控制下管道的高度this.gapHeight = baseObj.randomNum(150,160);// 管道中间间隙宽度,通过调节大小,可以的控制游戏难度this.upHeight = 312 - this.downHeight - this.gapHeight;// 用来生成Div的方法this.createDiv = function(url, height, positionType, left, top) {var newDiv = document.createElement("div");
        newDiv.style.width = "62px";
        newDiv.style.height = height;
        newDiv.style.position = positionType;
        newDiv.style.left = left;
        newDiv.style.top = top;
        newDiv.style.backgroundImage = url;  //"url(/img/0.jpg)"return newDiv;
    };this.createBlock = function() {var upDiv1 = this.createDiv("url(img/up_mod.png)", this.upHeight + "px");var upDiv2 = this.createDiv("url(img/up_pipe.png)", "60px");this.upDivWrap = this.createDiv(null, null, "absolute", "450px");this.upDivWrap.appendChild(upDiv1);this.upDivWrap.appendChild(upDiv2);//生成上方管道var downDiv1 = this.createDiv("url(img/down_pipe.png)", "60px");var downDiv2 = this.createDiv("url(img/down_mod.png)", this.downHeight +"px");this.downDivWrap = this.createDiv(null, null, "absolute", "450px", 363 - this.downHeight + "px");this.downDivWrap.appendChild(downDiv1);this.downDivWrap.appendChild(downDiv2); //生成下方的管道

        jsWrapBg.appendChild(this.upDivWrap);
        jsWrapBg.appendChild(this.downDivWrap);
    };this.moveBlock = function() { //控制管道移动的方法this.upDivWrap.style.left = this.upDivWrap.offsetLeft - 3 + "px";this.downDivWrap.style.left = this.downDivWrap.offsetLeft - 3 + "px";
    };    
}
Public object file baseObj.js is used to provide random Number, and collision detection of two rectangular divs
var baseObj = {//随机数
    randomNum: function(min, max) {return parseInt(Math.random() * (max - min + 1) + min);
    },//两个矩形元素之间的碰撞检测
    rectangleCrashExamine: function (obj1, obj2) {var obj1Left = obj1.offsetLeft;var obj1Width = obj1.offsetLeft + obj1.offsetWidth;var obj1Top = obj1.offsetTop;var obj1Height = obj1.offsetTop + obj1.offsetHeight;var obj2Left = obj2.offsetLeft;var obj2Width = obj2.offsetLeft + obj2.offsetWidth;var obj2Top = obj2.offsetTop;var obj2Height = obj2.offsetTop + obj2.offsetHeight;if (!(obj1Left > obj2Width || obj1Width < obj2Left || obj1Top > obj2Height || obj1Height < obj2Top)) {return true;
            }return false;
    },
};

My idea below is to create a block when the start button is clicked, and store this block in the array
blocksArr
, in

landTimer

Timer method

landRun

Check the length of this array. If the array is not an empty array, then let all blocks in the array move. Check the distance of the last block in the array. When it reaches a certain distance, create a new block and add it to the array. Check the first block in the array. Once it reaches a certain position, remove downDivWrap and upDivWrap in the structure and delete the block in the array.

        var blocksArr = [];
        var blockDistance = baseObj.randomNum(130,250);
        var landTimer = setInterval(landRun,30); //让草地动起来的定时器
        function landRun() {
            if (jsGrassLand1.offsetLeft <= -343) {jsGrassLand1.style.left = "343px";
            }
            if (jsGrassLand2.offsetLeft <= -343) {jsGrassLand2.style.left = "343px";
            }jsGrassLand1.style.left = jsGrassLand1.offsetLeft - 3 + "px";jsGrassLand2.style.left = jsGrassLand2.offsetLeft - 3 + "px";

            if (blocksArr.length) {
                for (var i = 0; i < blocksArr.length; i++) {blocksArr[i].moveBlock();
                    var x =baseObj.rectangleCrashExamine(blocksArr[i].downDivWrap, bird.div);
                    var y = baseObj.rectangleCrashExamine(blocksArr[i].upDivWrap, bird.div);
                    var z = bird.div.offsetTop >= 390;
                    if (x || y || z) {
                        window.clearInterval(landTimer);//清除landTimer定时器bird.fallSpeed = 0; //小鸟下落jsWrapBg.onclick = null; //消除点击事件

                    }
                }
                if (blocksArr[blocksArr.length - 1].downDivWrap.offsetLeft < (450 - blockDistance)) {blockDistance = baseObj.randomNum(130,250);
                        var newBlock = new Block();
                        newBlock.createBlock();blocksArr.push(newBlock);
                }

                if (blocksArr[0].downDivWrap.offsetLeft < -50) {jsWrapBg.removeChild(blocksArr[0].downDivWrap);jsWrapBg.removeChild(blocksArr[0].upDivWrap);blocksArr.shift(blocksArr[0]);
                }
            }
        }
Current game effect

play02.gif

3.3 计分器

游戏中的计分器相对较好实现,我们就实现最大为三位数的计分器吧。
html

        <div id="score">
            <div id="num1"></div>
            <div id="num2"></div>
            <div id="num3"></div>
        </div>

css样式

#score{position:absolute;left: 130px;top:50px;z-index: 1;
}#score div{height: 39px;width: 28px;float: left;background-image: url(../img/0.jpg);display: none;
}

js

        var jsScore = document.getElementById("score");
        var jsNum1 = document.getElementById("num1");
        var jsNum2 = document.getElementById("num2");
        var jsNum3 = document.getElementById("num3");
        var score = 0;

实现计数器功能,最重要的是如何判断走过水管的数量,我们以水管的位置来判断。bird的定位left为50px,水管的宽度是62px,当水管越过小鸟的时候,水管距离它父级的定位offsetLeft 是 -12px。每当有一个水管到达此位置,score++;
在start按钮的事件处理程序中加入

jsNum1.style.display = "block";// 在点击开始之后,让计数器显示出来。
       if (blocksArr[0].downDivWrap.offsetLeft == -12) {score++;//积分面板
                if (score < 10) {jsNum1.style.backgroundImage = "url(img/" + score + ".jpg)";
            } else if (score < 100) {jsNum2.style.display = "block";jsNum1.style.backgroundImage = "url(img/" + parseInt(score/10) + ".jpg)";jsNum2.style.backgroundImage = "url(img/" + score%10 + ".jpg)";
            } else if (score < 1000) {jsNum3.style.display = "block";jsNum1.style.backgroundImage = "url(img/" + parseInt(score/100) + ".jpg)";jsNum2.style.backgroundImage = "url(img/" + parseInt(score/10)%10 + ".jpg)";jsNum3.style.backgroundImage = "url(img/" + score%10 + ".jpg)";
            }
                console.log(score);
        }

目前效果 ,计数器功能完成。


play03.gif

4.“结束界面”的开发

当小鸟和管道碰撞或者和地面碰撞时候,隐藏计分器,弹出结束面板。
结束界面主要有“结束面板”和“ok”按钮,这里需要为“ok”按钮添加点击事件。

            <div id="gameOver">
                <img src="img/game_over.jpg" alt="game over" />
                <img src="img/message.jpg" alt="message" />
                <img id="ok" src="img/ok.jpg" alt="ok" />
            </div>
#gameOver{position: absolute;top: 100px;text-align: center;display: none;z-index: 1;
}

为“OK”按钮添加事件

        jsOkBtn.onclick = function() {window.location.href = "index.html"; //刷新页面
        }

最终效果


play04.gif

有兴趣的朋友,可以加群下载代码,然后加上音效

The above is the detailed content of Detailed explanation of the whole process of implementing Fly Bird game using js. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn