-----------------------------------------------福利---------------------------------------------前端
-----------------------------------------------分割線---------------------------------------------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也能寫!
附 源碼