唯独趣味十足的小游戏提供了不错的条件,不过趣味十足的小游戏提供了要得的环境

flappy bird制作全流程:

图片 1

flappy bird制作全流程:

图片 2

一、前言

像素小鸟这一个简单的嬉戏于二零一四年在网络上爆红,游戏上线一段时间内appleStore上的下载量一度达到四千万次,风靡一时半刻,

近些年移动web的推广为这么没有复杂逻辑和精密动画效果,不过趣味十足的小游戏提供了特出的环境,

与此同时借助各大社交软件平台的传播效应,创新意识不断的小游戏有着精良的经营销售效益,获得了广大的关切。

先前在网上查询了重重有关那么些小游戏的素材,不过基本上一塌糊涂,本身的结合有关课程将以此游乐的根本框架整理出来,供大家一起学习。

一、前言

像素小鸟那么些简单的嬉戏于二〇一五年在互联网上爆红,游戏上线一段时间内appleStore上的下载量一度达到六千万次,风靡目前,

近期移动web的推广为这么没有复杂逻辑和精密动画效果,不过趣味十足的小游戏提供了精良的条件,

再者借助各大社交软件平台的传播效应,创新意识不断的小游戏有着精良的经营销售效益,得到了无数的关心。

从前在网上查询了诸多关于那个小游戏的质地,然则基本上一无可取,本身的构成有关课程将这一个游戏的第3框架整理出来,供大家一起学学。

二 、技术中央

 基本JavaScript基础 ,canvas 基础, 面向对象的合计;

贰 、技术主旨

 基本JavaScript基础 ,canvas 基础, 面向对象的思辨;

③ 、思路整理

三 、思路整理

全副娱乐的逻辑相比不难:

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

附带:鸟在飞翔的进程中,会落下,类似落体运动,要求玩家不断点击显示屏让鸟向上海飞机创建厂。

再度正是:鸟和背景成分的相对移动的经过,鸟不动,背景左移。

任何游戏的逻辑相比较不难:

第2游戏规则:鸟撞到管道上,地上要去世,飞到显示屏外要长逝。

附带:鸟在飞翔的经过中,会落下,类似落体运动,需求玩家不断点击荧屏让鸟向上飞。

再也等于:鸟和背景成分的相对移动的经过,鸟不动,背景左移。

将总体娱乐细化:

大家采用面向对象的思路来创造,具体的事物用构造函数来创制,方法放到构造函数的敬亭山真面目对象中。

打闹细化那个历程不是简单的,如若在一贯不相关辅导的意况下,本身要不停的重组自身的想法去试错。

作者使用的格局是使用Xmind将流程以脑图的格局绘制下来,分块去做,不断细化记录本身的思路,最后呈现的意义如下:

(顺序依照图片中的序号去看  脑图、素材、及全部源码下载地址:http://pan.baidu.com/s/1c130V7M
想练习的同班能够点那里)

脑图分为三大块:一 、准备阶段 贰 、主函数 三 、游戏优化。

图片 3

图片 4

 

 

将全部游戏细化:

我们应用面向对象的思绪来营造,具体的事物用构造函数来创立,方法放到构造函数的精神对象中。

游戏细化那么些进度不是轻易的,如若在没有有关指引的事态下,自身要不断的构成自身的想法去试错。

自家使用的艺术是利用Xmind将流程以脑图的花样绘制下来,分块去做,不断细化记录自身的思绪,最后表现的意义如下:

(顺序依照图片中的序号去看  脑图、素材、及全部源码下载地址:http://pan.baidu.com/s/1c130V7M
想练习的同室能够点那里)

脑图分为三大块:壹 、准备阶段 ② 、主函数 ③ 、游戏优化。

图片 5

图片 6

 

 

 肆 、游戏达成:

现行重组脑图来慢慢达成大家的二十六日游。

1.装置canvas画布,准备图片数据,当图片加载成功后实施回调函数;

图片 7图片 8

<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的时候再进行主函数;

图片 9图片 10

function  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来决定循环次数,大家运用1个叫requestAnimationFrame()的定时器

       因为setInterval会生出时间误差,setInterval只可以依照时间来移动固定距离。

       那对于轮播图一类几千微秒切换2次的动作来说并没有何关联,可是对于大家16-18纳秒绘制2次的卡通片是相当不纯粹的;

       requestAnimationFrame()那么些定时器的裨益是依照浏览器的习性来推行三个函数,我们用来获取一次绘制的间隔时间;

       移动距离的盘算改变成速度×间隔时间的方法,来消除绘图不标准的难点。

图片 11图片 12

var 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.1 小鸟的绘图:

  小鸟本身有二个翅膀扇动的职能,和三个下跌的进度。

  翅膀扇动的进程是一张天使图三幅画面包车型地铁的切换(设置三个index属性,控制天使图的岗位),降低进度是其y坐标在画布上的位移();

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

  那里要求专注几点:

  •  小鸟的绘图选拔canvas
    drawImage的九参数格局(分别是图形,原图的裁切起源,原图的宽高,贴到画布上的职位,贴到画布上的宽高);
  •  小鸟的翅膀扇动不能够太快,所以我们设置1个阀门函数,当累计计时跨越100ms的时候切换一下图纸,然后在让一起计时减去100ms;
  •  小鸟的减退供给使用一定物理知识,不过都很简短啦。
    我们都以通过速度×时间来落实;

图片 13图片 14

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

鸟类的构造函数及动作控制

 
构造3个鸟类,并且将其动作刷新函数和制图函数放置在大家地点提到的绘图区域,此后协会出的近乎对象都以那样的操作步骤:

 
这里须要留意的一点是,如何让鸟儿顺畅的迈入飞翔,其实依然物理知识,由于加快度的作用,我们给小鸟贰个升华的顺时速度就能够了。

图片 15图片 16

load(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 - preTime;
                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;
            } )
        })

制图小鸟,点击小鸟上海飞机制造厂

意义如下:

图片 17

2.2天空的绘图:

  天空的绘图相比不难了,只要使用canvas
drawImage的三参数格局就能够(图源,画布上的坐标)。

  那里唯一专注的一些是,无缝滚动的贯彻,对于800*600分辨率那种场地大家创立七个天空对象就能够了,不过为了适配更加多的图景,我们将这几个成效写活

  在天空的构造函数上加二个count属性设置多少个天空图片,count属性让实例通过原形中的方法访问。前边涉及到重现的当地和管道,都给它们增进那种考虑。

图片 18图片 19

var 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;  //当向左移动了一整张图片后立刻切回第一张图片
    }
}

上苍构造函数及移动函数

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

  setcount是用来安装无缝滚动的

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

  那里仅插入部分连锁代码

图片 20图片 21

var 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 地面包车型大巴绘图

  和天空的绘图完全相同,由于本地图片尺寸较小,所以大家要多画多少个

图片 22图片 23

var 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; //无缝滚动的实现
    }
}

地点的构造函数及运动函数

图片 24图片 25

//创建----放置在创建区域
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制图管道

  管道的绘图有多少个困难是管道中度的明确

  要点:

  •  为了保持游戏可玩性,管道必须有1个稳定中度+三个专擅中度,且上下管道之间的留白是定点的宽度。
  • 管道不是连连的,多个相邻的管道之间有距离
  • 留神管道在无缝播放,抽回后务必交给3个新的任性中度,给用户一种错觉,以为又一个管道飘了过来。

  

图片 26图片 27

var  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;     //切换后的管道必须重新设置一个高度,给用户一个新管道的错觉
    }
}    

管道的构造函数及活动函数

图片 28图片 29

//创建区域
            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 判断游戏是还是不是违犯禁令

  1. 接触到当地和天空顶部,结束游戏

图片 30图片 31

//我们改造一下主循环,设置一个gameover为false来控制函数的执行
//任何违规都会触发gameover=true;
               var gameover = false;

                if(bird.y < 0 || bird.y > 488 -45/2 ){ //碰到天和地
                    gameover = true ;
                }
                if(!gameover){    //如果没有结束游戏则继续游戏
                    requestAnimationFrame(run);
                }

粗略判读gameover

  2. 遇见管道甘休游戏

图片 32图片 33

//x和y到时候我们传入小鸟的运动轨迹,每次重绘管道都有判断
Pipe.prototype.hitTest = function(x,y){
    return (x > this.x && x < this.x + 52)    //在管子横向中间
        &&(! (y >this.r  && y < this.r +150));  //在管子竖向中间
}

判断是或不是蒙受管敬仲

图片 34图片 35

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

主循环的判定标准构成

图片 36

到这一步我们的游玩形成的大都了,剩下的就是有的数码的校正

最首要要求校勘的三个点是碰上的测算,因为大家具有的相撞都是比照小鸟图片的左上角计算的,这样就会有不确切的标题,通过测试很不难将以此距离加减校订了

 

3.游戏的优化

 小鸟游戏的飞禽在内外的经过中会随着点击,抬头飞翔,或迁就冲刺,如何形成那么些效果啊?

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

 为了防备全部坐标系的总体旋转运动

 必要在小鸟绘制函数Bird.prototype.draw里前面后端插足ctx.save()
和ctx.restore()来单独主宰小鸟画布

图片 37图片 38

Bird.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();
}

加入小鸟旋转效果

理所当然末了不要忘记对管道碰撞的判断,在此处再立异2回。

实际若是打算出席旋转效果,上1遍的匡正不必要,你会意识众多重复工。

最终做出的听从如下:

图片 39

 主体效能和逻辑已经全副落到实处。越来越多的效益能够自行添加。

 假若想协调练习一下,请点击游戏细化部分的链接下载相关资料和全部源码。

 肆 、游戏达成:

当今整合脑图来慢慢达成大家的游乐。

1.设置canvas画布,准备图片数据,当图片加载成功后实行回调函数;

图片 40图片 41

<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的时候再履行主函数;

图片 42图片 43

function  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()这几个定时器的便宜是根据浏览器的性情来执行3个函数,大家用来取得三次绘制的间隔时间;

       移动距离的计量改变成速度×间隔时间的方法,来缓解绘图不纯粹的题材。

图片 44图片 45

var 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.1 小鸟的绘图:

  小鸟自个儿有1个翅膀扇动的功力,和二个降低的进度。

  翅膀扇动的历程是一张天使图三幅画面包车型客车的切换(设置一个index属性,控制天使图的地方),下降进度是其y坐标在画布上的运动();

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

  那里须求小心几点:

  •  小鸟的绘图采用canvas
    drawImage的九参数方式(分别是图形,原图的裁切起源,原图的宽高,贴到画布上的职责,贴到画布上的宽高);
  •  小鸟的翅膀扇动不可能太快,所以大家设置2个阀门函数,当累计计时超过100ms的时候切换一下图纸,然后在让一起计时减去100ms;
  •  小鸟的大跌要求选取一定物理知识,可是都相当粗略啦。
    大家都是经过速度×时间来促成;

图片 46图片 47

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

鸟类的构造函数及动作控制

 
构造2个鸟类,并且将其动作刷新函数和制图函数放置在大家地点提到的绘图区域,此后结构出的类似对象都以那般的操作步骤:

 
那里须求注意的少数是,怎么样让鸟儿顺畅的提升飞翔,其实依然物理知识,由于加速度的功效,大家给小鸟二个前行的顺时速度就足以了。

图片 48图片 49

load(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 - preTime;
                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;
            } )
        })

制图小鸟,点击小鸟上海飞机创建厂

功用如下:

图片 50

2.2天幕的绘图:

  天空的绘图相比简单了,只要选取canvas
drawImage的三参数形式就足以(图源,画布上的坐标)。

  那里唯一专注的有些是,无缝滚动的落到实处,对于800*600分辨率那种景色大家成立多少个天空对象就足以了,但是为了适配越来越多的景况,大家将那些效率写活

  在穹幕的构造函数上加三个count属性设置多少个天空图片,count属性让实例通过原形中的方法访问。后边涉及到再也现身的地点和管道,都给它们拉长那种设想。

图片 51图片 52

var 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;  //当向左移动了一整张图片后立刻切回第一张图片
    }
}

天上构造函数及活动函数

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

  setcount是用来安装无缝滚动的

  注意一点:绘制上的图形是有一个层级关系的,无法把鸟画到天空的底下,那本来最后画鸟了,上边涉及到的遮盖难题不再专门提到。

  那里仅插入部分连锁代码

图片 53图片 54

var 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 地面包车型客车绘图

  和天空的绘图完全平等,由于当地图片尺寸较小,所以我们要多画多少个

图片 55图片 56

var 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; //无缝滚动的实现
    }
}

当地的构造函数及运动函数

图片 57图片 58

//创建----放置在创建区域
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绘制管道

  管道的绘图有八个难关是管道中度的鲜明

  要点:

  •  为了保全游戏可玩性,管道必须有多少个一定高度+一个随便中度,且上下管道之间的留白是原则性的宽窄。
  • 管道不是连连的,七个相邻的管道之间有距离
  • 留意管道在无缝播放,抽回后必须交给1个新的任意高度,给用户一种错觉,以为又三个管道飘了还原。

  

图片 59图片 60

var  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;     //切换后的管道必须重新设置一个高度,给用户一个新管道的错觉
    }
}    

管道的构造函数及活动函数

图片 61图片 62

//创建区域
            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 判断游戏是不是违犯禁令

  1. 接触到地面和天空顶部,结束游戏

图片 63图片 64

//我们改造一下主循环,设置一个gameover为false来控制函数的执行
//任何违规都会触发gameover=true;
               var gameover = false;

                if(bird.y < 0 || bird.y > 488 -45/2 ){ //碰到天和地
                    gameover = true ;
                }
                if(!gameover){    //如果没有结束游戏则继续游戏
                    requestAnimationFrame(run);
                }

简短判读gameover

  2. 境遇管道甘休游戏

图片 65图片 66

//x和y到时候我们传入小鸟的运动轨迹,每次重绘管道都有判断
Pipe.prototype.hitTest = function(x,y){
    return (x > this.x && x < this.x + 52)    //在管子横向中间
        &&(! (y >this.r  && y < this.r +150));  //在管子竖向中间
}

看清是不是遇到管敬仲

图片 67图片 68

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

主循环的衡量尺度构成

图片 69

到这一步大家的玩耍形成的几近了,剩下的正是部分数目标修正

重大要求改进的三个点是冲击的测算,因为大家富有的撞击都以遵守小鸟图片的左上角总括的,那样就会有不标准的题材,通过测试很简单将以此距离加减改正了

 

3.游戏的优化

 小鸟游戏的鸟儿在前后的长河中会随着点击,抬头飞翔,或妥洽冲刺,如何成功那么些成效呢?

 答案正是运动canvas 坐标系和挑选坐标系的角度
 ctx.translate()和ctx.rotate();

 为了防备全部坐标系的完全旋转运动

 必要在小鸟绘制函数伯德.prototype.draw里前面后端加入ctx.save()
和ctx.restore()来单独主宰小鸟画布

图片 70图片 71

Bird.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();
}

加盟小鸟旋转效果

当然最终不要遗忘对管道碰撞的判断,在那里再核对一回。

事实上假如打算到场旋转效果,上一回的校勘不须求,你会意识众多重复工。

最后做出的机能如下:

图片 72

 主体作用和逻辑已经整整兑现。更加多的成效能够自行添加。

 即使想本人练习一下,请点击游戏细化部分的链接下载相关材料和全体源码。

相关文章