像素小鸟,canvas落成图片裁剪

by admin on 2019年2月14日

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

2016/01/03 · HTML5 ·
Canvas

原稿出处: xingoo   

直接想自个儿做点小东西,直到眼下看了本《HTML5玩耍支付》,才打听游戏开发中的一点点入门知识。

本篇就针对学习的几个样例,自个儿入手实践,做了个FlappyBird,源码共享在度盘 ;也得以参考github,里面有越来越多的玩乐样例。

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

想必网上早已有多少个flappy-bird的html5版本啦,到这么些时候flappy-bird大概也没有前边那么火了,可是作为七个新手,自个儿研商,自个儿出手写二个flappy-bird的demo如故很有成就感的。

canvas是贰个足以让我们运用脚本绘图的竹签,它提供了一多重完整的习性和方法。大家得以借此来贯彻图形绘制,图像处理照旧达成简单的动画和娱乐制作。

打闹截图

必发88 1

必发88 2

flappy bird制作全流程:

必发88 3

flappy-bird的html5版无非是经过canvas来画的,可能网上也有webgl版本的,但是作者一般没见过,即使您发觉了,希望告知作者一声,我们一起讨论探讨。此前在今日头条上观察有大神用60几行就写出了1个demo,那让自个儿写完未来发现自身的demo有将近200多行的代码,须臾间让小编对大神们奉为楷模的佩服,当然小编的代码也可以简单到几十行,不过尔尔写出来,不便于维护,对于新人也很难看懂。

canvas标签唯有八个天性:width和height,用来设定画布的宽和高,要是没有通过标签属性可能脚本来设置,专擅认同为300*150;

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逐个绘制皆以独自的操作。比如下图的多个绘制图形,第一个会以覆盖的样式绘制,因而制图图形的逐一就浮现非凡要害了。

必发88 4

一、前言

像素小鸟那些大约的游戏于二〇一六年在网络上爆红,游戏上线一段时间内appleStore上的下载量一度达到伍仟万次,风靡一时,

新近移动web的普及为如此没有复杂逻辑和精美动画效果,不过趣味十足的小游戏提供了地道的环境,

并且借助各大社交软件平台的传播效应,创意不断的小游戏有着卓绝的营销效益,拿到了好多的关爱。

从前在网上查询了累累关于这么些小游戏的资料,但是基本上一无可取,本人的组合相关学科将这一个娱乐的主要性框架整理出来,供大家一起上学。

html代码小编就不写了,我们也都驾驭,假如您连html代码也要求的话,那您接下去也就没须求看了,还不如直接跳转到w3school.com.cn。

好了,canvas的介绍就先到那边,下边我们来看望javascript结合canvas完成图片的剪裁代码:

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则指定了裁剪图片的坐标尺寸,那在采取多成分的矢量图时很常用。比如:

必发88 5

上边的图形中为了削减图片财富的伸手数量,把过多的因素放在了一个图形中,此时就须求经过裁剪的法子,获取指定的图形成分。

二、技术核心

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

接下去就是主要的js了,至于css吗?你领会的css对于canvas是行不通的,那自个儿干嘛还写css呢,那不是荒废生命啊

复制代码 代码如下:

FlappyBird原理分析

实质上那几个娱乐很粗略,一张图就可以看懂其中的神秘:

必发88 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;
            }

很不难吗!

由于该游戏一共就那多少个因素,由此把他们都放入1个Objects数组中,通过setInteral()方法,在自然间隔时间内,执行三回重绘

重绘的时候会先去掉画面中的所有因素,然后依照新的因素的坐标三次绘制图形,那样就会现出活动的效应。

三、思路整理

一发轫首先定义bird对象,提议用构造函数的方法,当然你也足以用工厂函数,那没怎么关系的

var selectObj = null;
function ImageCrop(canvasId, imageSource, x, y, width, height) {
    var canvas = $(“#” + canvasId);
    if (canvas.length == 0 && imageSource) {
        return;
    }
    function canvasMouseDown(e) {
        StopSelect(e);
        canvas.css(“cursor”, “default”);
    }
    function canvasMouseMove(e) {
        var canvasOffset = canvas.offset();
        var pageX = e.pageX || event.targetTouches[0].pageX;
        var pageY = e.pageY || event.targetTouches[0].pageY;
        iMouseX = Math.floor(pageX – canvasOffset.left);
        iMouseY = Math.floor(pageY – canvasOffset.top);
        canvas.css(“cursor”, “default”);
        if (selectObj.bDragAll) {
            canvas.css(“cursor”, “move”);
            canvas.data(“drag”, true);
            var cx = iMouseX – selectObj.px;
            cx = cx < 0 ? 0 : cx;
            mx = ctx.canvas.width – selectObj.w;
            cx = cx > mx ? mx : cx;
            selectObj.x = cx;
            var cy = iMouseY – selectObj.py;
            cy = cy < 0 ? 0 : cy;
            my = ctx.canvas.height – selectObj.h;
            cy = cy > my ? my : cy;
            selectObj.y = cy;
        }
        for (var i = 0; i < 4; i++) {
            selectObj.bHow[i] = false;
            selectObj.iCSize[i] = selectObj.csize;
        }
        // hovering over resize cubes
        if (iMouseX > selectObj.x – selectObj.csizeh && iMouseX <
selectObj.x + selectObj.csizeh &&
            iMouseY > selectObj.y – selectObj.csizeh && iMouseY <
selectObj.y + selectObj.csizeh) {
            canvas.css(“cursor”, “pointer”);
            selectObj.bHow[0] = true;
            selectObj.iCSize[0] = selectObj.csizeh;
        }
        if (iMouseX > selectObj.x + selectObj.w – selectObj.csizeh &&
iMouseX < selectObj.x + selectObj.w + selectObj.csizeh &&
            iMouseY > selectObj.y – selectObj.csizeh && iMouseY <
selectObj.y + selectObj.csizeh) {
            canvas.css(“cursor”, “pointer”);
            selectObj.bHow[1] = true;
            selectObj.iCSize[1] = selectObj.csizeh;
        }
        if (iMouseX > selectObj.x + selectObj.w – selectObj.csizeh &&
iMouseX < selectObj.x + selectObj.w + selectObj.csizeh &&
            iMouseY > selectObj.y + selectObj.h – selectObj.csizeh &&
iMouseY < selectObj.y + selectObj.h + selectObj.csizeh) {
            canvas.css(“cursor”, “pointer”);
            selectObj.bHow[2] = true;
            selectObj.iCSize[2] = selectObj.csizeh;
        }
        if (iMouseX > selectObj.x – selectObj.csizeh && iMouseX <
selectObj.x + selectObj.csizeh &&
            iMouseY > selectObj.y + selectObj.h – selectObj.csizeh &&
iMouseY < selectObj.y + selectObj.h + selectObj.csizeh) {
            canvas.css(“cursor”, “pointer”);
            selectObj.bHow[3] = true;
            selectObj.iCSize[3] = selectObj.csizeh;
        }
        if (iMouseX > selectObj.x && iMouseX < selectObj.x +
selectObj.w && iMouseY > selectObj.y && iMouseY < selectObj.y +
selectObj.h) {
            canvas.css(“cursor”, “move”);
        }
        // in case of dragging of resize cubes
        var iFW, iFH, iFX, iFY, mx, my;
        if (selectObj.bDrag[0]) {
            iFX = iMouseX – selectObj.px;
            iFY = iMouseY – selectObj.py;
            iFW = selectObj.w + selectObj.x – iFX;
            iFH = selectObj.h + selectObj.y – iFY;
            canvas.data(“drag”, true);
        }
        if (selectObj.bDrag[1]) {
            iFX = selectObj.x;
            iFY = iMouseY – selectObj.py;
            iFW = iMouseX – selectObj.px – iFX;
            iFH = selectObj.h + selectObj.y – iFY;
            canvas.data(“drag”, true);
        }
        if (selectObj.bDrag[2]) {
            iFX = selectObj.x;
            iFY = selectObj.y;
            iFW = iMouseX – selectObj.px – iFX;
            iFH = iMouseY – selectObj.py – iFY;
            canvas.data(“drag”, true);
        }
        if (selectObj.bDrag[3]) {
            iFX = iMouseX – selectObj.px;
            iFY = selectObj.y;
            iFW = selectObj.w + selectObj.x – iFX;
            iFH = iMouseY – selectObj.py – iFY;
            canvas.data(“drag”, true);
        }
        if (iFW > selectObj.csizeh * 2 && iFH > selectObj.csizeh
* 2) {
            selectObj.w = iFW;
            selectObj.h = iFH;
            selectObj.x = iFX;
            selectObj.y = iFY;
        }
        drawScene();
    }
    function canvasMouseOut() {
        $(canvas).trigger(“mouseup”);
    }
    function canvasMouseUp() {
        selectObj.bDragAll = false;
        for (var i = 0; i < 4; i++) {
            selectObj.bDrag[i] = false;
        }
        canvas.css(“cursor”, “default”);
        canvas.data(“select”, {
            x: selectObj.x,
            y: selectObj.y,
            w: selectObj.w,
            h: selectObj.h
        });
        selectObj.px = 0;
        selectObj.py = 0;
    }
    function Selection(x, y, w, h) {
        this.x = x; // initial positions
        this.y = y;
        this.w = w; // and size
        this.h = h;
        this.px = x; // extra variables to dragging calculations
        this.py = y;
        this.csize = 4; // resize cubes size
        this.csizeh = 6; // resize cubes size (on hover)
        this.bHow = [false, false, false, false]; // hover statuses
        this.iCSize = [this.csize, this.csize, this.csize,
this.csize]; // resize cubes sizes
        this.bDrag = [false, false, false, false]; // drag statuses
        this.bDragAll = false; // drag whole selection
    }
    Selection.prototype.draw = function () {
        ctx.strokeStyle = ‘#666’;
        ctx.lineWidth = 2;
        ctx.strokeRect(this.x, this.y, this.w, this.h);
        // draw part of original image
        if (this.w > 0 && this.h > 0) {
            ctx.drawImage(image, this.x, this.y, this.w, this.h, this.x,
this.y, this.w, this.h);
        }
        // draw resize cubes
        ctx.fillStyle = ‘#999’;
        ctx.fillRect(this.x – this.iCSize[0], this.y –
this.iCSize[0], this.iCSize[0] * 2, this.iCSize[0] * 2);
        ctx.fillRect(this.x + this.w – this.iCSize[1], this.y –
this.iCSize[1], this.iCSize[1] * 2, this.iCSize[1] * 2);
        ctx.fillRect(this.x + this.w – this.iCSize[2], this.y + this.h

上行下效小鸟引力

是因为这一个娱乐不涉及小鸟横向的活动,由此假设模拟出小鸟下跌的动作以及上升的动作就能够了。

必发88 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. 像素小鸟,canvas落成图片裁剪。                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.             }  
  • this.iCSize[2], this.iCSize[2] * 2, this.iCSize[2] * 2);
            ctx.fillRect(this.x – this.iCSize[3], this.y + this.h –
    this.iCSize[3], this.iCSize[3] * 2, this.iCSize[3] * 2);
        };
        var drawScene = function () {
    像素小鸟,canvas落成图片裁剪。        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); //
    clear canvas
            // draw source image
            ctx.drawImage(image, 0, 0, ctx.canvas.width,
    ctx.canvas.height);
            // and make it darker
            ctx.fillStyle = ‘rgba(0, 0, 0, 0.5)’;
            ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
            // draw selection
            selectObj.draw();
            canvas.mousedown(canvasMouseDown);
            canvas.on(“touchstart”, canvasMouseDown);
        };
        var createSelection = function (x, y, width, height) {
            var content = $(“#imagePreview”);
            x = x || Math.ceil((content.width() – width) / 2);
            y = y || Math.ceil((content.height() – height) / 2);
            return new Selection(x, y, width, height);
        };
        var ctx = canvas[0].getContext(“2d”);
        var iMouseX = 1;
        var iMouseY = 1;
        var image = new Image();
        image.onload = function () {
            selectObj = createSelection(x, y, width, height);
            canvas.data(“select”, {
                x: selectObj.x,
                y: selectObj.y,
                w: selectObj.w,
                h: selectObj.h
            });
            drawScene();
        };
        image.src = imageSource;
        canvas.mousemove(canvasMouseMove);
        canvas.on(“touchmove”, canvasMouseMove);
        var StopSelect = function (e) {
            var canvasOffset = $(canvas).offset();
            var pageX = e.pageX || event.targetTouches[0].pageX;
            var pageY = e.pageY || event.targetTouches[0].pageY;
            iMouseX = Math.floor(pageX – canvasOffset.left);
            iMouseY = Math.floor(pageY – canvasOffset.top);
            selectObj.px = iMouseX – selectObj.x;
            selectObj.py = iMouseY – selectObj.y;
            if (selectObj.bHow[0]) {
                selectObj.px = iMouseX – selectObj.x;
                selectObj.py = iMouseY – selectObj.y;
            }
            if (selectObj.bHow[1]) {
                selectObj.px = iMouseX – selectObj.x – selectObj.w;
                selectObj.py = iMouseY – selectObj.y;
            }
            if (selectObj.bHow[2]) {
                selectObj.px = iMouseX – selectObj.x – selectObj.w;
                selectObj.py = iMouseY – selectObj.y – selectObj.h;
            }
            if (selectObj.bHow[3]) {
                selectObj.px = iMouseX – selectObj.x;
                selectObj.py = iMouseY – selectObj.y – selectObj.h;
            }
            if (iMouseX > selectObj.x + selectObj.csizeh &&
                iMouseX < selectObj.x + selectObj.w – selectObj.csizeh
    &&
                iMouseY > selectObj.y + selectObj.csizeh &&
                iMouseY < selectObj.y + selectObj.h – selectObj.csizeh)
    {
                selectObj.bDragAll = true;
            }
            for (var i = 0; i < 4; i++) {
                if (selectObj.bHow[i]) {
                    selectObj.bDrag[i] = true;
                }
            }
        };
    必发88 ,    canvas.mouseout(canvasMouseOut);
        canvas.mouseup(canvasMouseUp);
        canvas.on(“touchend”, canvasMouseUp);
        this.getImageData = function (previewID) {
            var tmpCanvas = $(“<canvas></canvas>”)[0];
            var tmpCtx = tmpCanvas.getContext(“2d”);
            if (tmpCanvas && selectObj) {
                tmpCanvas.width = selectObj.w;
                tmpCanvas.height = selectObj.h;
                tmpCtx.drawImage(image, selectObj.x, selectObj.y,
    selectObj.w, selectObj.h, 0, 0, selectObj.w, selectObj.h);
                if (document.getElementById(previewID)) {
                    document.getElementById(previewID).src =
    tmpCanvas.toDataURL();
                    document.getElementById(previewID).style.border = “1px
    solid #ccc”;
                }
                return tmpCanvas.toDataURL();
            }
        };
    }
    function autoResizeImage(maxWidth, maxHeight, objImg) {
        var img = new Image();
        img.src = objImg.src;
        var hRatio;
        var wRatio;
        var ratio = 1;
        var w = objImg.width;
        var h = objImg.height;
        wRatio = maxWidth / w;
        hRatio = maxHeight / h;
        if (w < maxWidth && h < maxHeight) {
            return;
        }
        if (maxWidth == 0 && maxHeight == 0) {
            ratio = 1;
        } else if (maxWidth == 0) {
            if (hRatio < 1) {
                ratio = hRatio;
            }
        } else if (maxHeight == 0) {
            if (wRatio < 1) {
                ratio = wRatio;
            }
        } else if (wRatio < 1 || hRatio < 1) {
            ratio = (wRatio <= hRatio ? wRatio : hRatio);
        } else {
            ratio = (wRatio <= hRatio ? wRatio : hRatio) –
    Math.floor(wRatio <= hRatio ? wRatio : hRatio);
        }
        if (ratio < 1) {
            if (ratio < 0.5 && w < maxWidth && h < maxHeight) {
                ratio = 1 – ratio;
            }
            w = w * ratio;
            h = h * ratio;
        }
        objImg.height = h;
        objImg.width = w;
    }

碰撞检测

打闹中小鸟碰到管敬仲只怕地面都会算游戏停止:

必发88 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将流程以脑图的款式绘制下来,分块去做,不断细化记录本身的思绪,最终表现的功力如下:

(顺序根据图片中的序号去看
 脑图、素材、及全部源码下载地址:
想操练的同室可以点那里)

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

必发88 9

必发88 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画布,准备图片数据,当图片加载成功后执行回调函数;

必发88 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的时候再实施主函数;

必发88 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].add伊夫ntListener(“load”,function(){ imgCount–;
if(imgCount==0){ callback(imgEls); }; }) }; }; 入口函数设置

主循环的装置:那里大家不接纳setInterval来控制循环次数,大家使用壹个叫requestAnimationFrame()的定时器

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

       那对于轮播图一类几千微秒切换一遍的动作来说并不曾什么关联,但是对于我们16-18阿秒绘制一回的卡通片是不行不标准的;

       requestAnimationFrame()这么些定时器的益处是依照浏览器的属性来施行1个函数,大家用来得到两遍绘制的间隔时间;

       移动距离的测算改变成速度×间隔时间的方法,来缓解绘图不准确的难题。

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

  小鸟本身有壹个翅膀扇动的功用,和3个大跌的历程。

  翅膀扇动的经过是一张天使图三幅画面的的切换(设置多少个index属性,控制天使图的地方),下跌进程是其y坐标在画布上的移动();

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

  那里需要专注几点:

  •  小鸟的绘图采用canvas
    drawImage的九参数情势(分别是图片,原图的裁切起源,原图的宽高,贴到画布上的职位,贴到画布上的宽高);
  •  小鸟的膀子扇动不大概太快,所以我们设置几个阀门函数,当累计计时领先100ms的时候切换一下图形,然后在让一起计时减去100ms;
  •  小鸟的下降需求拔取一定物理知识,不过都很不难啦。
    大家都以透过速度×时间来落实;

必发88 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; } 小鸟的构造函数及动作控制

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

 
那里要求小心的有些是,怎样让鸟儿顺畅的升华飞翔,其实依然大体知识,由于加快度的效果,大家给小鸟3个腾飞的顺时速度就可以了。

必发88 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 – 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; } ) }) 绘制小鸟,点击小鸟上飞

效果如下:

必发88 16

2.2天上的绘图:

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

  这里唯一专注的一些是,无缝滚动的落到实处,对于800*600分辨率那种气象大家创立八个天空对象就足以了,不过为了适配更加多的情形,我们将那些功效写活

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

必发88 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;
//当向左移动了一整张图片后马上切回第一张图纸 } } 天空构造函数及活动函数

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

  setcount是用来设置无缝滚动的

  注意一点:绘制上的图样是有三个层级关系的,无法把鸟画到天空的下边,那自然最终画鸟了,下边涉及到的掩盖难题不再专门提到。

  那里仅插入部分连锁代码

必发88 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 – pre提姆e; 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 地面的绘图

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

必发88 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; //无缝滚动的完成 } } 地面的构造函数及运动函数
必发88 20//创设—-放置在开创区域
var land1 = new Maserati(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绘制管道

  管道的绘图有三个难题是管道高度的规定

  要点:

  •  为了维持游戏可玩性,管道必须有二个固定中度+一个任意中度,且上下管道之间的留白是定位的幅度。
  • 管道不是屡次三番的,三个相邻的管道之间有距离
  • 专注管道在无缝播放,抽回后务必提交多个新的任意中度,给用户一种错觉,以为又一个管道飘了还原。

  

必发88 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;
//切换后的管道必须另行设置多少个可观,给用户三个新管道的错觉 } } 管道的构造函数及运动函数
必发88 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 判断游戏是还是不是违禁

必发88 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. 遇上管道为止游戏

必发88 24//x和y到时候我们传入小鸟的移位轨迹,每一回重绘管道都有咬定
Pipe.prototype.hitTest = function(x,y){ return (x > this.x && x <
this.x + 52) //在管仲横向中间 &&(! (y >this.r && y < this.r
+150)); //在管仲竖向中间 } 判断是不是蒙受管敬仲
必发88 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); } 主循环的判定标准构成

必发88 26

到这一步大家的玩乐形成的大半了,剩下的就是有的数码的匡正

最首要须求改正的三个点是碰撞的测算,因为我们具有的碰撞都以比照小鸟图片的左上角总结的,那样就会有不确切的标题,通过测试很不难将以此距离加减校对了

 

3.游戏的优化

 小鸟游戏的鸟儿在前后的历程中会随着点击,抬头飞翔,或让步冲刺,怎么着达成那个效果啊?

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

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

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

必发88 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(); }
参与小鸟旋转效果

自然最终不要遗忘对管道碰撞的判定,在此间再校对两遍。

骨子里如若打算进入旋转效果,上两次的修正不必要,你会发现许多重复工。

最终做出的效应如下:

必发88 28

 主体成效和逻辑已经整整贯彻。愈多的机能可以自行添加。

 如若想协调训练一下,请点击游戏细化部分的链接下载相关材质和一切源码。

制作flappy
bird(像素小鸟)全流程,canvasflappy flappy bird制作全流程: 一、前言
像素小鸟那个简单的二十五日游于二〇一五年在互连网上爆红,游戏上…

 

你或者感兴趣的篇章:

  • js+html5绘制图片到canvas的点子
  • JS移动端/H5同时选取多张图纸上传并使用canvas压缩图片
  • js落成canvas保存图片为png格式并下载到本地的不二法门
  • Js利用Canvas已毕图片压缩功用
  • js达成canvas图片与img图片的相互转换的言传身教
  • JavaScript+html5
    canvas落成图片破碎重组动画特效
  • javascript结合canvas完成图片旋转效果
  • js HTML5
    canvas绘制图片的方法
  • Canvas + JavaScript
    制作图纸粒子效果
  • js
    canvas完结放大镜查看图片功效
  • JavaScript+Canvas达成彩色图片转换成黑白图片的章程分析

全副源码

<!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给画出来

总结

在念书玩乐开发的时候,作者忽然怀想起高校的大体。当时很怀疑,学电脑学什么物理,后来再触及游戏支付才晓得,没有一定的大体知识,根本不大概模拟游戏中的各类场景。

而通过那么些大致的小游戏,也捡起来了很多旧文化。

  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 收藏
评论

必发88 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对象的概念,没错,已经做到了,就一些代码而已。没有太多

接下去是水管对象的概念,不过我人太懒,实在是不想找水管的老大图片,所以作者就草草,用了几个盒子来取代水管,原理是一模一样的,不过视觉效果,你懂的,就比如小编身边的七个女性同学说的,程序猿能有何美感!大家将就着啊

概念盒子对象

  1. var Box = function (x, y) {  
  2.                 this.x = x || boxOption.x;  
  3.                 this.y = y || boxOption.y;  
  4.                 this.w = boxOption.w;  
  5.                 this.h = boxOption.h;  
  6.                 this.img = boxOption.img;  
  7.                 this.visible = true;  
  8.   
  9.                 return this;  
  10.             };  

是还是不是认为和bird很像,但是就是多了visible属性,那些天性是控制盒子的看见与否,在游戏中的小鸟通过的的水管之间的空子就是靠它了,

 

或许要定义它多少个方法,不对,它唯有3个办法

  1. Box.prototype.draw = function () {  
  2.   
  3.                 // console.log([this.img, this.img.width, this.img.height, this.x, this.y, this.w, this.h]);  
  4.                 ctx.drawImage(this.img, 0, 0, this.img.width, this.img.height, this.x, this.y,  
  5.                     this.w, this.h);  
  6.   
  7.             };  

有没有认为那一个方法和bird的draw方法一样,没错是一致的,其实自身应该让box继承bird对象,那样作者的代码有能够少几行了

 

好了,不谈代码行数的标题了,痛苦

接下去是pipe的目的,它然而是box的3个汇聚

  1. var pipe = function (posX, xDir, maxNum) {  
  2.                 this.x = posX;  
  3.                 this.xDir = xDir;  
  4.                 var boxList = [];  
  5.                 var box = new Box(0, 0);  
  6.                 var boxW = box.w,  
  7.                     boxH = box.h;  
  8.                 var boxTmp;  
  9.                 var maxNum = maxNum || Math.ceil(canvas.height / boxW);  
  10.   
  11.                 for (var i = 0; i < maxNum; i++) {  
  12.                     boxTmp = new Box(posX, i * boxH);  
  13.                     boxList.push(boxTmp);  
  14.                 }  
  15.   
  16.                 this.obj = boxList;  
  17.                 this.boxW = boxW;  
  18.                 return this;  
  19.             };  

this.obj那个脾性就是box数组

 

和目前一样,pipe也有个draw属性

  1. pipe.prototype.draw = function () {  
  2.                 var box;  
  3.                 for (var i = 0; i < this.obj.length; i++) {  
  4.                     box = this.obj[i];  
  5.                     box.x = this.x;  
  6.                     if (box.visible) {  
  7.                         box.draw();  
  8.                     }  
  9.                 }  
  10.                 return this;  
  11.             };  

尽管将this.obj中的所有box来两次遍历输出,当然box的visible属性必须是可知的

 

上面的那些艺术是随机隐藏五个延续的box,以便给可伶的小鸟通过,大家是慈善的,给了七个box的冲天,当然假如您借使想虐人的话,提议你只给二个中度

  1. // 随机隐藏多个一而再的箱子  
  2.             pipe.prototype.rand = function () {  
  3.                 for (var i = 0; i < this.obj.length; i++) {  
  4.                     this.obj[i].visible = true;  
  5.                 }  
  6.   
  7.                 var rand = Math.floor(Math.random() *  5) + 1;  
  8.                 // console.log(rand);  
  9.                 this.obj[rand].visible = false;  
  10.                 this.obj[rand + 1].visible = false;  
  11.   
  12.                 return this;  
  13.             };  

说到底叁特性质是移动方法,这是让水管进行左右运动的

  1. pipe.prototype.move = function () {  
  2.                 this.x += this.xDir;  
  3.   
  4.                 // console.log(this.x, this.xDir, this.boxW);  
  5.                 if (this.x < -this.boxW) {  
  6.                     this.x = canvas.width;  
  7.                     this.rand();  
  8.                 }  
  9.                 this.draw();  
  10.                 return this;  
  11.             };  

ok
基本那样ok了,但是大家是或不是忘了怎么着事物啊,想起来了,我们还一向不展开碰撞检测呢,如若不开展碰撞检测,那岂不是开挂了,那本来是极度的

  1. // 碰撞函数  
  2.   
  3.             function collision (bird, pipe1) {  
  4.                 var birdx = bird.x,  
  5.                     birdy = bird.y,  
  6.                     birdw = bird.w,  
  7.                     birdh = bird.h;  
  8.   
  9.                 var boxes = pipe1.obj;  
  10.                 var box1, box2, num;  
  11.                 for (var i = 0; i < boxes.length – 1; i++) {  
  12.                     // 找到被隐形的多少个盒子  
  13.                     if (!boxes[i].visible) {  
  14.                         box1 = boxes[i];  
  15.                         box2 = boxes[i + 1];  
  16.                         break;  
  17.                     }  
  18.                 }  
  19.                 var emptyx = box1.x;  
  20.                 var emptyy = box1.y;  
  21.                 var emptyw = box1.w;  
  22.                 var emptyh = box1.h + box2.h;  
  23.   
  24.                 // 检测是不是与上半部水管碰撞  
  25.                 console.log([birdx, birdy, birdw, birdh, emptyx, 0, emptyw, box1.y, boxes[0].y]);  
  26.                 var collUp = calculate(birdx, birdy, birdw, birdh, emptyx, 0, emptyw, box1.y);  
  27.                 // 检测是或不是与下半部水管碰撞  
  28.                 var collDown = calculate(birdx, birdy, birdw, birdh, emptyx, box2.y + box2.h, emptyw, canvas.height – box2.y – box2.h);  
  29.                 // console.log(collUp, collDown);  
  30.                 if (collUp || collDown) {  
  31.                     // alert(‘game over’);  
  32.                     console.log(‘game over 1111’);  
  33.                     console.log(myReq);  
  34.                     stop();  
  35.                 }  
  36.   
  37.                 if (birdy > canvas.height – birdh) {  
  38.                     console.log(‘game over   222’);  
  39.                     console.log(myReq);  
  40.                     stop();    
  41.                 }  
  42.             }  
  43.   
  44.             // 计算碰撞函数,暗中认可矩形碰撞  
  45.             function calculate (x1, y1, w1, h1, x2, y2, w2, h2) {  
  46.                 var ax = x1 + w1 / 2,  
  47.                     ay = y1 + h1 / 2,  
  48.                     bx = x2 + w2 / 2,  
  49.                     by = y2 + h2 / 2;  
  50.                 var collX = false, collY = false;  
  51.   
  52.                 (Math.abs(bx – ax) < (w1 + w2) / 2) && (collX = true);  
  53.                 (Math.abs(by – ay) < (h1 + h2) / 2) && (collY = true);  
  54.   
  55.                 return collX && collY;  
  56.             }  

那样就基本ok了,接下去也只是有个别,先河化而已,那一个平昔上代码吧

 

  1. var count = 0, timeout, myReq = 0, stopped, requestId = 0;  
  2.             function render() {  
  3.                 if (!stopped) {  
  4.                     ctx.fillStyle = ‘#ccc’;  
  5.                     ctx.fillRect(0, 0, canvas.width, canvas.height);  
  6.                     bird.jump();  
  7.                     pipe1.move();  
  8.                     // 检测碰撞  
  9.                     collision(bird, pipe1);  
  10.                     requestId = window.requestAnimationFrame(render);  
  11.                     console.log(requestId);  
  12.                 }  
  13.             }  
  14.   
  15.             // 绑定鼠标事件  
  16.             document.onclick = function () {  
  17.                 bird.y -= 25;  
  18.             }  
  19.             function start() {  
  20.                 requestId = window.requestAnimationFrame(render);  
  21.                 stopped = false;  
  22.                 // console.log(requestId);  
  23.   
  24.             }  
  25.   
  26.             function stop() {  
  27.                 if (requestId) {  
  28.                     window.cancelAnimationFrame(requestId);  
  29.                 }  
  30.                 stopped = true;  
  31.                 // console.log(requestId);  
  32.             }  
  33.   
  34.             start();  

效益如下图所示

 

必发88 30

完整代码请访问作者的github

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图