利用Canvas实现Flappybird简陋游戏步骤
Canvas是Html5中用于绘图的元素,它可以绘制各种图形,比如长方形,多边形,圆形等等。如果想要了解Canvas的使用可以参考:
http://www.w3school.com.cn/tags/html_ref_canvas.asp
创建Canvas标签、和获取绘图上下文。
var cvs = document.getElementById('cvs'); var ctx = cvs.getContext('2d')
资源加载,等所有图片资源加载完成之后,再调用main函数,真正开始游戏相关的逻辑。
- 把想要加载的图片的路径用数组存储起来(
imgs
),并新建一个空的数组(imgObjects
)用于存储创建出来的img标签。 - 遍历
imgs
数组,依次用new Image()
的方式创建图像标签,为它们设置src、添加加载完成事件的监听,并存储到imgObjects
数组中。 - 书写监听器函数、创建一个计数器,该函数每次被调用时计数器+1,当计数器大于等于
imgs
数组长度时,所有图像加载完成,调用main
函数,正式开始游戏逻辑。
- 把想要加载的图片的路径用数组存储起来(
在
main
函数中准备一个主循环函数loop
、创建一个变量lastTime
用于记录上一次调用loop
时的时间,在loop
中进行以下工作:获取两帧间隔时间
var now = Date.now(); var dt = lastTime - now; lastTime = now;
- 用
ctx.clearRect
清空画布 - 用
requestAnimationFrame(loop)
让浏览器在自己觉得合适时,调用loop函数绘制下一帧。
requestAnimationFrame(要循环的函数体) ,它会根据浏览器的情况,自动去优化循环的次数,正常的一个动画,每秒60帧就足够了。
封装想要绘制到屏幕上的显示对象:
小鸟精灵
- 小鸟会有的行为:1.以自己的速度切换要显示的图片;2.一直下落;3.在屏幕被点击时向上飞。
update里要做的事情:
用
this.waitTime
记录小鸟在当前帧等待的时间,如果超过100毫秒,则切换图像this.waitTime += dt; if(this.waitTime > 100){ this.frameIndex = (this.frameIndex + 1) % 3; this.waitTime -= 100; }
- 根据加速度和dt求得当前的速度,根据速度和dt求得当前的y轴坐标
绘制时的细节:
根据小鸟的速度获取小鸟在这一帧应该有的角度;
var angle = this.speed / 0.3 * 45;
位移、旋转坐标系后,将小鸟绘制到屏幕上;
ctx.save(); //保存上一次的坐标等状态 ctx.translate(this.x, this.y); ctx.rotate(angle / 180 * Math.PI); ..... ctx.restore(); //恢复上一次的坐标等状态
天空
- 一共有两块800*600的天空向左飘,哪块天空移出了屏幕,则将哪块天空移动到最右边(
this.x = this.x + 800 * 2
)。
- 一共有两块800*600的天空向左飘,哪块天空移出了屏幕,则将哪块天空移动到最右边(
- 管子
- 一共有5根52*420的管子,每隔200px绘制一根管子。和天空类似的,哪根管子移出了屏幕,则把哪根管子移动到最右侧,并随机生成一个上侧管子的长度
pipe1H
。(this.x = this.x + 200 * 5
) - 绘制时的细节:
- 获取上侧的管子长度为pipe1H;把上侧的管子的图片绘制到 (this.x, pipe1H-420)点上,把下侧的管子绘制到(this.x, pipe1H + 150)的点上。(150是两根管子的间隔长度)
- 对两根管子分别绘制矩形路径,以便后面用
isPointInPath
判断小鸟是不是撞到了管子。
- 一共有5根52*420的管子,每隔200px绘制一根管子。和天空类似的,哪根管子移出了屏幕,则把哪根管子移动到最右侧,并随机生成一个上侧管子的长度
- 大地
- 和天空类似,但是一共有四块336*112的大地。
完成main函数,整体的架构如下:
function main(){ // TODO:创建程序所需的显示对象:鸟,天空,大地,管子 ...... // TODO:为canvas增加事件监听:每当鼠标点击时,给鸟一个-0.3的速度 ...... // TODO:主循环 function loop(){ // TODO:获取间隔时间,清空画布等 // TODO:调用所有显示对象的update函数,更新各个显示对象的状态 // TODO:根据小鸟的状态,判断小鸟是不是撞到了天花板或者地面 if(.......){ gameOver = true; } // TODO:用isPointInPath判断小鸟是不是撞在了柱子上。 if(ctx.isPointInPath(bird.x, bird.y)){ gameOver = true; } ctx.beginPath(); //记得清空路径,不要影响到下一帧的判断 // TODO:调用所有显示对象的draw函数 if(!gameOver){ requestAnimationFrame(loop) } } loop(); }
可参看的博文:
http://www.cnblogs.com/xing901022/p/5094550.html
by Turbo Beijing