最近開始研究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
歡迎繼續關注我的博客