HTML5物理遊戲開發 - 越野山地單車(三)粉碎單車

來源:互聯網
上載者:User

標籤:產生   意思   滑鼠   觸發事件   文章   rgb   str   list   deb   

自上一章公布到如今已時隔四月,實在對不住大家。讓大家久等了~話說不是我不關注我的部落格,而是事情一多起來寫部落格的時間就少了。

待到今日有空了,回頭看了看自己曾經寫的文章,猛得發現已經四個月不曾寫文章了。便僅僅得叫聲:“苦也~”,我害怕本系列文章會拖得更久,於是立馬提筆,也好為本系列文章留個鳳尾。

首先,大家來溫習一下前面兩篇裡的內容吧:

HTML5物理遊戲開發 - 越野山地單車(二)建立一輛可操控的單車

http://blog.csdn.net/yorhomwang/article/details/21300253

HTML5物理遊戲開發 - 越野山地單車(一)建立各式各樣的地形

http://blog.csdn.net/yorhomwang/article/details/19710537


今天我們要實現的內容就是——當我們單車的關鍵區段碰壁後。立馬使其粉碎,通俗點講就是“單車碎一地”。Ok。閑話何苦多說呢,我們就開始咯~

先放上兩張吧:





※再次聲明,本次開發用到了lufylegend.js開源html5遊戲引擎和box2dweb物理引擎,請到官方網站下載使用。官方網站地址已在第一章中說過了。



一,粉碎原理

用過鎚子的人都知道(假設你沒用過,並且也不知道怎麼用,建議你去問問雷神索爾)。要砸碎一個單車該怎麼砸呢?假設你不會,我教你三招吧:

法一:使勁砸;這樣的方法適用於你想換把鎚子

法二:到阿斯嘉找雷神大哥去。這個速率最快,預計不到抽完一根煙的工夫,你的單車就僅僅剩原子了

法三:去某個地方把鎚子換成螺絲刀等工具。然後把你那單車零件一塊一塊地給卸下來

顯然。這三種方法各有所長。只是既然我們的單車是一塊一塊地拼起來的,那麼還是一塊一塊地給拆了好,於是,我選擇了3(實際上是由於Box2dWeb沒有鎚子這玩意。也認不得雷神)。我們在上一章中提到過怎樣把零件拼起來,原理是運用了Box2dWeb裡的關節,這些關節把零件們連在了一起,那麼假設這些關節一銷毀,那麼這些零件就會散落。但是怎樣銷毀關節呢?Box2dWeb的b2World裡有一個DestroyJoint函數,參數就是你要銷毀的b2Joint對象。我們來看看在lufylegend裡怎樣銷毀關節吧。

首先,在lufylegend裡通過LBox2d關鍵關節的函數都會返回建立出的b2Joint對象,也就是說:

var j = LStage.box2d.setRevoluteJoint(a.box2dBody, b.box2dBody);LStage.box2d.world.DestroyJoint(j);
我們能夠把調用setRevoluteJoint建立出的旋轉關節儲存在變數j裡,然後銷毀時就直接調用LStage.box2d.world.DestroyJoint函數,參數則是j。

假設我們有多個關節怎麼辦呢?放數組裡唄,想必聰明的你在我說這話之前就已經想到了這點吧。
原理搞定。那麼我們開始看代碼吧。


二。更新單車類和Main類

上一章中我們著重講了怎樣實現單車類,這次由於要粉碎它,所以要先在它身上動手術。安放幾個炸彈再說。裝炸彈前要做好準備,以免把自己給炸over了,所以得先搞個盒子把要炸毀的地方裝起來。恰巧Main類路過(關於Main請看第一章),我把它一手提了過來。唱聲喏。道:“閣下暫且替我裝兩個東西,怎樣?”,Main類尋思道:“這廝能夠掌管全部程式。萬一這廝火了。一把delete把我等刪個乾淨卻不是個好事。

”,於是他無可奈何地替我擔負了這個重任。卻說看官欲知是哪兩個東西呢?原來是一個名叫jointList的數組和一個喚作gameOverController的bool型變數;這兩廝一個管裝全部產生的關節,一個管遊戲是否結束。

於是Main的構造器改造後例如以下:

function Main(){var s = this;base(s,LSprite,[]);/**設定情境大小*/s.sceneWidth = 8500;s.sceneHeight = LStage.height+1000;/**關節列表*/s.jointList = new Array();/**遊戲結束控制器*/s.gameOverController = false;}

卻說上面那段明顯有些水滸的風格。不好意思。最近《水滸傳》看多了,望各位包括包括。

我們知道。炸彈都是要有點火線的。或者更進階一點的開關啊,反正就是一個引爆裝置,這個工作還是交給Main吧。改動Main的init方法:

Main.prototype.init = function(){var s = this;/**增加邊框*/s.addBorder();/**增加路面*/s.addRoad();/**增加單車*/s.addBicycle();/**增加剛體碰撞事件*/LStage.box2d.setEvent(LEvent.POST_SOLVE,s.postSolve);/**增加迴圈事件*/s.addEventListener(LEvent.ENTER_FRAME,s.loop);};

主要是加了個調用LStage.box2d.setEvent函數。這個函數是LBox2d類的一個方法(LStage.box2d是LBox2d的執行個體化對象),詳細的用法是這樣子滴:

■setEvent(type, func)

參數介紹:

type box2d世界裡的碰撞事件類型

func 觸發事件時調度的函數

碰撞事件的類型能夠為:

LEvent.BEGIN_CONTACT:剛剛碰撞開始的時候會觸發這個函數
LEvent.END_CONTACT:碰撞結束的時候會觸發這個函數
LEvent.POST_SOLVE:碰撞後會處理這個函數
LEvent.PRE_SOLVE:碰撞前即將碰撞的時候


這裡我們選的是POST_SOLVE,也就是碰撞後會處理這個函數,事實上選擇其它的事件類型,效果也應該是一樣的。

事件觸發時調度的函數是postSolve,這個函數也交給Main吧~ [Main類:說好的裝兩個呢(T_T)]

Main.prototype.postSolve = function(contact){if(world.gameOverController)return;var l = world.jointList;if(l.length == 0)return;//擷取碰撞的LSprite對象var cA = contact.GetFixtureA().GetBody().GetUserData();var cB = contact.GetFixtureB().GetBody().GetUserData();//推斷是否摧毀單車if(//--------------------------------------------//條件一:當單車和牆碰撞時//--------------------------------------------((cA.name=="wall" && cB.name=="bicycle")||(cA.name=="bicycle" && cB.name=="wall"))||//--------------------------------------------//條件二:當單車的車把、車把到輪子的支架或者車座碰到其它物體時//--------------------------------------------((cA.trigger=="destroy_bicycle" && cB.name!="bicycle")||(cA.name!="bicycle" && cB.trigger=="destroy_bicycle"))){//去掉單車上的全部關節以達到催毀單車for(var i in l){var jo = l[i];//去掉關節LStage.box2d.world.DestroyJoint(jo);//將遊戲結束控制器設定為遊戲結束world.gameOverController = true;}//從單車關節列表中移除全部關節l.length = 0;//增加遊戲結束提示var gameOverText = new LTextField();gameOverText.text = "Game Over";gameOverText.size = 50;gameOverText.alpha = 0;gameOverText.x = (LStage.width-gameOverText.getWidth())*0.5;gameOverText.y = (LStage.height-gameOverText.getHeight())*0.5;addChild(gameOverText);LTweenLite.to(gameOverText,5,{delay:1.5,alpha:1});}};

該函數會接受一個參數。參數是個啥對象呢?事實上我也不清楚,反正裡面有GetFixtureA和GetFixtureB這兩個函數。這兩個函數能取到正在碰撞的剛體的剛形,通過剛形的GetBody取到b2Body對象,然後用b2Body的GetUserData取到終於的LSprite對象。

參數介紹完了,我還是來介紹一下這個函數的執行邏輯吧。首先,假設遊戲已經結束或者jointList為空白的數組,則不再執行後面的代碼。假設繼續執行代碼,則首先把碰撞的兩個剛體所在的LSprite取出來。然後進行遊戲結束推斷。假設通過則執行遊戲結束的代碼。

有人或許納悶那個world是個啥?假設你從第一章看起,就應該會明確了。主要是postSolve是個回呼函數。裡面的this不是指向Main的。


在那個長達19行的推斷條件裡。我設定了兩個條件,滿足這兩個條件之中的一個,便進行銷毀關節:條件一:當單車和牆碰撞時;條件二:當單車的車把、車把到輪子的支架或者車座碰到其它物體時。

銷毀部分的代碼主要是注意,在box2d裡,銷毀關節用DestroyJoint這個函數,這一點在“粉碎原理”中就已經提到過了,這個函數是在b2World類中的,LBox2d的world屬性就是b2World的執行個體化對象。

能不能結束遊戲關鍵要看碰撞的b2Body所在的LSprite對象的name和trigger(英文翻譯過來是“觸發器”的意思),這些屬性在哪裡設定的呢?當然是在構造單車的類Bicycle類裡呢。接下來就來看看Bicycle類裡增加&改進的代碼。

首先來看Bicycle的init函數的變化:

Bicycle.prototype.init = function(){var s = this;var sx = s.sx;var sy = s.sy; /**輪子半徑*/var wheelR = 20;/**輪子之間的距離*/var gapBetweenWheelAndWheel = 100;/**車手柄到輪子的距離*/var gapBetweenWheelAndHandlebar = 50;/**車把尺寸*/var handlebarWidth=20,handlebarHeight=5;/**座椅到輪子支架的距離*/var gapBetweenWheelFrameAndSeat = 30;/**座椅尺寸*/var seatWidth=30,seatHeight=5;/**支架尺寸*/var frameSize = 10;/**增加支架*///輪子上的支架var frameAObj = new LSprite();frameAObj.x = sx+gapBetweenWheelAndWheel/2;frameAObj.y = sy+frameSize/2;frameAObj.addBodyPolygon(gapBetweenWheelAndWheel,frameSize,1,5);world.addChild(frameAObj);s.bodyList.push(frameAObj);//車把到輪子的支架var frameBObj = new LSprite();frameBObj.trigger = "destroy_bicycle";frameBObj.x = sx+gapBetweenWheelAndWheel-frameSize/2;frameBObj.y = sy-gapBetweenWheelAndHandlebar/2;frameBObj.addBodyPolygon(frameSize,gapBetweenWheelAndHandlebar,1,2);world.addChild(frameBObj);s.bodyList.push(frameBObj);/**增加車把*/var handlebarObj = new LSprite();handlebarObj.trigger = "destroy_bicycle";handlebarObj.x = sx+gapBetweenWheelAndWheel-handlebarWidth/2-frameSize;handlebarObj.y = sy-gapBetweenWheelAndHandlebar+handlebarHeight/2;handlebarObj.addBodyPolygon(handlebarWidth,handlebarHeight,1,.5);world.addChild(handlebarObj);s.bodyList.push(handlebarObj);/**增加座椅*///座椅到輪子支架的支架var seatFrameObj = new LSprite();seatFrameObj.x = sx+30;seatFrameObj.y = sy-gapBetweenWheelFrameAndSeat/2;seatFrameObj.addBodyPolygon(frameSize,gapBetweenWheelFrameAndSeat,1,1);world.addChild(seatFrameObj);s.bodyList.push(seatFrameObj);//座椅var seatObj = new LSprite();seatObj.trigger = "destroy_bicycle";seatObj.x = sx+30;seatObj.y = sy-gapBetweenWheelFrameAndSeat-seatHeight/2;seatObj.addBodyPolygon(seatWidth,seatHeight,1,.5);world.addChild(seatObj);s.bodyList.push(seatObj);/**增加輪子*///左邊輪子Avar wheelAObj = new LSprite();wheelAObj.x = sx-wheelR;wheelAObj.y = sy;wheelAObj.addBodyCircle(wheelR,wheelR,wheelR,1,2.5,.2,.4);world.addChild(wheelAObj);s.bodyList.push(wheelAObj);//右邊輪子Bvar wheelBObj = new LSprite();wheelBObj.x = sx+gapBetweenWheelAndWheel-wheelR;wheelBObj.y = sy;wheelBObj.addBodyCircle(wheelR,wheelR,wheelR,1,2.5,.2,.4);world.addChild(wheelBObj);s.bodyList.push(wheelBObj);/**增加關節*///輪子A和輪子支架的旋轉關節world.jointList.push(LStage.box2d.setRevoluteJoint(frameAObj.box2dBody, wheelAObj.box2dBody));//輪子B和輪子支架的旋轉關節world.jointList.push(LStage.box2d.setRevoluteJoint(frameAObj.box2dBody, wheelBObj.box2dBody));//車把到輪子的支架和輪子支架的焊接關節world.jointList.push(LStage.box2d.setWeldJoint(frameAObj.box2dBody, frameBObj.box2dBody));//車把到輪子的支架和車把的焊接關節world.jointList.push(LStage.box2d.setWeldJoint(handlebarObj.box2dBody, frameBObj.box2dBody));//輪子的支架和座椅的焊接關節world.jointList.push(LStage.box2d.setWeldJoint(seatFrameObj.box2dBody, frameAObj.box2dBody));//座椅的支架和座椅的焊接關節world.jointList.push(LStage.box2d.setWeldJoint(seatFrameObj.box2dBody, seatObj.box2dBody));/**遍曆全部單車零件剛體*/for(var key in s.bodyList){var obj = s.bodyList[key];//增加滑鼠拖動if(obj.box2dBody)obj.setBodyMouseJoint(true);//設定對象名稱obj.name = "bicycle";}/**設定主剛體*/s.mainBody = frameAObj.box2dBody;/**設定拉壓操作剛體*/s.tcBody = wheelBObj.box2dBody;};
主要改的是這裡:

/**增加關節*///輪子A和輪子支架的旋轉關節world.jointList.push(LStage.box2d.setRevoluteJoint(frameAObj.box2dBody, wheelAObj.box2dBody));//輪子B和輪子支架的旋轉關節world.jointList.push(LStage.box2d.setRevoluteJoint(frameAObj.box2dBody, wheelBObj.box2dBody));//車把到輪子的支架和輪子支架的焊接關節world.jointList.push(LStage.box2d.setWeldJoint(frameAObj.box2dBody, frameBObj.box2dBody));//車把到輪子的支架和車把的焊接關節world.jointList.push(LStage.box2d.setWeldJoint(handlebarObj.box2dBody, frameBObj.box2dBody));//輪子的支架和座椅的焊接關節world.jointList.push(LStage.box2d.setWeldJoint(seatFrameObj.box2dBody, frameAObj.box2dBody));//座椅的支架和座椅的焊接關節world.jointList.push(LStage.box2d.setWeldJoint(seatFrameObj.box2dBody, seatObj.box2dBody));
我把全部的關節都增加到wolrd的jointList裡了,這樣一來我們就能夠通過遍曆取出關節來,然後進行銷毀,這一點在Main的postSolve裡就已經實現了。

還有改動的就是:1。給全部的屬於單車的剛體都加了一個name屬性,設定為:“bicycle”。2。給關鍵部位的剛體(車把、車把到輪子的支架和車座)加了trigger屬性,設定為“destroy_bicycle”。表示假設這些部位碰到了其它不屬於單車的剛體,就結束遊戲。

至於name為"wall"的剛體事實上就僅僅有一個(bottomBorder底部邊框。促使單車跌究竟部時結束遊戲):

Main.prototype.addBorder = function(){var s = this;/**建立邊框*///設定邊框尺寸var borderSize = 10;//頂部邊框var topBorder = new LSprite();topBorder.x = s.sceneWidth/2;topBorder.y = 5;topBorder.addBodyPolygon(s.sceneWidth,borderSize,0);s.addChild(topBorder);//右部邊框var rightBorder = new LSprite();rightBorder.x = s.sceneWidth-5;rightBorder.y = s.sceneHeight/2;rightBorder.addBodyPolygon(borderSize,s.sceneHeight,0);s.addChild(rightBorder);//底部邊框var bottomBorder = new LSprite();bottomBorder.name = "wall";bottomBorder.x = s.sceneWidth/2;bottomBorder.y = s.sceneHeight-5;bottomBorder.addBodyPolygon(s.sceneWidth,borderSize,0);s.addChild(bottomBorder);//左部邊框var leftBorder = new LSprite();leftBorder.x = 5;leftBorder.y = s.sceneHeight/2;leftBorder.addBodyPolygon(borderSize,s.sceneHeight,0);s.addChild(leftBorder);};
Ok,執行代碼,得到的就是本文最上方圖片所看到的的效果了。


奉上源碼:http://files.cnblogs.com/yorhom/box2dBicycle%283%29.rar

測試地址:http://yuehaowang.github.io/demo/ridebike_box2d/

本系列教程就到此為止了,事實上假設要做一個真正的“越野山地單車”這樣的遊戲,還須要對剛體進行貼圖,勝利推斷等。這些都非常easy,大家能夠自己動手做一做吧~(眼下我做的demo應該能夠當作一種發泄工具吧,壓力大了,就來把這輛虛擬單車拿來狠狠地摔吧~ 哈哈)

還有同學(這會兒但是真正意義上的同學了...)問我怎樣操作,好吧。算我失誤。沒有在本章告訴大家(事實上你看了第兩章就會知道的),在這裡補充一下。

操作說明:上下左右鍵操作,至於這些按鍵相應的效果就自己摸索吧,實在總結不出來就去第二章慢慢找吧,我也就偷個懶吧~


本章就先到這裡了。假設文章有不論什麼疏漏之處,歡迎指正。當然,有不懂之處也歡迎各位在本文下方留言。我會儘力回複大家的。

----------------------------------------------------------------

歡迎大家轉載我的文章。

轉載請註明:轉自Yorhom‘s Game Box

http://blog.csdn.net/yorhomwang

歡迎繼續關注我的部落格

HTML5物理遊戲開發 - 越野山地單車(三)粉碎單車

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.