-----------------------------------------------福利---------------------------------------------前端
-----------------------------------------------分割线---------------------------------------------jquery
今天 咱们研究下碰撞游戏 canvas
什么是碰撞游戏? 固然是东西碰到在一块儿啦 用前端逻辑来讲 就是2个物品互相碰撞产生的事件闭包
问多无用 先扫下二维码体验下( 欢乐斗地主接元宵)app
很简单 也很实用的碰撞吧 (虽然也很无聊)框架
不过我理念里是碰撞游戏用相似cocos2d 或者createJS 这种游戏引擎才能写 。不过谁叫咱只会原生js和jquery zepto哈dom
我尝试写了这个游戏 而且与你们分享分享思路。ide
首先这不是我第一次写碰撞游戏。 但之前写的碰撞游戏 都是以dom方法生成的 总之十分的卡! 卡!函数
此次换成canvas 作 。果真很是流畅布局
个人基本思路是 游戏流程是个对象 ,游戏里的动态元素(道具 人物)是对象 ,游戏里的静态元素(背景 装饰品)是dom元素
那么这样就产生了 用div 创建背景之类 。用canvas drawImage方法去生成汤圆之类的
dom这块我不用说了 右键查看下源码就知道怎么布局 主要想分析下canvas生成
在canvas中的所谓的落下 并非像animate 线性变化那么简单
它拆分了好几块 建立元素 插入元素 更新元素 循环。。 熟悉帧动画的人比较熟悉 咱们看到的动画 是无数细微变化的动画 快速组成的!
越是细小 动画越流畅 这也就是咱们常说的fps. (打游戏卡)
_createCavaseEle:
这个方法是专门用来建立元素的 。固然应该叫作建立对象比较好。 由于元素只是张img的话是没法移动 判断的
SteinsGate(名字很亮吧)是个构造函数 返回1个元素对象 此对象含有些必要的的属性 对应后面的逻辑判断!
1 var SteinsGate=function(pic,type){ 2 if(!pic){return "undefined";} 3 var that=this; 4 this.tag=pic[0]; 5 this.img=new Image(); 6 this.src=pic[1]; 7 this.width=pic[2]; 8 this.height=pic[3]; 9 this.x=pic[4]; 10 this.y=pic[5]; 11 this.LastX=this.x 12 this.LastY=this.y; 13 this.collide=false; 14 this.down=false; 15 16 if(type=="dom"){//dom生成 17 if(!document.getElementById(this.tag)){ 18 var farmer=document.createElement("div"); 19 }else{ 20 var farmer=document.getElementById(this.tag); 21 } 22 farmer.id=this.tag; 23 farmer.className=this.tag; 24 farmer.style.left=this.x+"px"; 25 26 farmer.style.top=this.y+"px"; 27 28 $(".lovelive").append(farmer); 29 } 30 else{//canvas生成 31 this.loadimg=function(){ 32 that.img.src=that.src; 33 that.img.onload = function () { 34 _this._upDateEle(that,this.x,this.y); //_this是个闭包 指向外面的CollideGame 35 } 36 37 }(); 38 } 39 40 }
这里本来只有canvas生成 可是后面由于清除图像时候 也会把农民也给清除 因此农民这个对象是 数据仍是canvas数据 图像是由dom生成
不知道各位有没有更好的方法? 不要写2个canvas标签哦 破坏布局美感的
_ctrlGame
这个方法是游戏的主逻辑程序;
为每一个刚刚创建的元素添加基本属性(汤圆or王炸) 基本事件 (控制or下落)
而且全局控制游戏进程 _ctrlDownItem(控制掉落物) _ctrlFarmer(控制农民)
请注意 这个方法仍是没有在canvas里生成图像 。生成是在控制所调用_upDateEle方法里
_ctrlDownItem 和 _ctrlFarmer
载入设定好的参数 和布局属性(canvas高啊 canvas宽啊) 而且为对象的绑定对应事件( 掉落的话就绑定碰撞 落地 or 控制就触摸事件)
在这些对应事件里又有分各类细节的逻辑判断
_isCollide 和_isGround 和_canvas_touchmove
这些都是细节对应的逻辑判断 具体原理请看源码 值得一提的是 上来touchmove我总是坐标不对 研究半天 原来发现手机屏幕大小和页面wrap大小不是1:1 通过对等换算就能解决啦
在这些判断后最后执行更新画布_upDateEle (请注意 这里仍是没有生成图像!!)
_upDateEle
原理很简单 只有知足的条件的才能生成图像 全部的条件在上面的判断已经生效!!
在这里别忘了 canvas的clearRect方法先清除上次的残留图像 在重新画
1 //更新元素pos 2 _upDateEle:function(ele,x,y,type){ //ele:元素 x:元素的x坐标 y:元素的y坐标 type:绘制方法(默认) 3 if(type=="dom"){ 4 //更新X坐标; 5 6 if(x){ele.x=x;} 7 //更新Y坐标; 8 if(y){ele.y=y;} 9 10 document.getElementById(ele.tag).style.left=ele.x+"px"; //更新图像 11 document.getElementById(ele.tag).style.top=ele.y+"px"; 12 ele.LastX=ele.x; 13 ele.LastY=ele.y; 14 }else{//Canvas 15 _this.ctx.clearRect(ele.LastX, ele.LastY,ele.width,ele.height); 16 //知足如下条件 才能够绘制 17 if(ele){ //是否有元素 18 if(!ele.down){ //是否已落地 19 if(!ele.collide){ //是否发生碰撞 20 //更新X坐标; 21 if(x){ele.x=x;} 22 //更新Y坐标; 23 if(y){ele.y=y;} 24 _this.ctx.drawImage(ele.img,ele.x,ele.y,ele.width,ele.height); 25 ele.LastX=ele.x; 26 ele.LastY=ele.y; 27 } 28 } 29 } 30 31 32 } 33 34 },
至此 整个游戏函数构造完成 接下来就是 把控各个参数 原理仍是老样子
建立对象-》插入对象-》更新对象(知足条件的才有图像 )
当对象的活动结束后别忘了 垃圾回收 =null哦
其实看到这可能你们还有些疑问 但我本身也不确信这些是否是很好的方法 好比
makikulisi() 个人原理是把 元素的运动的整个动画 拆分不少画面帧 而后递归的setTimeout(16毫秒)去刷新帧 达到帧动画效果
在游戏框架里也许有更好的方法吧?
isCollide()我一开始用的是老方法 (这个老方法 我研究了足足有1天!!)但网上查了资料 canvas好像也有那么神奇的isPointInPath方法 并且颇有效
由于过于神奇 和老方法的辛酸 因此我也很吃不许 这个是否是有bug?
总之 整个制做过程 本身也难以想象 我刚写时候 我还以为我写不出呢(不会框架!)
可是写着写着就写出来了。。。 真是船到桥头天然直
但愿对你之后制做这种类型的游戏有所帮助 不会不要怕 原生js也能写!
附 源码