上篇node
碰撞dom
你是否經歷過車禍?是否跟什麼物體相撞過?就像車同樣,物理剛體對象能夠互相接觸。當它們接觸的時候,就發生了碰撞。當碰撞發生時,它能夠被徹底忽略,也能夠引發一系列事件。ide
碰撞篩選函數
碰撞篩選容許你啓用或者阻止形狀之間碰撞的發生。物理引擎支持使用類型、組位掩碼來篩選碰撞。post
Cocos2d-x中支持32種碰撞類型。對於每一個形狀均可以指定其所屬的類型。還能夠指定有哪些類型能夠與這個形狀進行碰撞。這些是經過掩碼來完成的。例如this
autospa
sprite1 = addSpriteAtPosition(Vec2(s_centre.x - 150,s_centre.y));orm
sprite1->getPhysicsBody()->setCategoryBitmask(0x02);// 0010對象
sprite1->getPhysicsBody()->setCollisionBitmask(0x01); // 0001blog
sprite1
= addSpriteAtPosition(Vec2(s_centre.x - 150,s_centre.y + 100));
sprite1->getPhysicsBody()->setCategoryBitmask(0x02);// 0010
sprite1->getPhysicsBody()->setCollisionBitmask(0x01); //
0001
auto
sprite2 = addSpriteAtPosition(Vec2(s_centre.x + 150,s_centre.y),1);
sprite2->getPhysicsBody()->setCategoryBitmask(0x01);// 0001
sprite2->getPhysicsBody()->setCollisionBitmask(0x02); // 0010
auto
sprite3 = addSpriteAtPosition(Vec2(s_centre.x + 150,s_centre.y + 100),2);
sprite3->getPhysicsBody()->setCategoryBitmask(0x03);// 0011
sprite3->getPhysicsBody()->setCollisionBitmask(0x03); // 0011
能夠經過檢測、類型比較和碰撞掩碼,來肯定碰撞的發生:
if((shapeA->getCategoryBitmask() & shapeB->getCollisionBitmask()) == 0 || (shapeB->getCategoryBitmask() & shapeA->getCollisionBitmask()) == 0)
{
//
shapes can't collide
ret
= false;
}
碰撞組容許你指定一個綜合組的索引。你可讓具備同一組之索引的形狀全都一直碰撞(正索引)或者永不碰撞(負索引或零索引)。組指數不一樣的形狀間進行的碰撞,能夠根據類型和掩碼來進行篩選。換句話說,組篩選比類型篩選的優先級更高。
鏈接/關節
還記得以前的術語嗎?關節是一種把接觸點聯結在一塊兒的方式。沒錯,你能夠把它類比爲本身身體上的關節。每個關節都有一個從PhysicsJoint對象得到的定義。在兩個不一樣的剛體之間,全部的關節都是聯結在一塊兒的。剛體能夠是靜態的。你可使用joint->setCollisionEnable(false)來避免相關聯的剛體相互碰撞。不少關節的定義須要你提供一些幾何數據。不少狀況下,關節由錨點來定義。其他的關節定義數據取決於關節的類型。
PhysicsJointFixed:固定關節在一個特定的點上,將兩個剛體結合在了一塊兒。若是要建立一些之後會斷裂的複雜形狀,固定關節是很是有用的。
PhysicsJointLimit:一種限制關節,它利用了兩個剛體間最大距離,就如同兩個剛體被繩子連在一塊兒同樣。
PhysicsJointPin:針式關節可讓兩個剛體獨立地圍繞錨點進行旋轉,就如同它們被釘在一塊兒了同樣。
PhysicsJointDistance:設定兩個剛體間的固定距離。
PhysicsJointSpring:用彈簧來聯結兩個物理剛體
PhysicsJointGroove:將一個剛體連到線上,另外一個連到點上。
PhysicsJointRotarySpring:與彈簧關節類似,可是增長了自旋
PhysicsJointRotaryLimit:與限制關節類似,可是增長了自旋
PhysicsJointRatchet:與套筒扳手的工做相似
PhysicsJointGear:使一對剛體的角速度比率保持是一個常數。
PhysicsJointMotor:使一對剛體的相對角速度保持是一個常數。
碰撞檢測
碰撞(Contacts)是一種由物理引擎建立的用以管理兩個形狀間碰撞的對象。Contact對象會自動建立,而非由用戶建立。這裏有幾個與之相關聯的術語。
contact point:contact point是兩個形狀相接觸的那個點。
contact normal:contact normal指的是從一個形狀指向另外一個形狀的單位向量。
你能夠從一個碰撞中獲取PhysicsShape。從中,你能夠獲取剛體。
boolonContactBegin(PhysicsContact& contact)
{
auto
bodyA = contact.getShapeA()->getBody();
auto
bodyB = contact.getShapeB()->getBody();
returntrue;
}
你能夠經過使用contact listener來訪問碰撞。contact listener支持多種事件:begin,pre-solve,post-solve,以及separate。
begin:在這一步驟中,兩個形狀剛剛開始接觸。從回調函數中返回true,可使碰撞正常發生,若返回false,則物理引擎會將碰撞整個忽略掉。若是返回false值,preSolve()和postSolve()回調函數會被禁止運行,不過當兩個形狀中止重疊時,你仍然能夠收到一個單獨的事件。
pre-solve:在這一步驟中,兩個形狀接觸在一塊兒。若是在回調函數中返回false值,則物理引擎會忽略掉這次碰撞;若返回true,碰撞則會正常進行。此外,你可使用setRestitution()和setSurfaceVelocity()函數來忽略碰撞值,這樣就能夠提供自定義的恢復係數、摩擦係數和表面速度值。
post-solve:兩個形狀相接觸,而它們之間的碰撞已被處理。
separate:在這一步驟中,兩個形狀剛剛中止接觸。
也可使用EventListenerPhysicsContactWithBodies,EventListenerPhysicsContactWithShapes,EventListenerPhysicsContactWithGroup來監聽你感興趣的剛體、形狀和組的一些事件。除此以外,你還須要設定與物理接觸相關的掩碼,由於就算你建立了相關的EventListener,碰撞事件仍是不會在默認狀態下被接收。
例如:
boolinit()
{
//create
a static PhysicsBody
auto
sprite = addSpriteAtPosition(s_centre,1);
sprite->setTag(10);
sprite->getPhysicsBody()->setContactTestBitmask(0xFFFFFFFF);
sprite->getPhysicsBody()->setDynamic(false);
//adds
contact event listener
auto
contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin
= CC_CALLBACK_1(PhysicsDemoCollisionProcessing::onContactBegin, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener,this);
schedule(CC_SCHEDULE_SELECTOR(PhysicsDemoCollisionProcessing::tick),
0.3f);
returntrue;
returnfalse;
}
voidtick(floatdt)
{
auto
sprite1 = addSpriteAtPosition(Vec2(s_centre.x + cocos2d::random(-300,300),
s_centre.y
+ cocos2d::random(-300,300)));
auto
physicsBody = sprite1->getPhysicsBody();
physicsBody->setVelocity(Vec2(cocos2d::random(-500,500),cocos2d::random(-500,500)));
physicsBody->setContactTestBitmask(0xFFFFFFFF);
}
boolonContactBegin(PhysicsContact& contact)
{
auto
nodeA = contact.getShapeA()->getBody()->getNode();
auto
nodeB = contact.getShapeB()->getBody()->getNode();
if(nodeA && nodeB)
{
if(nodeA->getTag() == 10)
{
nodeB->removeFromParentAndCleanup(true);
}
elseif (nodeB->getTag() == 10)
{
nodeA->removeFromParentAndCleanup(true);
}
}
//bodies
can collide
returntrue;
}
查詢
你有沒有過站在一個地方往四周看的經歷?你能看到離你近的東西,也能看到離你遠的東西。你能判斷出它們離你有多遠。物理引擎提供相似的空間查詢功能。PhysicsWorld對象目前支持的查詢包括點查詢、射線查詢和矩形查詢。
點查詢
當你碰到什麼東西,好比說你的桌子的時候,你能夠將此認爲是一個點查詢的例子。這使你可以檢查在一個點周圍的必定距離內是否有形狀存在。對於鼠標拾取和簡單的傳感器來講,點查詢是很是有用的。你還能夠找到在一個形狀上離某定點最近的點,或者找到離某個點最近的形狀。
射線查詢
當你四處看的時候,在你視線內的某些物體確定會引發你的注意。像這樣的時候,你基本上就算是執行了一次射線查詢。你不停地掃描,直到有什麼有趣的東西讓你停下來。你可使用對某個形狀使用射線查詢來獲取第一個交叉點。例如:
void tick(float dt)
{
Vec2
d(300 * cosf(_angle), 300 * sinf(_angle));
Vec2
point2 = s_centre + d;
if(_drawNode)
{
removeChild(_drawNode);
}
_drawNode
= DrawNode::create();
Vec2
points[5];
intnum = 0;
auto
func = [&points, &num](PhysicsWorld& world,
constPhysicsRayCastInfo& info, void*
data)->bool
{
if(num < 5)
{
points[num++]
= info.contact;
}
returntrue;
};
s_currScene->getPhysicsWorld()->rayCast(func,
s_centre, point2, nullptr);
_drawNode->drawSegment(s_centre,
point2, 1, Color4F::RED);
for(inti = 0; i < num; ++i)
{
_drawNode->drawDot(points[i],
3, Color4F(1.0f, 1.0f, 1.0f, 1.0f));
}
addChild(_drawNode);
_angle
+= 1.5f * (float)M_PI
/ 180.0f;
}
矩形查詢
矩形查詢提供了一個大體檢查區域中存在的形狀的一種快捷方式。它很是容易實現:
auto
func = [](PhysicsWorld& world, PhysicsShape& shape, void*
userData)->bool
{
//Return
true from the callback to continue rect queries
returntrue;
}
scene->getPhysicsWorld()->queryRect(func,
Rect(0,0,200,200), nullptr);
A few examples of using a Rect query while doing a logo smash:
這裏是在製做撞擊logo時使用矩形查詢的幾個例子:
禁用物理引擎
使用內置的物理引擎是個不錯的想法。它又穩定又強大。然而,有時候你會想要使用一些其餘的物理引擎。這時候你只須要在base/ccConfig.h中把CC_USE_PHYSICS禁用就行了。