【HTML5物理小Demo】用Box2dWeb實現鎖鏈+彈簧效果

最近開始研究Box2dweb,Box2dweb是一款物理引擎,主要是對物理剛體和關節連接進行了封裝,box2dweb很強大當然也有些複雜,不過幸好lufylegend.js做了這方面的封裝,在製作時如果用lufylegend配合Box2dweb,那就簡單多了。要學習box2dWeb我還是給大家推薦拉登大叔的博客,地址:http://www.ladeng6666.com/blog,寫得相當好,話說他的文章中還運用了相當多的修辭手法呢,看他的文章邊學技術,邊學寫作,哈哈。順便也提一提,本次實現的效果也是模仿拉登大叔一篇文章中的效果,不過大叔的是ActionScript版本的,我是Js版的。

最後還是祝大家新年快樂吧~雖然這祝福來晚了,不過還是滿含我的誠意……偷笑

好了,費話不多說,直接進入正題。

首先看截圖吧,如下:



測試鏈接:http://yuehaowang.github.io/demo/box2d_linkage/

接下來就來講一講實現步驟。


一,準備工作

首先你需要下載lufylegend和box2dweb 這兩個引擎。

box2dweb可以到這裏下載:

http://code.google.com/p/box2dweb/downloads/list

lufylegend可以到這裏:

http://lufylegend.com/lufylegend

關於lufylegend怎麼用,可以到這裏看看API文檔:

http://lufylegend.com/lufylegend/api

Box2dWeb怎麼用?其實我也不太清楚,這次主要用lufylegend封裝的API,用到原生API的時候我自己來講講吧,講的差不要罵喔~


二,原理

這個小demo的原來其實很簡單,就是將幾塊矩形小剛體用旋轉關節連接起來。當然,說起來很容易,其實做起來還是要深究的。在我看到拉登大叔的文章之前,其實我也沒有想到什麼方法,於是就借鑑了大叔的文章,原理不是我獨創的,所以呢,不好直說,免得大叔看到了不高興,大家看一看拉登大叔的文章就能明白原理了。

文章地址如下:http://www.ladeng6666.com/blog/2012/11/25/create-box2d-linkage-or-bridge-effect-using-b2joint/


三,含詳細註釋的源代碼

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>box2d demo</title>
	<script type="text/javascript" src="./Box2dWeb-2.1.a.3.min.js"></script>
	<script type="text/javascript" src="./lufylegend-1.8.7.min.js"></script>
	
	<script type="text/javascript">
		init(50,"mylegend",600,400,pageInit);
		function pageInit(){
			LStage.setDebug(true);
			LStage.box2d = new LBox2d();

			if(LStage.canTouch == true){
				document.body.style.margin = "0px 0px";
				LStage.stageScale = LStageScaleMode.SHOW_ALL;
				LSystem.screen(LStage.FULL_SCREEN);
			}

			var mainObj = new Main();
			addChild(mainObj);
		}

		/**
		 *Main
		 *@author: Yorhom
		 *@http://blog.csdn.net/yorhomwang
		*/
		function Main(){
			var s = this;
			base(s,LSprite,[]);

			/**加入圍牆*/
			s.addWall();
			/**加入鎖鏈橋*/
			s.addBridge();
			/**隨機加入其他物體*/
			s.addRandomObj();
		}
		Main.prototype.addWall = function(){
			var s = this;
			
			//設置圍牆大小
			var wallSize = 10;
			//設置圍牆數據
			var wallList = [
				//左邊
				[wallSize*0.5, LStage.height*0.5, wallSize, LStage.height],
				//右邊
				[LStage.width-wallSize*0.5, LStage.height*0.5, wallSize, LStage.height],
				//上面
				[LStage.width*0.5, wallSize*0.5, LStage.width, wallSize],				
				//下面
				[LStage.width*0.5, LStage.height-wallSize*0.5, LStage.width, wallSize],
			];
			//通過遍歷圍牆數據,添加四面圍牆
			for(var key in wallList){
				//獲取數據
				var item = wallList[key];
				//創建圍牆對象
				var wallLayer = new LSprite();
				//設定對象位置
				wallLayer.x = item[0];
				wallLayer.y = item[1];
				//加入剛體
				wallLayer.addBodyPolygon(item[2],item[3],0);
				//加入顯示列表
				s.addChild(wallLayer);
			}
		};
		Main.prototype.addBridge = function(){
			var s = this;

			//關節向量
			var vec = new LStage.box2d.b2Vec2();
			//添加對象數量
			var amount = 6;
			//設置對象寬度和高度
			var bw=50,bh=15;
			//獲取鎖鏈橋總長度
			var bridgeWidth = bw*amount;
			//設置鎖鏈橋開始位置
			var initX=(LStage.width-bridgeWidth)*0.5,
				initY=(LStage.height-bh)*0.5+30;
			//設置用於固定鎖鏈橋的定點半徑
			var anchorR = 15;

			/**用於固定鎖鏈橋的定點A*/
			var anchorA = new LSprite();
			anchorA.x = initX-anchorR;
			anchorA.y = initY-anchorR;
			anchorA.addBodyCircle(anchorR,anchorR,anchorR,0);
			s.addChild(anchorA);
			/**用於固定鎖鏈橋的定點B*/
			var anchorB = new LSprite();
			anchorB.x = bridgeWidth+initX-anchorR;
			anchorB.y = initY-anchorR;
			anchorB.addBodyCircle(anchorR,anchorR,anchorR,0);
			s.addChild(anchorB);

			//上一個對象
			var previousBlock = anchorA;

			/**循環添加剛體*/
			for(var i=0; i<amount; i++){
				//實例化對象
				var block = new LSprite();
				//設定對象位置
				block.x = initX+i*bw+bw*0.5;
				block.y = initY;
				//加入剛體
				block.addBodyPolygon(bw,bh,1);
				//設置鼠標拖動
				block.setBodyMouseJoint(true);
				//加入顯示列表
				s.addChild(block);
				//加入關節
				var revoluteJoint = new LStage.box2d.b2RevoluteJointDef();
				vec.Set((initX+i*bw)/30, initY/30);
				revoluteJoint.Initialize(previousBlock.box2dBody,block.box2dBody,vec);
				LStage.box2d.world.CreateJoint(revoluteJoint);
				//更改上一個對象
				previousBlock = block;
			}
			//將最後一個剛體固定
			var revoluteJoint = new LStage.box2d.b2RevoluteJointDef();
			vec.Set((initX+i*bw)/30, initY/30);
			revoluteJoint.Initialize(previousBlock.box2dBody,anchorB.box2dBody,vec);
			LStage.box2d.world.CreateJoint(revoluteJoint);
		};
		Main.prototype.addRandomObj = function(){
			var s = this;
			for(var i=0; i<10; i++){
				//創建對象
				var obj = new LSprite();
				//設置對象位置
				obj.x = Math.floor(Math.random()*(400-200+1)+200);
				obj.y = 0;
				//加入顯示列表
				s.addChild(obj);
				//根據隨機數添加不同的剛體
				if(Math.random() > 0.5){
					//獲取隨機寬度和高度
					var w = Math.floor(Math.random()*10)+25;
					var h = Math.floor(Math.random()*10)+25;
					//重現設置y座標
					obj.y += h*0.5;
					//添加矩形剛體
					obj.addBodyPolygon(w,h,1);
				}else{
					//獲取隨機半徑
					var r = Math.floor(Math.random()*20)+5;
					//重現設置y座標
					obj.y += r;
					//添加圓形剛體
					obj.addBodyCircle(r,r,r,1);
				}
				//設置鼠標拖動
				obj.setBodyMouseJoint(true);
			}
		};
	</script>
</head>
<body>
	<div id="mylegend"></div>
</body>
</html>
所有代碼都在這裏了,還是很少的,對吧。看了拉登大叔的原理講解,再來看我寫的js代碼就非常容易了。主要是注意以下幾個地方。

1,添加剛體

在box2dweb中添加剛體超級麻煩,把整個創建過程告訴大家估計大家都會覺得不耐煩,所以,我用到了lufylegend.js添加剛體,這樣一來添加剛體就被簡化成一步了。非常方便,不是嗎?在lufylegend中添加剛體一共有這幾個函數:

addBodyCircle()添加原形剛體
addBodyPolygon()添加矩形剛體
addBodyVertices()添加不規則圖形剛體

具體的參數說明和使用舉例可以參見lufylegend的API文檔中LSprite的API。文檔地址已在文章的準備工作一欄寫出。

2,添加關節

在lufylegend雖然也有添加關節的封裝,但是不能設置關節點。所以我還是用了box2dweb原生方法。添加關節的代碼如下:

var revoluteJoint = new LStage.box2d.b2RevoluteJointDef();
vec.Set((initX+i*bw)/30, initY/30);
revoluteJoint.Initialize(previousBlock.box2dBody,block.box2dBody,vec);
LStage.box2d.world.CreateJoint(revoluteJoint);
其他的好理解,主要是vec這個變量,它在這裏是一個向量對象,實例化代碼如下:

var vec = new LStage.box2d.b2Vec2();
其實這個b2Vec2這個類可以傳參數,和它的成員函數Set的參數是一樣的。但是這裏又多個關節,所以就沒有直接設置,而是在後面用Set方法設置。這個向量可以看成一個json吧,傳的參數就是設定關節的位置(x,y)。

在創建了關節之後,千萬別忘記下面的代碼:

LStage.box2d.world.CreateJoint(revoluteJoint);
另外,Initialize方法傳的參數是box2dweb的剛體對象,在LSprite中的 box2dBody就可以獲取該LSprite添加的剛體。

3,固定動態剛體

在box2dweb中,剛體分動態和靜態。靜態剛體比較老實,就呆在原地不動;動態剛體很活潑,不停地在做運動。

拉登大叔其實也寫過相關的文章,但是我沒怎麼看,於是就自己想了一個方法:首先在鎖鏈的兩端建立兩個圓形靜態剛體,然後把鎖鏈兩端的兩塊矩形剛體分別連在附近的圓形靜態剛體上,圓形靜態剛體就會幫忙把鎖鏈拽着,不讓它亂跑。但由於鎖鏈中每個矩形剛體是動態的,所以他們還是可以互相牽扯的。

4,如果你自己在用lufylegend+box2dweb編寫時看不到圖象,該怎麼辦?

首先你要檢測一下是否在最底層上加了一個LSprite,並且用這個LSprite的graphics畫了一個不透明的背景。如果是的話,你可以把這個LSprite去掉,然後再看看有沒有。如果還沒有,可能有以下幾種原因:(1)沒有在用之前加入LStage.setDebug(true); (2)沒有在使用box2dweb之前加入LStage.box2d = new LBox2d();


源代碼在上面已經全部給出了,運行時需要配置一下引擎box2dweb和lufylegend,然後把引擎的壓縮版本(文件名含.min)放在與html同級的文件目錄下即可運行,測試愉快~


好了,今天就先講到這裏。如果大家有不懂的地方可以用微博@Yorhom或者用郵箱聯繫我wangyuehao1999(at)gmail.com(這年頭寫e-mail地址再不把@換成(at)垃圾郵件多得甚至會把你用的郵件程序弄得黑白不分呢)。希望大家多支持。下次還會繼續給大家帶來更多有趣的小玩意。敬請期待~


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

歡迎大家轉載我的文章。

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

http://blog.csdn.net/yorhomwang

歡迎繼續關注我的博客

發佈了67 篇原創文章 · 獲贊 45 · 訪問量 93萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章