(老文章)Box2D新手入门顺阶教程
注意:
本教程只適用于BOX2D 2.0以下版本,由于2.0版API的改動,所以有部分代碼會并不適用.但是主要思想還是一樣的.
一、 HelloWorld
開始之前,我假想你已經(jīng)看過了HelloWorld的源代碼,并看了用戶手冊中關(guān)于HelloWorld的相關(guān)說明,而且已經(jīng)大致明白了大多數(shù)內(nèi)容。
其實HelloWorld已經(jīng)用極其簡單的語言向你描述了Box2D物理引擎的運作機制,我們可以歸納一下步驟:
1、 建立一個世界,這個世界基于一個b2AABB框,并設(shè)立了一個g值和一個是否允許休眠的bool型變量。
2、 建立一個靜態(tài)剛體地表,這里講述了定義Box2D物理引擎中最為重要的一個東西——剛體的詳細過程:首先是定義一個形狀(可以是復(fù)合形狀,這個在第二部分講述),然后把形狀通過AddShape添加進剛體定義,創(chuàng)建這個剛體。
3、 重復(fù)創(chuàng)建剛體這個過程,直至你沒有需求了。
4、 在你的循環(huán)中加入世界的更新函數(shù)。
其實上面的步驟也是眾多物理引擎甚至于其他引擎采用的方式。
HelloWorld教程是相當(dāng)簡單的,這個時候你甚至都不用去想世界是怎么運作的,你可以利用相關(guān)函數(shù)取得剛體的位置和旋轉(zhuǎn)角度,然后在游戲的渲染部分去更新渲染你的角色對象。
看完HelloWorld,你可以不去想整個世界是怎樣的,因為這個世界相對這時的你來說,確實是太復(fù)雜了,而你靜下心來時,不妨回頭看看我們用到的概念和數(shù)據(jù)類型,來溫顧一下。
概念
在這一個例子中有幾個概念,
世界(b2World):世界就是一個環(huán)境,所有物理運算都在這個里面進行。
形狀定義(b2ShapeDef):形狀定義是什么?說簡單點形狀定義就是定義你這個對象的樣子,它用來做什么?就是用來確定你的碰撞。
剛體定義(b2BodyDef):剛體定義就是設(shè)定剛體的初始具體,在目前來說,最大的功能就是把你定義好的形狀加到你想到的剛體上。
剛體(b2Body):剛體就是物理引擎里面的東西(對象),它可以受力的作用進行當(dāng)前位置的變化旋轉(zhuǎn)等。你要在世界中使用的所有物體目前來說都是剛體。
類型定義
幾個類型定義(熟悉Box2D里面的類型定義可以對我們將來正確賦值運算有著很大的幫助):
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef float float32;
const float32 b2_pi = 3.14159265359f;
數(shù)據(jù)類型
1、 b2Vec2
就像在3D中Vector3類的使用一樣,b2Vec2在Box2D中也應(yīng)用廣泛,你幾乎在每個時刻都用到它,比如說定義坐標(biāo)位置,定義Box大小等
b2Vec2是由float32類型的x,y組成,支持負向量,+=,-=,*=操作符,
支持的方法有
Void SetZero();設(shè)置x,y為0
Void Set(float32 x_, float32 y_);設(shè)置x,y為指定值
b2Vec2 Make(float32 x_, float32 y_),生成一個值指定的b2Vec2
float32 Length()取得向量的長度或模
float32 Normalize()標(biāo)準(zhǔn)化向量
bool IsValid()檢查是否有效
如果在這里你并不了解我在這里所提到的一些數(shù)學(xué)概念,比如說標(biāo)準(zhǔn)化向量,模,可以參照b2Math.h文件,或者直接找本數(shù)學(xué)書來看。
2、b2Mat22
在HelloWorld教程中,b2Mat22雖然沒有被使用到,我們這里先提出這個概念,以便于在下一節(jié)中討論。
其實b2Mat22一個由兩個b2Vec2組成的2*2方陣,你可以直接由兩個b2Vec2(col1、col2)構(gòu)造或者由一個角度值構(gòu)造。
他的主要方法有:
void Set(const b2Vec2& c1, const b2Vec2& c2)
void Set(float32 angle),
提供兩種方式賦值方法
void SetIdentity(),設(shè)定恒等式
void SetZero(),把col1、col2的x,y都清為0
b2Mat22 Invert(),轉(zhuǎn)換相關(guān)數(shù)據(jù)
b2Vec2 Solve(const b2Vec2& b),解決A * x = b
3、b2AABB
b2AABB就是一個盒子,是由兩個向量組成,一個為minVertex是最小頂點,另一個為maxVertex是最大頂點,通過這兩個頂點來表示最為普通的AABB框。
4、b2ShapeDef
b2ShapeDef直翻為形狀定義,它用一個b2ShapeType型量type來表示形狀類型,用函數(shù)指針來表示用戶數(shù)據(jù)(userdata),用一個b2Vec2向量localPosition來表示當(dāng)前位置,用float32的localRotation來表示當(dāng)前角度,用float32的friction、density、restitution來表示摩擦力、密度、彈性系數(shù),用uint16的categoryBits和maskBits來表示碰撞位及位標(biāo)識(可以用來過濾一些碰撞),用int16的groupIndex來表示組號,這個組號可以用來過濾還比位標(biāo)識優(yōu)先。
相關(guān)常量
enum b2ShapeType
{
e_unknownShape = -1,
e_circleShape,
e_boxShape,
e_polyShape,
e_meshShape,
e_shapeTypeCount,
};
相關(guān)形狀定義
b2CircleDef繼承于b2ShapeDef,type 為 e_circleShape,另外帶有一個類型為float32的量radius來表示半徑值。
b2BoxDef繼承于b2ShapeDef,type 為 e_ boxShape,另外帶有一個類型為b2Vec2的量extents來表示區(qū)域值。
b2PolyDef繼承于b2ShapeDef,type 為 e_ polyShape,另外帶有一個類型為b2Vec2的數(shù)組vertices來表示頂點,并帶有一個int32型的量vertexCount來表示頂點數(shù),目前頂點數(shù)最多支持8個。
5、b2BodyDef
b2BodyDef是剛體定義結(jié)構(gòu),由一個函數(shù)指針userData來表示用戶數(shù)據(jù),一組類型為b2ShapeDef*指針數(shù)組shapes來表示形狀隊列,目前形狀數(shù)最大支持64個,用一個b2Vec2向量position來表示當(dāng)前位置,用類型為float32的量rotation來表示當(dāng)前角度,用類型為b2Vec2的量linearVelocity表示線速度,用類型為float32的angularVelocity來表示角速度,用類型為float32的量linearDamping來表示線性阻尼,用類型為float32的量angularDamping來表示角阻抗,用類型為bool的allowSleep 來表示是否可以允許休眠,用一個類型為bool的isSleeping來表示是否正在休眠,用一個類型為bool的量preventRotation來表示是否防止旋轉(zhuǎn),支持方法:
AddShape(b2ShapeDef* shape)。
上面這些東西,其實現(xiàn)在沒有必要去記住,慢慢運用中就可以熟練掌握。
源文件包里除了這個HelloWorld之外還有不少的例子,個人建議先從CompoundShapes開始。
二、CompoundShapes
CompoundShapes其實也沒有做什么事情,相對于HelloWorld來說,我認為,僅僅是多了一個方法的應(yīng)用,即是有關(guān)b2Mat22方陣和向量的相乘應(yīng)用,這里被用來獲得轉(zhuǎn)換后的位置。
這個例子對于看過HelloWorld的你來說,應(yīng)該會很簡單,只是建議看這個例子的時候再翻翻數(shù)學(xué)書,并復(fù)習(xí)一下使用到的幾種數(shù)據(jù)類型說明。
三、 VaryingRestitution、VaryingFriction、Pyramid、PolyShapes
Box2D本身所自帶的教程相當(dāng)?shù)纳?#xff0c;前兩個例程是關(guān)于摩擦力和彈性系數(shù)的例子,也僅僅修改了相關(guān)數(shù)據(jù),算是一種演示吧,Pyramid這個例子也就是一個簡單的例子,只是使用了Make方法來創(chuàng)建向量。沒什么參考價值。
PolyShapes這個例子舉個自定義多邊形形狀的方法,你只要記住當(dāng)前多邊形最多支持頂點數(shù)為8就行了。
四、 CollisionFiltering、
碰撞過濾是用來防止形狀與形狀之間進行碰撞的,就像上文所示,它可以用碰撞種類和組名來區(qū)別,Box2D總共提供16種碰撞種類,每個形狀都可以提定屬于什么種類,那么它就可以和其他不同種類的形狀碰撞,如果在一個多人在線游戲中,你想你的玩家在他們之間不進行碰撞,怪物和怪物之間不進行碰撞,但人和怪物進行碰撞,你可以使用
playerShapeDef.categoryBits = 0x0002; monsterShapeDef.categoryBits = 0x0004; playerShape.maskBits = 0x0004; monsterShapeDef.maskBits = 0x0002;
碰撞組索引是一個可以大量指定物體碰撞規(guī)則的東西,你可以通過它來指定成百上千的物體,當(dāng)碰撞組索引為負數(shù)時,東西之間不碰撞,當(dāng)為正數(shù)時進行碰撞,而且碰撞組索引的優(yōu)先級比碰撞種類要高。
shape1Def.groupIndex = 2; shape2Def.groupIndex = 2; shape3Def.groupIndex = -8; shape4Def.groupIndex = -8;
形狀1和2就碰撞,因為組索引大于0,而3和4不碰撞,因為小于0
可以參考例子代碼來確定你的碰撞方法.
五、 ApplyForce
應(yīng)力的應(yīng)用是物理引擎中必不可少的部分,你有剛體能碰撞卻不能推動它,那么它必定會給你帶來很強的挫敗感。
在這個教程中,主要是對剛體的幾個方法進行了應(yīng)用,這些方法都很簡單易用。
剛體有兩個點對我們有用,一個是剛體的坐標(biāo)點,另一個是剛體的質(zhì)心位置。剛體的質(zhì)心位置就不需要你自己指出,Box2D將會自己算出這個坐標(biāo)。
剛體有如下幾個成員變量,
uint32 m_flags;
質(zhì)心位置:
b2Vec2 m_position;
質(zhì)心旋轉(zhuǎn)度:
float32 m_rotation;
線性速度:
b2Vec2 m_linearVelocity;
角速度:
float32 m_angularVelocity;
力:
b2Vec2 m_force;
扭矩:
float32 m_torque;
形狀表:
b2Shape* m_shapeList;
形狀數(shù):
int32 m_shapeCount;
關(guān)節(jié)表:
b2JointNode* m_jointList;
關(guān)節(jié)數(shù):
b2ContactNode* m_contactList;
質(zhì)量:
float32 m_mass, m_invMass;
float32 m_I, m_invI;
線性阻尼:
float32 m_linearDamping;
角阻尼:
float32 m_angularDamping;
休眠時間
float32 m_sleepTime;
用戶數(shù)據(jù):
void* m_userData;
并有以下幾種方法:
1、設(shè)置剛體位置和旋轉(zhuǎn)度
void SetOriginPosition(const b2Vec2& position, float32 rotation);
2、取剛體當(dāng)前位置
b2Vec2 GetOriginPosition() const;
3、設(shè)置剛體的質(zhì)心位置及旋轉(zhuǎn)度
void SetCenterPosition(const b2Vec2& position, float32 rotation);
4、取得剛體的質(zhì)心位置
b2Vec2 GetCenterPosition() const;
5、取得旋轉(zhuǎn)度
float32 GetRotation() const;
6、取得旋轉(zhuǎn)矩陣
const b2Mat22& GetRotationMatrix() const;
7、設(shè)置和取得質(zhì)心的線性速度
void SetLinearVelocity(const b2Vec2& v);
b2Vec2 GetLinearVelocity() const;
8、設(shè)置和取得角速度
void SetAngularVelocity(float32 w);
float32 GetAngularVelocity() const;
9、應(yīng)用一個力到世界點上
void ApplyForce(const b2Vec2& force, const b2Vec2& point);
force為力的大小,point為作用點
10、應(yīng)用一個扭矩
void ApplyTorque(float32 torque);
11、在點上應(yīng)用一個推力
void ApplyImpulse(const b2Vec2& impulse, const b2Vec2& point);
12、取得質(zhì)量
float32 GetMass() const;
13、取得慣性
float32 GetInertia() const;
14、取得世界點(取得給定相對于質(zhì)心的點的世界坐標(biāo))
b2Vec2 GetWorldPoint(const b2Vec2& localPoint);
15、根據(jù)屆出當(dāng)前坐標(biāo)系給的向量來得到世界向量
b2Vec2 GetWorldVector(const b2Vec2& localVector);
16、根據(jù)給定世界坐標(biāo)來得到相對于質(zhì)心的坐標(biāo)
b2Vec2 GetLocalPoint(const b2Vec2& worldPoint);
17、根據(jù)一個世界向量來取得一個此時的向量
b2Vec2 GetLocalVector(const b2Vec2& worldVector);
18、判斷剛體是否靜止
bool IsStatic() const;
19、判斷剛體是否冷凍
bool IsFrozen() const;
20、判斷剛體是否休眠
bool IsSleeping() const;
21、你可以用它來單獨設(shè)置這個剛體是否可以休眠
void AllowSleeping(bool flag);
22、喚醒這個剛體
void WakeUp();
23、取得附加在這個剛體上的形狀表
b2Shape* GetShapeList();
24、取得附加在這個剛體上的聯(lián)系表
b2ContactNode* GetContactList();
25、取得附加在這個剛體上的所有關(guān)節(jié)表
b2JointNode* GetJointList();
26、取得這個剛體在世界剛體表中的下一剛體
b2Body* GetNext();
27、取得用戶數(shù)據(jù)
void* GetUserData();
void SynchronizeShapes();
void QuickSyncShapes();
// This is used to prevent connected bodies from colliding.
// It may lie, depending on the collideConnected flag.
bool IsConnected(const b2Body* other) const;
// This is called when the child shape has no proxy.
void Freeze();
標(biāo)記
enum
{
e_staticFlag = 0x0001,
e_frozenFlag = 0x0002,
e_islandFlag = 0x0004,
e_sleepFlag = 0x0008,
e_allowSleepFlag = 0x0010,
e_destroyFlag = 0x0020,
};
雖然說剛體這個類的很多成員變量沒有私有化,但是還是建議你使用它的眾多方法來管理。
在進行力學(xué)應(yīng)用的時候,經(jīng)常會需要相關(guān)轉(zhuǎn)換坐標(biāo),所以建議找找相關(guān)書看看。
六、 Web
在開始之前,我們先來回顧一下以前所討論過的形狀,剛體,在這里我們來看看使用他們有什么值得注意的地方。
1、關(guān)于多邊形形狀定義,我們由b2_maxPolyVertices決定了最大頂點數(shù)為8,如果你想要更多的多邊形,那么我可以在b2Setting.h里面修改相關(guān)數(shù)值。你在使用多邊形時,一定要指定頂點數(shù),而且頂點坐標(biāo)得按逆時針順序(CCW),你不能交疊任何的頂點,多邊形會自動幫你閉合,同時這個多邊形得凸起的,也就是說你必須讓每個頂點都向外擴展一定角度,以上幾點很重要,不要因此引起許多莫名其妙的錯誤。
2、關(guān)于摩擦力和彈性系數(shù),摩擦力與應(yīng)力是成比例關(guān)系,它介出0和1之間,0表示無摩擦,1表示摩擦力很強,如果有兩個形狀都定義了摩擦力,那么它實際摩擦力將會是兩個摩擦力的乘積開根。
3、彈性系數(shù)讓物體能夠彈起來,值也介于0與1之間,如果一個球掉到桌面上來,這個值是0的時候則不會彈起來,如果是1的話那么就叫完全彈性碰撞,如果剛體中有兩個形狀都有不同的彈性系數(shù),那么使用這個方法:
float32 restitution;
restitution = b2Max(shape1->restitution, shape2->restitution);
4、關(guān)于碰撞過濾,有三種情況下是附加影響碰撞的,靜態(tài)物體之間形狀不發(fā)生碰撞,同一個剛體中的形狀不發(fā)生碰撞,你能設(shè)置的在關(guān)節(jié)連接的兩個物體形狀間是否發(fā)生碰撞。
5、關(guān)于創(chuàng)建和銷毀一個形狀,你沒有必要去討論形狀的創(chuàng)建和銷毀,Box2D會幫你自動完成。
6、每一剛體添加形狀是由參數(shù)b2_maxShapesPerBody來控制的,目前最大設(shè)為64,如果你想要更大的話,那么你修改b2Setting.h里面相關(guān)數(shù)值。
7、關(guān)于剛體創(chuàng)建與銷毀,你不需要手動為一個剛體分配和釋放內(nèi)存,這些都由引擎自動完成,所以你創(chuàng)建的時候,你僅僅需要:
b2Body* body = myWorld->CreateBody(&bodyDef);
???? 銷毀的時候:
???? myWorld->DestroyBody(body);
???? body = NULL;
8、當(dāng)剛體被銷毀時,附加在上面的關(guān)節(jié)都會自動銷毀,你必須清空這些關(guān)節(jié)指針,不然你的程序會在你以后銷毀關(guān)卡的時候死得很難看。為了幫助你清空你的關(guān)卡指針,Box2D提供一個叫作b2WorldListener的監(jiān)聽類,你可以應(yīng)用它來清空,之后世界就會告訴你到一個關(guān)節(jié)被銷毀。
9、喚醒一個休眠物體你只能用b2Body::WakeUp,在它上面應(yīng)用任何力是不可以喚醒一個剛體的。
10、要擅于利用剛體的轉(zhuǎn)換函數(shù),它會幫我們解決很多問題。
11、在Debug模式下,最好能利用下列代碼把形狀顯示出來,幫助我們調(diào)試。
for (b2Shape* s = body->GetShapeList(); s; s = s->GetNext())
{ GameDrawShape(s);
}
12、Box2D里面所說的角度都是指弧度。
正文
在這一教程開始之前,先來討論關(guān)節(jié)。
關(guān)節(jié)(Joint)其實就是用來連接剛體的,你可以想像一下你的手。每一個關(guān)節(jié)也有一個關(guān)節(jié)定義b2JointDef,所有關(guān)節(jié)都連接在兩個不同的剛體之間,一個可能是靜態(tài),如果你想浪費內(nèi)存的話,就創(chuàng)建一個連在兩個靜態(tài)剛體上吧。
關(guān)節(jié)是物體引擎中的另一重要部分,所以Box2D中把它作了細分,我們目前暫時先討論在這個例程中使用的Distance關(guān)節(jié)。
先來看b2JointDef的結(jié)構(gòu):
struct b2JointDef
{ b2JointType type;
void* userData;
b2Body* body1;
b2Body* body2;
bool collideConnected;
};
Type表示為類別e_unknownJoint、 e_revoluteJoint、e_prismaticJoint、 e_distanceJoint、 e_pulleyJoint、 e_mouseJoint、 e_gearJoint。Userdata是用戶數(shù)據(jù),body1、body2為兩個剛體指針,collideConnected表示是否在兩個剛體之間檢查碰撞。
Distance Joint是一種用來連接兩個剛體的有距線段關(guān)節(jié)。你使用它的時候必須分別給兩個剛體指定兩個錨點,這兩個點意味著此關(guān)節(jié)的長度。
b2DistanceJointDef的結(jié)構(gòu)
struct b2DistanceJointDef : public b2JointDef
{ b2Vec2 anchorPoint1;
b2Vec2 anchorPoint2;
};
繼承于b2JointDef,只是多了兩個錨點。
下面是此關(guān)節(jié)定義的一個應(yīng)用:
b2DistanceJointDef jointDef; jointDef.body1 = myBody1; jointDef.body2 = myBody2; jointDef.collideConnected = true; jointDef.anchorPoint1 = myBody1->GetCenterPosition(); jointDef.anchorPoint2 = myBody2->GetCenterPosition();
參照Web例子,我們會發(fā)現(xiàn)定義一個關(guān)節(jié)其實也很簡單
1、指定關(guān)節(jié)定義
2、創(chuàng)建關(guān)節(jié)
3、結(jié)束時銷毀關(guān)節(jié)
七、 Chain、Bridge、Cradle
Chain、Bridge兩個例程是對Revolute Joint的應(yīng)用,Revolute Joint是兩個剛體共用一個錨點,它有一個自由度,在這里被叫作關(guān)節(jié)角度。
為了指定一個Revolute你必須提供兩個剛體和一個錨點,引擎會假定這兩個剛體已經(jīng)在正確位置上。
它的結(jié)構(gòu)如下:
struct b2RevoluteJointDef : public b2JointDef
{
b2Vec2 anchorPoint;
float32 lowerAngle;
float32 upperAngle;
float32 motorTorque;
float32 motorSpeed;
bool enableLimit;
bool enableMotor;
};
它也是繼承于b2JointDef,anchorPoint是錨點,lowerAngle為轉(zhuǎn)動角底限,upperAngle為轉(zhuǎn)動角上限,其他的這里暫時先不介紹。
Chain、Bridge兩個例子非常簡單,和Distance Joint相差不大,算是對Joint使用的再次鞏固。
八、 Pulleys
Pulleys是對Prismatic Joint、Pulley Joint的應(yīng)用,Prismatic Joint是一種允許兩個剛體沿指定軸相對移動的關(guān)節(jié),不允許相對旋轉(zhuǎn),所以有一個自由度。
它的結(jié)構(gòu)下:
struct b2PrismaticJointDef : public b2JointDef
{
b2Vec2 anchorPoint;
b2Vec2 axis;
float32 lowerTranslation;
float32 upperTranslation;
float32 motorForce;
float32 motorSpeed;
bool enableLimit;
bool enableMotor;
};
我們這時暫時只應(yīng)用到anchorPoint,axis,axis為軸,lowerTranslation為移動底限,upperTranslation為移動上限,而其他幾項我們在Joint motor塊討論。
Pulley Joint用來創(chuàng)建理想滑輪,滑輪連接兩個剛體,一個上去,一個便下來,根據(jù)你的最初設(shè)定來決定你的繩長。
length1 + length2 ==常數(shù)C
你可以應(yīng)用一個比例關(guān)系來模擬滑車裝置,這會導(dǎo)致一邊伸展得比另一邊快,同時約束力也是一邊大一邊小,你可以用它來創(chuàng)建杠桿。
length1 + ratio * length2 == 常數(shù)C
舉個例子,如果ratio(比例關(guān)系)是2,那么length1會變成length2的兩倍,當(dāng)作用在附加在剛體1上的繩上的力將會是作用在附加在剛體2上的力的一半。
struct b2PulleyJointDef : public b2JointDef
{
b2Vec2 groundPoint1;
b2Vec2 groundPoint2;
b2Vec2 anchorPoint1;
b2Vec2 anchorPoint2;
float32 maxLength1;
float32 maxLength2;
float32 ratio;
};
groundPoint1、groundPoint2是剛體1、2上面繩子的頂點,anchorPoint1、anchorPoint2是剛體與繩子連接的點,maxLength1、maxLength2為兩剛體的最大長度,ratio是比例系數(shù)。
九、 Gears
Gears內(nèi)容里面有關(guān)于Revolute Joint、Prismatic Joint、Gear Joint的應(yīng)用,前兩種已經(jīng)在前面討論過,現(xiàn)在我們先看Gear Joint。
Gear Joint直接翻譯為齒輪關(guān)節(jié),顧名思義就是用來處理齒輪類物體的相互關(guān)聯(lián)。
你在使用Gear Joint的時候必須先有一個附加了Prismatic Joint(此關(guān)節(jié)連接你的剛體和你的包容盒)的剛體和一個附加了Revolute Joint(此關(guān)節(jié)連接你的剛體和你的包容盒)的剛體咬合在一起。然后再用Gear Joint把這兩個剛體連接到一起。
和Pulley Joint一樣也有ratio值,在這里這個值可以是負數(shù),記住我們兩必要關(guān)節(jié)一個是Revolute Joint,另一個是Prismatic Joint,所以
coordinate1 + ratio * coordinate2 == 常數(shù)C
這個例子已經(jīng)應(yīng)用了ratio值,你可以自己動手調(diào)調(diào),來看看效果和作用。
Gear Joint依賴于兩個子關(guān)節(jié),一般是在兩個子關(guān)節(jié)之前刪除,甚至于是在所有有關(guān)剛體被刪除之前刪除。
結(jié)構(gòu)如下:
struct b2GearJointDef : public b2JointDef
{
b2Joint* joint1;
b2Joint* joint2;
float32 ratio;
};
繼承于關(guān)節(jié)定義, joint1、joint2表示兩個定義在剛體上面的關(guān)節(jié),ratio表示比例關(guān)系。
十、Joint(附加)
其實上面講了那么多種關(guān)節(jié),但是我們都還沒有真正討論過joint,joint這里翻譯為關(guān)節(jié),它的結(jié)構(gòu)為
b2JointType m_type;
b2Joint* m_prev;
b2Joint* m_next;
b2JointNode m_node1;
b2JointNode m_node2;
b2Body* m_body1;
b2Body* m_body2; bool m_islandFlag;
bool m_collideConnected; void* m_userData;
m_type是類型,分為 e_unknownJoint、e_revoluteJoint、 e_prismaticJoint、e_distanceJoint、e_pulleyJoint、e_mouseJoint、e_gearJoint。指針節(jié)點這些都應(yīng)用在數(shù)據(jù)結(jié)構(gòu)上,定義是兩個剛體對象:m_body1、m_body2,m_collideConnected表示連接剛體之間是否碰撞,還有一個函數(shù)指針型的m_userData來存儲自己的數(shù)據(jù)。m_islandFlag這個標(biāo)識暫時不用去管。
支持的方法有:
1、b2JointType GetType() const;
取得關(guān)節(jié)類型。
2、b2Body* GetBody1();
取得剛體1
3、b2Body* GetBody2();
取得剛體2
4、virtual b2Vec2 GetAnchor1() const = 0;
取得錨點1
5、virtual b2Vec2 GetAnchor2() const = 0;
取得錨點2
6、virtual b2Vec2 GetReactionForce(float32 invTimeStep) const = 0;
取得反作用力
7、virtual float32 GetReactionTorque(float32 invTimeStep) const = 0;
取得反作用扭矩
8、b2Joint* GetNext();
取得下一個關(guān)節(jié)
9、void* GetUserData();
取得用戶數(shù)據(jù)
10、static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator);
創(chuàng)建關(guān)節(jié)
11、static void Destroy(b2Joint* joint, b2BlockAllocator* allocator);
銷毀關(guān)節(jié)
12、其他方法(暫不介紹)
virtual void PrepareVelocitySolver() = 0;
virtual void SolveVelocityConstraints(const b2TimeStep* step) = 0;
virtual void PreparePositionSolver() {}
virtual bool SolvePositionConstraints() = 0;
以前所討論過的幾種關(guān)節(jié)都是繼承于b2Joint而來,下面列出了相關(guān)附加屬性和方法。不推薦直接使用相關(guān)成員變量來取值或賦值,要擅于利用相關(guān)功能函數(shù)來取值。
Gear Joint:
附加屬性(常用):
b2Body* m_ground1;
地面剛體1指針
b2Body* m_ground2;
地面剛體2指針
b2RevoluteJoint* m_revolute1;
RevoluteJoint指針1
b2PrismaticJoint* m_prismatic1;
PrismaticJoint指針1
b2RevoluteJoint* m_revolute2;
RevoluteJoint指針2
b2PrismaticJoint* m_prismatic2;
PrismaticJoint指針2
b2Vec2 m_groundAnchor1;
地面錨點1
b2Vec2 m_groundAnchor2;
地面錨點2
b2Vec2 m_localAnchor1;
當(dāng)前錨點1
b2Vec2 m_localAnchor2;
當(dāng)前錨點2
float32 m_ratio;
比例關(guān)系
float32 m_mass;
質(zhì)量
float32 m_impulse;
推力
附加方法:
1、float32 GetRatio() const;
取得比例關(guān)系
Revolute Joint:
附加屬性:
b2Vec2 m_localAnchor1;
b2Vec2 m_localAnchor2;
b2Vec2 m_ptpImpulse;
float32 m_motorImpulse;
float32 m_limitImpulse;
float32 m_limitPositionImpulse;
b2Mat22 m_ptpMass; // effective mass for point-to-point constraint.
float32 m_motorMass; // effective mass for motor/limit angular constraint.
float32 m_intialAngle;
float32 m_lowerAngle;
float32 m_upperAngle;
float32 m_maxMotorTorque;
float32 m_motorSpeed;
bool m_enableLimit;
bool m_enableMotor;
b2LimitState m_limitState;
附加方法:
1、float32 GetJointAngle() const;
取得關(guān)節(jié)角度
2、float32 GetJointSpeed() const;
取得關(guān)節(jié)速度
3、float32 GetMotorTorque(float32 invTimeStep) const;
取得發(fā)動扭矩
4、void SetMotorSpeed(float32 speed);
取得發(fā)動速度
5、void SetMotorTorque(float32 torque);
設(shè)置發(fā)動扭矩
Prismatic Joint:
附加方法:
1、float32 GetJointTranslation() const;
取得關(guān)節(jié)位移
2、float32 GetJointSpeed() const;
取得關(guān)節(jié)速度
3、float32 GetMotorForce(float32 invTimeStep) const;
取得發(fā)動應(yīng)力
4、 void SetMotorSpeed(float32 speed);
???? 設(shè)置發(fā)動速度
5、void SetMotorForce(float32 force);
設(shè)置發(fā)動速度
Revolute Joint:
附加方法:
1、float32 GetJointAngle () const;
取得關(guān)節(jié)角度
2、float32 GetJointSpeed() const;
取得關(guān)節(jié)速度
3、float32 GetMotorTorque (float32 invTimeStep) const;
取得發(fā)動扭矩
4、 void SetMotorSpeed(float32 speed);
???? 設(shè)置發(fā)動速度
5、void SetMotorTorque (float32 torque);
設(shè)置發(fā)動扭矩
十一、Joint motor(MotorsAndLimits、SliderCrank)
在開始之前,我們再來回顧一下Joint,我們前面討論過的情況來看,在幾種Joint中應(yīng)用到motor的只有Prismatic Joint和Revolute Joint。在使用motor時總有那么幾個常見量,float32 motorTorque或者float32 motorForce、 float32 motorSpeed、bool enableLimit、bool enableMotor。
motorTorque或motorForce表示現(xiàn)在的扭矩或應(yīng)力,Revolute Joint就是扭矩,因為他共用一個錨點,只能沿這錨點轉(zhuǎn)動,而Prismatic Joint支持基于軸的移動,所以他是應(yīng)力。
motorSpeed表示的是把這應(yīng)力或者扭距應(yīng)用到剛體上的數(shù)值增減程度。(僅當(dāng)參考,事實是你加大減少這個值會讓游戲數(shù)值瞬間變化量變多或變少,理解就行)
enableMotor是決定使用不使用Motor。
enableLimit決定上下限(角度或者長度)是否有用。
在SliderCrank這個例子中,先是定義了一個剛體,并用這個剛體和地面創(chuàng)建了一個Revolute Joint,這個Revolute Joint的motorTorque值設(shè)為一定值,讓這個剛體持續(xù)轉(zhuǎn)動,當(dāng)然你的速度越快,轉(zhuǎn)動就越快。這個剛體又用Revolute Joint連接了一個剛體,但這個Revolute Joint無效了motor,所以這個剛體只能靠其他剛體讓他移動。又用Revolute Joint連接了活塞剛體,同樣是無效了motor,之后創(chuàng)建了Prismatic Joint來連接你的活塞和地面,給定了應(yīng)力,所以這個應(yīng)力就使得上面掉下來的塊上升。
注意他的相關(guān)坐標(biāo)設(shè)置。
總結(jié)一下,這里真正提供動力的有兩個東西,一個是活塞,他是給下面掉下來的塊提供力量,另一個是最持續(xù)轉(zhuǎn)動的剛體盒子,他供給活塞以及他上面的塊能量。
MotorsAndLimits這個例子同樣很好理解,除了對motor的應(yīng)用外,還使用了enableLimit值,這個值是用來做什么,上面說過了,是用來決定在JointDef中定義的相關(guān)上下限是否起效。
試著改動相關(guān)數(shù)據(jù)對你理解更有效。
十二、CollisionProcessing
CollisionProcessing這個例子是有關(guān)于Contacts的使用。這個東西是Box2D用來在形狀間檢測碰撞的,有很多不同種類的Contacts,比如說負責(zé)圓和圓碰撞的,負責(zé)圓和多邊形碰撞的。這些其實你都沒有必要去了解它,你只要會應(yīng)用你最需要的就行了。
這里你最起碼需要了解的幾個概念:
Contact:就是用來管理碰撞的
contact manifold:這個東西就是碰撞時候產(chǎn)生的,是一個由碰撞點組成的矢量線段。
contact point:碰撞點
在例子CollisionProcessing中的Step部分,先從世界的Contacts表里取出你需要的連接,然后取得contact manifold的數(shù)量,如果有連接,然后再做出相應(yīng)的處理。
b2Contact的結(jié)構(gòu):
重要的屬性:
發(fā)生碰撞的兩個形狀
b2Shape* m_shape1;
b2Shape* m_shape2;
contact manifold的數(shù)量
int32 m_manifoldCount;
組合摩擦力和彈性系數(shù)
float32 m_friction;
float32 m_restitution;
重要的成員函數(shù):
取得相應(yīng)的contact manifold
virtual b2Manifold* GetManifolds() = 0;
取得contact manifold數(shù)
int32 GetManifoldCount() const
取得下一個Contact
b2Contact* GetNext();
取得這個Contact的兩個形狀
b2Shape* GetShape1();
b2Shape* GetShape2();
Box2D的例子不多,但基本上所有東西都涉及到了,接下來我想拿幾個實例來與大家討論。
總結(jié)
以上是生活随笔為你收集整理的(老文章)Box2D新手入门顺阶教程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【大学物理】期末复习原题+答案(超实用)
- 下一篇: 中国手持式红外测温仪市场深度研究分析报告