目录
1.分析页面结构,理清需求和功能
1.1 开始界面
1.2 游戏界面
1.3 结束界面
2. 开发“开始界面”
2.1 HTML
2.2 CSS
2.3 JS
2.3.1 开始标题的摆动
2.3.2 移动的草地
2.3.3 Start按键
3. “游戏界面”的开发
3.1 小鸟
3.2 障碍(上管道和下管道)
3.3 计分器
4.“结束界面”的开发
首页 web前端 js教程 js实现Fly Bird游戏的全过程详解

js实现Fly Bird游戏的全过程详解

Jun 26, 2017 am 11:21 AM
javascript js 实现 小游戏

1.分析页面结构,理清需求和功能

游戏有三个界面,分别是开始界面,游戏界面和游戏结束界面。

1.1 开始界面


start.gif
  • 游戏的大背景

  • 上下移动的游戏标题和翅膀摆动的小鸟

  • start 按钮,点击进入游戏界面

  • 一直移动的地面

    1.2 游戏界面


play.gif
  • 显示越过障碍数量的计分器

  • 移动的障碍物,分别是上管道和下管道

  • 点击游戏界面,小鸟向上飞起,然后在重力作用下下坠,

  • 当小鸟和管道碰撞后,结束界面弹出,同时小鸟落到地面

    1.3 结束界面

  • Game over 提示面板

  • OK 按钮

2. 开发“开始界面”

考虑到草地的移动效果,我们在页面中加入两个草地

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中的overflow:hidden 注释掉的页面效果


开始界面.jpg

2.3 JS

小鸟煽动翅膀的效果需要用到逐帧动画的原理

逐帧动画是一种常见的动画形式(Frame By Frame),其原理是在“连续的关键帧”中分解动画动作,也就是在时间轴的每帧上逐帧绘制不同的内容,使其连续播放而成动画。


bird1.png

bird0.png
2.3.1 开始标题的摆动
        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 移动的草地
        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按键

        var jsStartBtn = document.getElementById("startBtn");
        jsStartBtn.onclick = function() { //为start按键添加点击事件处理程序
            jsHeadTitle.style.display = "none"; //隐藏标题
            clearInterval(headWaveTimer); //关闭让标题摆动的定时器
            jsStartBtn.style.display = "none"; //隐藏按键//待添加功能//点击开始按键进入游戏界面
        }
登录后复制

完成后的效果(注释掉了wrapBg中的overflow:hidden )


start01.gif


接下来我们开发“游戏界面”

3. “游戏界面”的开发

游戏界面中有三样元素,分别是“小鸟”,“障碍”,和“计分器”,我们依次来创建相应的对象。

3.1 小鸟

首先,创建小鸟的对象, bird.js 文件。

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}
            }
        }
    },    
};
登录后复制

下面,实现点击start按钮时,加载小鸟。(在之前的代码基础上添加)

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;
    };//待添加功能//点击开始按键进入游戏界面
}
登录后复制

添加小鸟后的效果


play01.gif

3.2 障碍(上管道和下管道)


block示意图.png


障碍分为上管道和下管道,如示意图所示结构嵌套,这样就可以通过随机设置DownDiv2的高度和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";
    };    
}
登录后复制

公共对象文件 baseObj.js ,用来提供随机数,和两个矩形div的碰撞检测

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;
    },
};
登录后复制

下面我的想法是在start按钮点击的时候创建一个block,把这个block存储到数组blocksArr 中,在 landTimer 定时器的方法 landRun 中检查此数组的长度,如果数组不为空数组,那么就让数组中所有的block移动。

检查数组中最后一个block离开的距离,达到一定距离,就重新new 一个block,添加到数组。

检查数组中第一个block,一旦达到一定位置,就在结构中移除downDivWrap 和 upDivWrap,同时在数组中删除block。

        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]);
                }
            }
        }
登录后复制

当前的游戏效果


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

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

以上是js实现Fly Bird游戏的全过程详解的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

华为手机如何实现双微信登录? 华为手机如何实现双微信登录? Mar 24, 2024 am 11:27 AM

华为手机如何实现双微信登录?随着社交媒体的兴起,微信已经成为人们日常生活中不可或缺的沟通工具之一。然而,许多人可能会遇到一个问题:在同一部手机上同时登录多个微信账号。对于华为手机用户来说,实现双微信登录并不困难,本文将介绍华为手机如何实现双微信登录的方法。首先,华为手机自带的EMUI系统提供了一个很便利的功能——应用双开。通过应用双开功能,用户可以在手机上同

推荐:优秀JS开源人脸检测识别项目 推荐:优秀JS开源人脸检测识别项目 Apr 03, 2024 am 11:55 AM

人脸检测识别技术已经是一个比较成熟且应用广泛的技术。而目前最为广泛的互联网应用语言非JS莫属,在Web前端实现人脸检测识别相比后端的人脸识别有优势也有弱势。优势包括减少网络交互、实时识别,大大缩短了用户等待时间,提高了用户体验;弱势是:受到模型大小限制,其中准确率也有限。如何在web端使用js实现人脸检测呢?为了实现Web端人脸识别,需要熟悉相关的编程语言和技术,如JavaScript、HTML、CSS、WebRTC等。同时还需要掌握相关的计算机视觉和人工智能技术。值得注意的是,由于Web端的计

PHP编程指南:实现斐波那契数列的方法 PHP编程指南:实现斐波那契数列的方法 Mar 20, 2024 pm 04:54 PM

编程语言PHP是一种用于Web开发的强大工具,能够支持多种不同的编程逻辑和算法。其中,实现斐波那契数列是一个常见且经典的编程问题。在这篇文章中,将介绍如何使用PHP编程语言来实现斐波那契数列的方法,并附上具体的代码示例。斐波那契数列是一个数学上的序列,其定义如下:数列的第一个和第二个元素为1,从第三个元素开始,每个元素的值等于前两个元素的和。数列的前几个元

如何在华为手机上实现微信分身功能 如何在华为手机上实现微信分身功能 Mar 24, 2024 pm 06:03 PM

如何在华为手机上实现微信分身功能随着社交软件的普及和人们对隐私安全的日益重视,微信分身功能逐渐成为人们关注的焦点。微信分身功能可以帮助用户在同一台手机上同时登录多个微信账号,方便管理和使用。在华为手机上实现微信分身功能并不困难,只需要按照以下步骤操作即可。第一步:确保手机系统版本和微信版本符合要求首先,确保你的华为手机系统版本已更新到最新版本,以及微信App

掌握Golang如何实现游戏开发的可能性 掌握Golang如何实现游戏开发的可能性 Mar 16, 2024 pm 12:57 PM

在当今的软件开发领域中,Golang(Go语言)作为一种高效、简洁、并发性强的编程语言,越来越受到开发者的青睐。其丰富的标准库和高效的并发特性使它成为游戏开发领域的一个备受关注的选择。本文将探讨如何利用Golang来实现游戏开发,并通过具体的代码示例来展示其强大的可能性。1.Golang在游戏开发中的优势作为一种静态类型语言,Golang在构建大型游戏系统

如何在Golang中实现精确除法运算 如何在Golang中实现精确除法运算 Feb 20, 2024 pm 10:51 PM

在Golang中实现精确除法运算是一个常见的需求,特别是在涉及金融计算或其它需要高精度计算的场景中。Golang的内置的除法运算符“/”是针对浮点数计算的,并且有时会出现精度丢失的问题。为了解决这个问题,我们可以借助第三方库或自定义函数来实现精确除法运算。一种常见的方法是使用math/big包中的Rat类型,它提供了分数的表示形式,可以用来实现精确的除法运算

PHP游戏需求实现指南 PHP游戏需求实现指南 Mar 11, 2024 am 08:45 AM

PHP游戏需求实现指南随着互联网的普及和发展,网页游戏的市场也越来越火爆。许多开发者希望利用PHP语言来开发自己的网页游戏,而实现游戏需求是其中一个关键步骤。本文将介绍如何利用PHP语言来实现常见的游戏需求,并提供具体的代码示例。1.创建游戏角色在网页游戏中,游戏角色是非常重要的元素。我们需要定义游戏角色的属性,比如姓名、等级、经验值等,并提供方法来操作这些

js和vue的关系 js和vue的关系 Mar 11, 2024 pm 05:21 PM

js和vue的关系:1、JS作为Web开发基石;2、Vue.js作为前端框架的崛起;3、JS与Vue的互补关系;4、JS与Vue的实践应用。

See all articles