【亚洲必赢官网】Canvas前端游戏开发,像素小鸟

[Canvas前端游戏支付]——FlappyBird详解

2016/01/03 · HTML5 ·
Canvas

初稿出处: xingoo   

直白想自己做点小东西,直到日前看了本《HTML5戏耍支付》,才精通游戏支付中的一点点入门知识。

本篇就针对学习的多少个样例,自己出手实践,做了个FlappyBird,源码共享在度盘 ;也得以参考github,里面有愈来愈多的游戏样例。

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

或许网上已经有多少个flappy-bird的html5版本啦,到这些时候flappy-bird可能也远非此前那么火了,可是作为一个新手,自己思考,自己出手写一个flappy-bird的demo依旧很有成就感的。

canvas是一个可以让大家选拔脚本绘图的标签,它提供了一名目繁多完整的特性和艺术。大家得以借此来落到实处图形绘制,图像处理照旧达成不难的动画片和玩耍制作。

玩耍截图

亚洲必赢官网 1

亚洲必赢官网 2

flappy bird制作全流程:

亚洲必赢官网 3

flappy-bird的html5版无非是透过canvas来画的,可能网上也有webgl版本的,可是我一般没见过,若是你发觉了,希望告知我一声,我们一块儿座谈啄磨。以前在博客园上看到有大神用60几行就写出了一个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每个绘制都是单身的操作。比如下图的五个绘制图形,第四个会以遮盖的款型绘制,由此绘制图形的逐条就显得煞是重中之重了。

亚洲必赢官网 4

一、前言

像素小鸟这些不难的玩乐于二零一四年在网络上爆红,游戏上线一段时间内appleStore上的下载量一度高达5000万次,风靡一时,

近些年移动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则指定了裁剪图片的坐标尺寸,这在利用多元素的矢量图时很常用。比如:

亚洲必赢官网 5

上面的图片中为了削减图片资源的哀告数量,把无数的元素放在了一个图纸中,此时就需求经过裁剪的不二法门,获取指定的图片元素。

二、技术中央

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

接下去就是重点的js了,至于css吗?你通晓的css对于canvas是于事无补的,那我干嘛还写css呢,那不是浪费生命啊

复制代码 代码如下:

FlappyBird原理分析

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

亚洲必赢官网 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对象,提议用构造函数的办法,当然你也得以用工厂函数,那没怎么关联的

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);
【亚洲必赢官网】Canvas前端游戏开发,像素小鸟。        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

模仿小鸟动力

出于那个娱乐不关乎小鸟横向的位移,因而即便模拟出小鸟下跌的动作以及上升的动作就足以了。

亚洲必赢官网 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.             }  
  • 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 () {
            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;
                }
            }
        };
        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;
    }

碰撞检测

游戏中小鸟蒙受管敬仲或者地点都会算游戏甘休:

亚洲必赢官网 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].add伊芙(Eve)ntListener(“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 – pre提姆(Tim)e; //获取时间间隔 pre提姆(Tim)e =
now; //更新当前时间 ctx.clearRect(0,0,800,600); //清空画布
//——————————————— 绘制代码执行区域
//———————————————–
requestAnimationFrame(run); //再次执行run函数 }
requestAnimationFrame(run); //首次执行run函数; 设置绘制格局

2、主函数分为两片段成效,简单说就是把图画上去,然后处理动态效果,再判断一下是否违禁。

2.1 小鸟的绘图:

  小鸟本身有一个翅膀扇动的作用,和一个下落的进度。

  翅膀扇动的长河是一张天使图三幅画面的的切换(设置一个index属性,控制天使图的职位),下落进度是其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 pre提姆e=
Date.now(); function run(){ var now = Date.now(); dt = now – pre提姆e;
pre提姆e = now; ctx.clearRect(0,0,800,600); //——–图片绘制区域——-
bird.update(dt) bird.draw(); //————————-
requestAnimationFrame(run); } requestAnimationFrame(run);
//设置点击事件。给小鸟一个一晃的上扬速度
cvs.add伊夫ntListener(“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 pre提姆e= Date.now();
function run(){ var now = Date.now(); dt = now – pre提姆e; pre提姆e = 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制作全流程: 一、前言
像素小鸟那么些简单的嬉戏于二零一四年在网络上爆红,游戏上…

 

你或许感兴趣的小说:

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

亚洲必赢官网 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属性,这些特性是决定盒子的看见与否,在戏耍中的小鸟通过的的水管之间的当儿就是靠它了,

 

或者要定义它多少个情势,不对,它唯有一个方法

  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的一个集结

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

效果如下图所示

 

亚洲必赢官网 30

总体代码请访问我的github

网站地图xml地图