用html5实现的flappy-bird

作者:信息技术

[Canvas前端游戏开垦]——FlappyBird详解

2016/01/03 · HTML5 · Canvas

初稿出处: xingoo   

直接想和谐做点小东西,直到眼前看了本《HTML5嬉戏开辟》,才精通游戏开采中的一小点入门知识。

本篇就本着学习的多少个样例,自身入手实施,做了个FlappyBird,源码共享在度盘 ;也得以参照github,里面有更加多的玩乐样例。

canvas 制作flappy bird(像素小鸟)全流程,canvasflappy

莫不网络早就有多少个flappy-bird的html5版本啦,到那年flappy-bird或者也绝非前边那么火了,不过作为一个新手,本人观念,本人动手写一个flappy-bird的demo依然很有成就感的。

打闹截图

图片 1

图片 2

flappy bird制作全流程:

图片 3

flappy-bird的html5版无非是经过canvas来画的,恐怕网络也许有webgl版本的,然而我平常没见过,纵然您发觉了,希望告知笔者一声,我们一同切磋钻探。在此之前在博客园上看出有大神用60几行就写出了三个demo,那让自个儿写完以往发掘本人的demo有将近200多行的代码,刹那间让作者对大神们三跪九叩的钦佩,当然作者的代码也足以简单到几十行,也就那样写出来,不便于维护,对于新人也非常难看懂。

HTML5之Canvas

Canvas是Html5中用于绘图的要素,它能够绘制各类图片,比如长方形,多边形,圆形等等。倘若想要明白Canvas的利用能够参照:

 

//假使想要使用canvas,首先供给获得上下文对象: ctx = document.getElementById('canvas').getContext('2d'); //然后使用那么些ctx绘制图形

1
2
3
//如果想要使用canvas,首先需要获得上下文对象:
ctx = document.getElementById('canvas').getContext('2d');
//然后使用这个ctx绘制图形

在cavas每种绘制都以单独的操作。举例下图的四个绘制图形,第四个会以遮掩的花样绘制,因而制图图形的次第就呈现格外最重要了。

图片 4

一、前言

像素小鸟这些轻易的游艺于二零一五年在互联网上爆红,游戏上线一段时间内appleStore上的下载量一度抵达四千万次,风靡一时,

近来移动web的推广为那样未有复杂逻辑和小巧动画效果,然而野趣十足的小游戏提供了一举两得的条件,

相同的时间依靠各大社交软件平台的传播效应,创新意识不断的小游戏有着不错的营销效果与利益,获得了不菲的关怀。

原先在网络查询了无数有关那一个小游戏的材料,可是大多非常不佳,自个儿的结缘有关课程将以此娱乐的显要框架整理出来,供大家一同读书。

html代码作者就不写了,我们也都知情,假若您连html代码也供给的话,那你接下去也就没供给看了,还不及直接跳转到w3school.com.cn。

canvas之drawImage()

本篇的二十二日游开荒中,主要选用的是基于图片绘制的api:drawImage(),它有多少个宗旨的应用办法:

ctx.drawImage(image,this.bx,this.by,this.bwidth,this.bheight); ctx.drawImage(image,x,y,width,height,this.px,this.py,this.pwidth,this.pheight);

1
2
ctx.drawImage(image,this.bx,this.by,this.bwidth,this.bheight);
ctx.drawImage(image,x,y,width,height,this.px,this.py,this.pwidth,this.pheight);

首先个api中,钦赐Image对象,然后给出绘制图片的x,y坐标以及宽度和可观就可以。

第贰个api中,第一组x,y,width,height则钦点了裁剪图片的坐标尺寸,那在运用多成分的矢量图时很常用。比如:

图片 5

地点的图样中为了收缩图片能源的伏乞数量,把广大的要素放在了四个图片中,此时就必要通过裁剪的办法,获取钦定的图样成分。

二、能力中央

 基本JavaScript基础 ,canvas 基础, 面向对象的惦念;

接下去正是主要的js了,至于css吗?你掌握的css对于canvas是低效的,那笔者干嘛还写css呢,那不是浪费生命啊

Flappy伯德原理深入分析

实质上那一个游乐很简短,一张图就可以看懂个中的神妙:

图片 6

里面背景和本地是不动的。

鸟类唯有上和下四个动作,能够经过决定小鸟的y坐标实现。

上下的管敬仲只会向左移动,为了简单完结,游戏中七个镜头仅仅会现出一些管敬仲,那样当管仲移出左侧的背景框,就自动把管仲放在最侧面!

if(up_pipe.px+up_pipe.pwidth>0){ up_pipe.px -= velocity; down_pipe.px -= velocity; }else{ up_pipe.px = 400; down_pipe.px = 400; up_pipe.pheight = 100+Math.random()*200; down_pipe.py = up_pipe.pheight+pipe_height; down_pipe.pheight = 600-down_pipe.py; isScore = true; }

1
2
3
4
5
6
7
8
9
10
11
if(up_pipe.px+up_pipe.pwidth>0){
                up_pipe.px -= velocity;
                down_pipe.px -= velocity;
            }else{
                up_pipe.px = 400;
                down_pipe.px = 400;
                up_pipe.pheight = 100+Math.random()*200;
                down_pipe.py = up_pipe.pheight+pipe_height;
                down_pipe.pheight = 600-down_pipe.py;
                isScore = true;
            }

很简短吗!

鉴于该游戏一共就那多少个要素,由此把她们都放入贰个Objects数组中,通过setInteral()方法,在断定间隔时间内,奉行一次重绘

重绘的时候会先消除画面中的全体因素,然后依据新的要素的坐标一回绘制图形,这样就能产出活动的效果与利益。

三、思路整理

一初阶首先定义bird对象,建议用构造函数的法子,当然你也能够用工厂函数,那没怎么关联的

模仿小鸟重力

由于那个游戏不关乎小鸟横向的移动,因而一旦模拟出小鸟下跌的动作以及上涨的动作就足以了。

图片 7

上升:那个一点也不细略,只要把小鸟的y坐标减去断定的值就足以了

下落:其实重力不必要利用gt^2来模拟,能够省略的钦命多个变量,v1和gravity,那四个变量与setInterval()中的时间共同效能,就会效仿引力。

ver2 = ver1+gravity; bird.by += (ver2+ver1)*0.5;

1
2
ver2 = ver1+gravity;
bird.by += (ver2+ver1)*0.5;

成套游戏的逻辑相比较轻易:

先是游戏法则:鸟撞到管道上,地上要与世长辞,飞到显示器外要谢世。

说不上:鸟在飞翔的历程中,会掉落,类似落体运动,需求游戏发烧友不断点击显示屏让鸟向上飞。

再次就是:鸟和背景成分的相持移动的历程,鸟不动,背景左移。

  1. var Bird = function (param) {  
  2.                 this.x = param.x || 0;  
  3.                 this.y = param.y || 0;  
  4.                 this.w = param.w;  
  5.                 this.h = param.h;  
  6.                 this.yDir = param.yDir || 1;  
  7.                 this.img = param.img;  
  8.   
  9.                 return this;  
  10.             }  

碰撞检验

打闹中型小型鸟蒙受管敬仲大概本地都会算游戏结束:

图片 8

其中条件1上管道的检查测量试验为:

((bird.bx+bird.bwidth>up_pipe.px)&&(bird.by>up_pipe.py)&&(bird.bx+bird.bwidth<up_pipe.px+up_pipe.pwidth)&&(bird.by<up_pipe.py+up_pipe.pheight))|| ((bird.bx+bird.bwidth>up_pipe.px)&&(bird.by>up_pipe.py)&&(bird.bx+bird.bwidth<up_pipe.px+up_pipe.pwidth)&&(bird.by<up_pipe.py+up_pipe.pheight))

1
2
((bird.bx+bird.bwidth>up_pipe.px)&&(bird.by>up_pipe.py)&&(bird.bx+bird.bwidth<up_pipe.px+up_pipe.pwidth)&&(bird.by<up_pipe.py+up_pipe.pheight))||
((bird.bx+bird.bwidth>up_pipe.px)&&(bird.by>up_pipe.py)&&(bird.bx+bird.bwidth<up_pipe.px+up_pipe.pwidth)&&(bird.by<up_pipe.py+up_pipe.pheight))

条件2下管道的检查实验为:

((bird.bx>down_pipe.px)&&(bird.by>down_pipe.py)&&(bird.bx<down_pipe.px+down_pipe.pwidth)&&(bird.by<down_pipe.py+down_pipe.pheight))|| ((bird.bx>down_pipe.px)&&(bird.by+bird.bheight>down_pipe.py)&&(bird.bx<down_pipe.px+down_pipe.pwidth)&&(bird.by+bird.bheight<down_pipe.py+down_pipe.pheight))

1
2
((bird.bx>down_pipe.px)&&(bird.by>down_pipe.py)&&(bird.bx<down_pipe.px+down_pipe.pwidth)&&(bird.by<down_pipe.py+down_pipe.pheight))||
((bird.bx>down_pipe.px)&&(bird.by+bird.bheight>down_pipe.py)&&(bird.bx<down_pipe.px+down_pipe.pwidth)&&(bird.by+bird.bheight<down_pipe.py+down_pipe.pheight))

条件3地面的检查实验最简易,为:

bird.by+bird.bheight>ground.bgy

1
bird.by+bird.bheight>ground.bgy

假设满足那四个原则,即便游戏停止,会消除循环以及提示游戏截止新闻。

将全方位游戏细化:

我们选用面向对象的思路来制作,具体的事物用构造函数来创立,方法放到构造函数的原形对象中。

娱乐细化那么些进度不是一下子就化解了的,如若在向来不相关指点的处境下,本人要不断的构成自身的主见去试错。

自身使用的办法是使用Xmind将流程以脑图的格局绘制下来,分块去做,不断细化记录自个儿的笔触,最后呈现的效劳如下:

(顺序遵照图片中的序号去看  脑图、素材、及全部源码下载地址: 想练习的同班能够点这里)

脑图分为三大块:1、策动阶段 2、主函数 3、游戏优化。

图片 9

图片 10

 

 

创制一个bird的构造函数,传入参数param 并回到this,参数param是连锁的陈设参数。

分数总结

分数的图谋与碰撞检验类似,设置三个开关,当管敬仲重新出现时,设置为true。当分值加1时,设置为false。

鸟类的最侧边的x坐标要是赶过了管敬仲的x+width,就认为成功通过。

if(isScore && bird.bx>up_pipe.px+up_pipe.pwidth){ score += 1; isScore = false; if(score>0 && score%10 === 0){ velocity++; } }

1
2
3
4
5
6
7
if(isScore && bird.bx>up_pipe.px+up_pipe.pwidth){
                score += 1;
                isScore = false;
                if(score>0 && score%10 === 0){
                    velocity++;
                }
            }

通过后,分值加1,速度+1。

 四、游戏完毕:

现今整合脑图来逐步落实我们的娱乐。

1.安装canvas画布,计划图片数据,当图片加载成功后试行回调函数;

图片 11<canvas id="cvs" width="800" height="600"></canvas> <script> var imglist = [ { "name":"birds","src":"res/birds.png"}, { "name":"land","src":"res/land.png"}, { "name":"pipe1","src":"res/pipe1.png"}, { "name":"pipe2","src":"res/pipe2.png"}, { "name":"sky","src":"res/sky.png"} ]; var cvs = document.getElementById("cvs"); var ctx = cvs.getContext("2d"); </script> 画布筹算,图片数据打算

此地那些入口函数的设置要小心,必需确认保障图片能源加载成功后再执行别的操作,每加载一张图片大家让imgCount--,减到0的时候再施行主函数;

图片 12function load (source, callback ){ var imgEls={}; var imgCount=source.length; for (var i = 0; i < imgCount; i++) { var name = source[i].name; var newImg = new Image (); newImg.src = source[i].src; imgEls[name] = newImg; imgEls[name].addEventListener("load",function(){ imgCount--; if(imgCount==0){ callback(imgEls); }; }) }; }; 入口函数设置

主循环的设置:这里大家不利用setInterval来支配循环次数,大家选择二个叫requestAnimationFrame()的电火花计时器

       因为setInterval会时有产生时间基值误差,setInterval只好依靠时间来移动固定距离。

       那对于轮播图一类几千飞秒切换一回的动作来说并不曾什么关系,可是对于大家16-18微秒绘制贰遍的动画片是那叁个不确切的;

       requestAnimationFrame()这一个电磁打点计时器的功利是依靠浏览器的个性来试行贰个函数,大家用来得到两回绘制的间隔时间;

       移动距离的一个钱打二拾柒个结改产生速度×间隔时间的艺术,来缓和绘图不可相信的难题。

图片 13var preTime= Date.now(); //获取当今日子 function run(){ var now = Date.now(); //获取最新时刻 dt = now - preTime; //获取时间距离 preTime = now; //更新当前岁月 ctx.clearRect(0,0,800,600); //清空画布 //--------------------------------------------- 绘制代码施行区域 //----------------------------------------------- requestAnimationFrame(run); //再一次实践run函数 } requestAnimationFrame(run); //第二次推行run函数; 设置绘制方式

2、主函数分为两片段成效,轻便说正是把图画上去,然后管理动态效果,再决断一下是否违犯禁令。

2.1 小鸟的绘图:

  小鸟自己有三个双翅扇动的机能,和三个下滑的经过。

  双翅扇动的进程是一张Smart图三幅画面包车型地铁的切换(设置贰个index属性,调控Smart图的岗位),下落进度是其y坐标在画布上的移位();

  所以小鸟的构造函数中应当包罗(图源,x坐标,y坐标,速度,下落加快度,ctx(context画布))等参数。

  这里必要专心几点:

  •  小鸟的绘图选取canvas drawImage的九参数格局(分别是图形,原图的裁切起源,原图的宽高,贴到画布上的职位,贴到画布上的宽高);
  •  小鸟的双翅扇动不可能太快,所以大家设置三个阀门函数,当累计计时当先100ms的时候切换一下图纸,然后在让一同计时减去100ms;
  •  小鸟的暴跌必要动用一定物理知识,但是都不会细小略啦。 大家皆以经过速度×时间来兑现;

图片 14var Bird= function (img,x,y,speed,a,ctx){ this.img = img; this.x = x; this.y = y; this.speed = speed; this.a =a ; this.ctx = ctx; this.index = 0; //用于创设小鸟扇双翅的动作 } Bird.prototype.draw = function (){ this.ctx.drawImage( this.img,52*this.index,0,52,45, this.x,this.y,52,45 ) } var durgather=0; Bird.prototype.update = function(dur){ //小鸟羽翼扇动每100ms切换一张图纸 durgather+=dur; if(durgather>100){ this.index++; if(this.index===2){ this.index=0; } durgather -= 100; } //小鸟下降动作 this.speed = this.speed + this.a *dur; this.y = this.y + this.speed * dur; } 小鸟的构造函数及动作调控

  构造二个鸟类,而且将其动作刷新函数和制图函数放置在我们地点提到的绘图区域,此后布局出的相近对象都以这么的操作步骤:

  这里须求小心的一些是,怎么着让鸟儿顺畅的升华飞翔,其实仍旧情理知识,由于加快度的职能,大家给小鸟一个提升的顺时速度就足以了。

图片 15load(imglist ,function(imgEls){ //制造对象 //在主函数中开创一个鸟类 var bird = new Bird(imgEls["birds"],150,100,0.0003,0.0006,ctx); //主循环 var preTime= Date.now(); function run(){ var now = Date.now(); dt = now - pre提姆e; preTime = now; ctx.clearRect(0,0,800,600); //--------图片绘制区域------- bird.update(dt) bird.draw(); //------------------------- requestAnimationFrame(run); } requestAnimationFrame(run); //设置点击事件。给小鸟八个转眼的提升速度 cvs.addEventListener("click",function(){ bird.speed = -0.3; } ) }) 绘制小鸟,点击小鸟上海飞机创制厂

作用如下:

图片 16

2.2天上的绘图:

  天空的绘图相比较轻巧了,只要采纳canvas drawImage的三参数方式就能够(图源,画布上的坐标)。

  这里独一潜心的有个别是,无缝滚动的达成,对于800*600分辨率这种状态大家创设三个天空对象就可以了,不过为了适配越多的图景,大家将那一个效率写活

  在天宇的构造函数上加八个count属性设置多少个天空图片,count属性让实例通过原形中的方法访问。后边涉及到再现的地面和管道,都给它们增进这种思量。

图片 17var Sky = function(img,x,speed,ctx) { this.img = img ; this.ctx = ctx; this.x = x; this.speed = speed; } Sky.prototype.draw = function(){ this.ctx.drawImage( this.img ,this.x,0 ) } Sky.prototype.setCount = function(count){ Sky.count = count; } Sky.prototype.update = function(dur){ this.x = this.x+ this.speed * dur; if(this.x<-800){ //天空图片的大幅度是800 this.x = Sky.count * 800 + this.x; //当向左移动了一整张图纸后即时切回第一张图片 } } 天空构造函数及移动函数

  同理在主函数中创建2个天空对象,并将革新函数和制图函数放置在主循环的绘图区域;

  setcount是用来设置无缝滚动的

  注意一点:绘制上的图纸是有一个层级关系的,不能够把鸟画到天空的下面,那本来最后画鸟了,上面涉及到的掩盖难点不再特地提到。

  这里仅插入部分连锁代码

图片 18var bird = new Bird(imgEls["birds"],150,100,0.0003,0.0006,ctx); var sky1 = new Sky(imgEls["sky"],0,-0.3,ctx); var sky2 = new Sky(imgEls["sky"],800,-0.3,ctx); //主循环 var preTime= Date.now(); function run(){ var now = Date.now(); dt = now - preTime; preTime = now; ctx.clearRect(0,0,800,600); //--------图片绘制区域------- sky1.update(dt); sky1.draw() sky2.update(dt); sky2.draw() sky1.setCount(2); bird.update(dt) bird.draw(); //------------------------- 绘制天空

2.3 地面包车型大巴绘图

  和天上的绘图完全平等,由于地方图片尺寸一点都不大,所以大家要多画多少个

图片 19var Land = function(img,x,speed,ctx){ this.img = img ; this.x = x; this.speed = speed; this.ctx = ctx ; } Land.prototype.draw = function(){ this.ctx.drawImage ( this.img , this.x ,488 ) } Land.prototype.setCount= function(count){ Land.count = count; } Land.prototype.update = function(dur){ this.x = this.x + this.speed * dur; if (this.x <- 336){ this.x = this.x + Land.count * 336; //无缝滚动的贯彻 } } 地面包车型的士构造函数及运动函数 图片 20//创制----放置在开创区域 var land1 = new Land(imgEls["land"],0,-0.3,ctx); var land2 = new Land(imgEls["land"],336*1,-0.3,ctx); var land3 = new Land(imgEls["land"],336*2,-0.3,ctx); var land4 = new Land(imgEls["land"],336*3,-0.3,ctx); //绘制 ----放置在绘制区域 land1.update(dt); land1.draw(); land2.update(dt); land2.draw(); land3.update(dt); land3.draw(); land4.update(dt); land4.draw(); land1.setCount(4); //设置无缝滚动 绘制地面主要代码

2.4绘制管道

  管道的绘图有二个难点是管道高度的规定

  要点:

  •  为了保障游戏可玩性,管道必需有三个牢固中度+一个随便中度,且上下管道之间的留白是原则性的宽窄。
  • 管道不是三回九转的,七个相邻的管道之间有距离
  • 留心管道在无缝播放,抽回后必需交给贰个新的妄动中度,给顾客一种错觉,感到又贰个管道飘了过来。

  

图片 21var Pipe = function(upImg,downImg,x,speed,ctx){ this.x = x; this.upImg = upImg ; this.downImg = downImg; this.speed = speed; this.ctx = ctx; this.r = Math.random() *200 + 100; //随机中度+固定中度 } Pipe.prototype.draw = function(){ this.ctx.drawImage( this.upImg, this.x , this.r - 420 //管道图片的尺寸是420 ) this.ctx.drawImage( this.downImg, this.x , this.r +150 //管道中国建工业总集合团的留白是150px ) } Pipe.prototype.setCount = function( count,gap ){ Pipe.count = count; Pipe.gap = gap; //这里是此番绘制的非常之处,出席了区间 } Pipe.prototype.update =function( dur ){ this.x = this.x + this.speed*dur; if(this.x <- 52){ //管道宽度52px this.x = this.x + Pipe.count * Pipe.gap; //无缝滚动 this.r = Math.random() *200 + 150; //切换后的管道必得重新安装一个冲天,给客商三个新管道的错觉 } } 管道的构造函数及运动函数 图片 22//创造区域 var pipe1 = new Pipe(imgEls["pipe2"],imgEls["pipe1"],400, -0.1,ctx); var pipe2 = new Pipe(imgEls["pipe2"],imgEls["pipe1"],600, -0.1,ctx); var pipe3 = new Pipe(imgEls["pipe2"],imgEls["pipe1"],800, -0.1,ctx); var pipe4 = new Pipe(imgEls["pipe2"],imgEls["pipe1"],1000,-0.1,ctx); var pipe5 = new Pipe(imgEls["pipe2"],imgEls["pipe1"],1200,-0.1,ctx); //绘制区域 pipe1.update(dt); pipe1.draw(); pipe2.update(dt); pipe2.draw(); pipe3.update(dt); pipe3.draw(); pipe4.update(dt); pipe4.draw(); pipe5.update(dt); pipe5.draw(); pipe1.setCount(5,200); //设置管道数量和距离 管道的绘图首要代码

到这一步大家的主要性画面就制作出来了,是否很简短呢O(∩_∩)O~

2.5 判定游戏是不是违犯禁令

图片 23 //大家改动一下主循环,设置叁个gameover为false来支配函数的实行//任何违规都会触发gameover=true; var gameover = false; if(bird.y < 0 || bird.y > 488 -45/2 ){ //遭逢天和地 gameover = true ; } if(!gameover){ //若无终结游戏则接二连三玩乐 requestAnimationFrame(run); } 简单判读gameover

  2. 遇见管道甘休游戏

图片 24//x和y到时候大家传入小鸟的运动轨迹,每趟重绘管道都有咬定 Pipe.prototype.hitTest = function(x,y){ return (x > this.x && x < this.x + 52) //在管仲横向中间 &&(! (y >this.r && y < this.r +150)); //在管仲竖向中间 } 剖断是还是不是碰着管仲 图片 25 var gameover = false; gameover = gameover || pipe1.hitTest(bird.x ,bird.y); gameover = gameover || pipe2.hitTest(bird.x ,bird.y); gameover = gameover || pipe3.hitTest(bird.x ,bird.y); gameover = gameover || pipe4.hitTest(bird.x ,bird.y); gameover = gameover || pipe5.hitTest(bird.x ,bird.y); //逻辑终端 if(bird.y < 0 || bird.y > 488 -45/2 ){ gameover = true ; } if(!gameover){ requestAnimationFrame(run); } 主循环的评定榜样构成

图片 26

到这一步大家的游乐造成的大半了,剩下的就是有个别数目标匡正

主要须要改良的一个点是冲击的谋算,因为我们全数的撞击都以比照小鸟图片的左上角总计的,那样就能有不标准的主题材料,通过测验很轻易将这么些距离加减校勘了

 

3.游戏的优化

 小鸟游戏的鸟类在左右的长河中会随着点击,抬头飞翔,或投降冲锋,怎么做到这几个效果呢?

 答案就是移动canvas 坐标系和抉择坐标系的角度  ctx.translate()和ctx.rotate();

 为了制止全部坐标系的共同体旋转运动

 供给在小鸟绘制函数Bird.prototype.draw里眼前后端参与ctx.save() 和ctx.restore()来单独主宰小鸟画布

图片 27Bird.prototype.draw = function (){ this.ctx.save(); this.ctx.translate(this.x ,this.y); //坐标移动到小鸟的核心点上 this.ctx.rotate((Math.PI /6) * this.speed / 0.3 ); //小鸟最大旋转30度,并乘机速度实时退换角度 this.ctx.drawImage( this.img,52*this.index,0,52,45, -52/2,-45/2,52,45 //这里非常重大的一些是,整个小鸟坐标系初阶活动 ) this.ctx.restore(); } 参预小鸟旋转效果

理所必然最终不要忘记对管道碰撞的论断,在此间再修正叁遍。

实际上假若希图加入旋转效果,上三次的改进无需,你会意识多数重复工。

最终做出的效果如下:

图片 28

 主体效能和逻辑已经全副达成。更加的多的效果与利益能够自行增多。

 假使想和煦集会练习一下,请点击游戏细化部分的链接下载相关材质和全部源码。

制作flappy bird(像素小鸟)全流程,canvasflappy flappy bird制作全流程: 一、前言 像素小鸟这些轻巧的游乐于2015年在互连网上爆红,游戏上...

 

成套源码

<!DOCTYPE html> <html> <head> <title>Flappy Bird</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript"> // Edit by xingoo // Fork on my github: var ctx; var cwidth = 400; var cheight = 600; var objects = []; var birdIndex = 0; var ver1 = 10; var ver2; var gravity = 2; var pipe_height = 200; var velocity = 10; var tid; var score = 0; var isScore = false; var birds = ["./images/0.gif","./images/1.gif","./images/2.gif"]; var back = new Background(0,0,400,600,"./images/bg.png"); var up_pipe = new UpPipe(0,0,100,200,"./images/pipe.png"); var down_pipe = new DownPipe(0,400,100,200,"./images/pipe.png"); var ground = new Background(0,550,400,200,"./images/ground.png"); var bird = new Bird(80,300,40,40,birds); objects.push(back); objects.push(up_pipe); objects.push(down_pipe); objects.push(ground); objects.push(bird); function UpPipe(x,y,width,height,img_src){ this.px = x; this.py = y; this.pwidth = width; this.pheight = height; this.img_src = img_src; this.draw = drawUpPipe; } function DownPipe(x,y,width,height,img_src){ this.px = x; this.py = y; this.pwidth = width; this.pheight = height; this.img_src = img_src; this.draw = drawDownPipe; } function drawUpPipe(){ var image = new Image(); image.src = this.img_src; ctx.drawImage(image,150,500,150,800,this.px,this.py,this.pwidth,this.pheight); } function drawDownPipe(){ var image = new Image(); image.src = this.img_src; ctx.drawImage(image,0,500,150,500,this.px,this.py,this.pwidth,this.pheight); } function Background(x,y,width,height,img_src){ this.bgx = x; this.bgy = y; this.bgwidth = width; this.bgheight = height; var image = new Image(); image.src = img_src; this.img = image; this.draw = drawbg; } function drawbg(){ ctx.drawImage(this.img,this.bgx,this.bgy,this.bgwidth,this.bgheight); } function Bird(x,y,width,height,img_srcs){ this.bx = x; this.by = y; this.bwidth = width; this.bheight = height; this.imgs = img_srcs; this.draw = drawbird; } function drawbird(){ birdIndex++; var image = new Image(); image.src = this.imgs[birdIndex%3]; ctx.drawImage(image,this.bx,this.by,this.bwidth,this.bheight); } function calculator(){ if(bird.by+bird.bheight>ground.bgy || ((bird.bx+bird.bwidth>up_pipe.px)&&(bird.by>up_pipe.py)&&(bird.bx+bird.bwidth<up_pipe.px+up_pipe.pwidth)&&( bird.by<up_pipe.py+up_pipe.pheight))|| ((bird.bx+bird.bwidth>up_pipe.px)&&(bird.by>up_pipe.py)&&(bird.bx+bird.bwidth<up_pipe.px+up_pipe.pwidth)&&( bird.by<up_pipe.py+up_pipe.pheight))|| ((bird.bx>down_pipe.px)&&(bird.by>down_pipe.py)&&(bird.bx<down_pipe.px+down_pipe.pwidth)&&(bird.by<down_pipe.py+down_pipe.pheight))|| ((bird.bx>down_pipe.px)&&(bird.by+bird.bheight>down_pipe.py)&&(bird.bx<down_pipe.px+down_pipe.pwidth)&&(bird.by+bird.bheight<down_pipe.py+down_pipe.pheight))){ clearInterval(tid); ctx.fillStyle = "rgb(255,255,255)"; ctx.font = "30px Accent"; ctx.fillText("You got "+score+"!",110,100) return; } ver2 = ver1+gravity; bird.by += (ver2+ver1)*0.5; if(up_pipe.px+up_pipe.pwidth>0){ up_pipe.px -= velocity; down_pipe.px -= velocity; }else{ up_pipe.px = 400; down_pipe.px = 400; up_pipe.pheight = 100+Math.random()*200; down_pipe.py = up_pipe.pheight+pipe_height; down_pipe.pheight = 600-down_pipe.py; isScore = true; } if(isScore && bird.bx>up_pipe.px+up_pipe.pwidth){ score += 1; isScore = false; if(score>0 && score%10 === 0){ velocity++; } } ctx.fillStyle = "rgb(255,255,255)"; ctx.font = "30px Accent"; if(score>0){ score%10!==0?ctx.fillText(score,180,100):ctx.fillText("Great!"+score,120,100); } } function drawall(){ ctx.clearRect(0,0,cwidth,cheight); var i; for(i=0;i<objects.length;i++){ objects[i].draw(); } calculator(); } function keyup(e){ var e = e||event; var currKey = e.keyCode||e.which||e.charCode; switch (currKey){ case 32: bird.by -= 80; break; } } function init(){ ctx = document.getElementById('canvas').getContext('2d'); document.onkeyup = keyup; drawall(); tid = setInterval(drawall,80); } </script> </head> <body onLoad="init();"> <canvas id="canvas" width="400" height="600" style="margin-left:200px;"> Your browser is not support canvas! </canvas> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
<!DOCTYPE html>
<html>
<head>
    <title>Flappy Bird</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script type="text/javascript">
        // Edit by xingoo
        // Fork on my github:https://github.com/xinghalo/CodeJS/tree/master/HTML5
        var ctx;
        var cwidth = 400;
        var cheight = 600;
        var objects = [];
        var birdIndex = 0;
        var ver1 = 10;
        var ver2;
        var gravity = 2;
        var pipe_height = 200;
        var velocity = 10;
        var tid;
        var score = 0;
        var isScore = false;
        var birds = ["./images/0.gif","./images/1.gif","./images/2.gif"];
        var back = new Background(0,0,400,600,"./images/bg.png");
        var up_pipe = new UpPipe(0,0,100,200,"./images/pipe.png");
        var down_pipe = new DownPipe(0,400,100,200,"./images/pipe.png");
        var ground = new Background(0,550,400,200,"./images/ground.png");
        var bird = new Bird(80,300,40,40,birds);
        objects.push(back);
        objects.push(up_pipe);
        objects.push(down_pipe);
        objects.push(ground);
        objects.push(bird);
        function UpPipe(x,y,width,height,img_src){
            this.px = x;
            this.py = y;
            this.pwidth = width;
            this.pheight = height;
            this.img_src = img_src;
            this.draw = drawUpPipe;
        }
        function DownPipe(x,y,width,height,img_src){
            this.px = x;
            this.py = y;
            this.pwidth = width;
            this.pheight = height;
            this.img_src = img_src;
            this.draw = drawDownPipe;
        }
        function drawUpPipe(){
            var image = new Image();
            image.src = this.img_src;
            ctx.drawImage(image,150,500,150,800,this.px,this.py,this.pwidth,this.pheight);
        }
        function drawDownPipe(){
            var image = new Image();
            image.src = this.img_src;
            ctx.drawImage(image,0,500,150,500,this.px,this.py,this.pwidth,this.pheight);
        }
        function Background(x,y,width,height,img_src){
            this.bgx = x;
            this.bgy = y;
            this.bgwidth = width;
            this.bgheight = height;
            var image = new Image();
            image.src = img_src;
            this.img = image;
            this.draw = drawbg;
        }
        function drawbg(){
            ctx.drawImage(this.img,this.bgx,this.bgy,this.bgwidth,this.bgheight);
        }
        function Bird(x,y,width,height,img_srcs){
            this.bx = x;
            this.by = y;
            this.bwidth = width;
            this.bheight = height;
            this.imgs = img_srcs;
            this.draw = drawbird;
        }
        function drawbird(){
            birdIndex++;
            var image = new Image();
            image.src = this.imgs[birdIndex%3];
            ctx.drawImage(image,this.bx,this.by,this.bwidth,this.bheight);
        }
        function calculator(){
            if(bird.by+bird.bheight>ground.bgy ||
                ((bird.bx+bird.bwidth>up_pipe.px)&&(bird.by>up_pipe.py)&&(bird.bx+bird.bwidth<up_pipe.px+up_pipe.pwidth)&&(    bird.by<up_pipe.py+up_pipe.pheight))||
                ((bird.bx+bird.bwidth>up_pipe.px)&&(bird.by>up_pipe.py)&&(bird.bx+bird.bwidth<up_pipe.px+up_pipe.pwidth)&&(    bird.by<up_pipe.py+up_pipe.pheight))||
                ((bird.bx>down_pipe.px)&&(bird.by>down_pipe.py)&&(bird.bx<down_pipe.px+down_pipe.pwidth)&&(bird.by<down_pipe.py+down_pipe.pheight))||
                ((bird.bx>down_pipe.px)&&(bird.by+bird.bheight>down_pipe.py)&&(bird.bx<down_pipe.px+down_pipe.pwidth)&&(bird.by+bird.bheight<down_pipe.py+down_pipe.pheight))){
                clearInterval(tid);
                ctx.fillStyle = "rgb(255,255,255)";
                ctx.font = "30px Accent";
                ctx.fillText("You got "+score+"!",110,100)
                return;
            }
            ver2 = ver1+gravity;
            bird.by += (ver2+ver1)*0.5;
            if(up_pipe.px+up_pipe.pwidth>0){
                up_pipe.px -= velocity;
                down_pipe.px -= velocity;
            }else{
                up_pipe.px = 400;
                down_pipe.px = 400;
                up_pipe.pheight = 100+Math.random()*200;
                down_pipe.py = up_pipe.pheight+pipe_height;
                down_pipe.pheight = 600-down_pipe.py;
                isScore = true;
            }
            if(isScore && bird.bx>up_pipe.px+up_pipe.pwidth){
                score += 1;
                isScore = false;
                if(score>0 && score%10 === 0){
                    velocity++;
                }
            }
            ctx.fillStyle = "rgb(255,255,255)";
            ctx.font = "30px Accent";
            if(score>0){
                score%10!==0?ctx.fillText(score,180,100):ctx.fillText("Great!"+score,120,100);
            }
        }
        function drawall(){
            ctx.clearRect(0,0,cwidth,cheight);
            var i;
            for(i=0;i<objects.length;i++){
                objects[i].draw();
            }
            calculator();
        }
        function keyup(e){
            var e = e||event;
               var currKey = e.keyCode||e.which||e.charCode;
               switch (currKey){
                case 32:
                    bird.by -= 80;
                    break;
            }
        }    
        function init(){
            ctx = document.getElementById('canvas').getContext('2d');
            document.onkeyup = keyup;
            drawall();
            tid = setInterval(drawall,80);
        }
    </script>
</head>
<body onLoad="init();">
<canvas id="canvas" width="400" height="600" style="margin-left:200px;">
    Your browser is not support canvas!
</canvas>
</body>
</html>

接下去是bird的draw属性,这几个天性主固然将bird给画出来

总结

在攻读玩乐支付的时候,小编蓦地挂念起高校的大意。那时很狐疑,学Computer学如何物理,后来再触及游戏开荒才知道,未有一定的大意知识,根本无法模拟游戏中的各类场景。

而由此这么些轻易的小游戏,也捡起来了累累旧文化。

  1. Bird.prototype.draw = function () {  
  2.   
  3.                 ctx.drawImage(this.img, 0, 0, this.img.width, this.img.height, this.x, this.y, this.w, this.h);  
  4.   
  5.                 return this;  
  6.             };  

参考

【1】:Canvas参考手册

【2】:《HTML5玩耍支付》

【3】:EdisonChou的FlappyBird

2 赞 6 收藏 评论

图片 29

ok,就那样轻易,只是简短的调用canvas的drawImage方法

 

接下去正是bird的jump属性,那特特性首借使调整bird的下挫,模仿小鸟的下挫

  1. Bird.prototype.jump = function () {  
  2.                 this.y += this.yDir;  
  3.                 this.draw();  
  4.   
  5.                 return this;  
  6.             }  

不容争辩,照旧这么简单,正是修改y参数,然后调用draw方法,额,其实jump方法和draw方法是能够统一的,但是为了未来的恢弘大概,修改方便,笔者要么选拔分手了。当然就算合併了,笔者的代码又能够少几行了。

 

地点就完了了bird对象的定义,没有错,已经成功了,就一些代码而已。未有太多

本文由杏彩发布,转载请注明来源

关键词: