2009-08-31 44 views
3

我在一週前有這個工作,但後來我最終打破了它。我無法再讓它工作。我有一些2D精靈,他們只是矩形。不涉及輪換。我不想找到一種方法來檢測它們之間的衝突,我有這個,並且有數以千計的文章。我找不到任何有關在看到碰撞時應該怎麼做的資源。我只想讓精靈不被允許重疊。沒有彈跳或任何東西。他們停下來。具體來說,現在我只有一名球員和一些他遇到的關卡。邊界框碰撞處理 - 沒有檢測

這聽起來很簡單,但事實並非如此。它必須是非常精確或奇怪的事情發生。我一直試圖用奇怪的混合結果整天解決這個問題。有時我的玩家被困在地板上,無法左右移動。當我解決這個問題時,他可以左右走路。

所以我的當前設置認爲是這樣的:嘗試將他想要去的球員。然後問地圖他的瓷磚是否與任何東西碰撞。如果是這樣,那麼地圖會說明在四個方向的每一個方向上有多少像素重疊。現在棘手的部分是玩家應該如何對這些數字作出反應。當他在地面上時,與地板重疊1像素,以便他知道他在地面上(否則他在落地和落地之間振動,因爲沒有重疊,他認爲他下面沒有任何東西)。這一個像素重疊意味着左右邊緣也嵌入在地板中,因此他不能移動。

是否有讓一切整理出來,用一個邊框玩家的好方法?爲他的四邊各設一個單獨的邊界框會更好嗎?

回答

0

我想我已經明白了。主要由stonemetal的答案啓發。我最近的缺點是玩家能夠「掛」到牆上,因爲他的邊界框會在牆上留下一個像素,然後它會落在下面磚的邊緣,阻止他。

我通過分裂x和y的運動來解決所有問題。由於重力是一筆交易,我把它作爲優先事項。看看你是否被允許水平移動,然後取消那個動作,如果你不能。然後嘗試垂直,如果不能,則取消。這種分離確保了任何一方都不會從另一方獲得錯誤的信息(比如認爲自己在地上,是Y的事情,因爲你靠在牆上,這是一件X的事)。多謝你們!

2

一種替代具有與地面的重疊是設置他的開始位置至略高於地面;然後總是調用下降的例程。

如果他的下一個下降部分會使他與地面磚重疊,請將化身'在地面上'的字段設置爲true(假設您需要跟蹤該字段用於跳躍目的),並將y化身的位置剛好在地面上。雖然他會不斷「摔倒」,但它會在視覺上感覺不到。

另一種方法是你所提到的,在那裏你有4個邊框;抓住這一點,你可能不希望4個角落成爲任何一個盒子的成員;所以,如果頭像圖像是16x16px,則將其視爲四個邊上的每個邊上的4個1x16px邊界框。這會帶來它自己的數學頭痛,但它會起作用。

至於處理衝突和跳躍;我會想象的一件事情將會是:將運動分解爲兩個離散的運動部分,一個在x軸上移動,另一個在y軸上移動。如果x軸上的移動被牆堵塞,則將x座標設置爲有效的其他位置(因此,x應該是導致擁抱牆/平臺的值)。與y軸類似。此時,您還可以更改處理速度的方式;如果合適,將x/y速度分量設置爲0。根據您所尋找的遊戲感覺,這可能並不理想。

0

這聽起來像你正試圖推出自己的東西,但我一直在原型的一些東西與花栗鼠動態,一個可愛的小2D物理庫,它是開源的,所以你可以看看,看看他們是如何做到這一點,如果你想要想法。

http://code.google.com/p/chipmunk-physics/

+0

如果你打算提到Chipmunk,你可能還會提到Box2D,但我認爲要麼是他想要做的事情過度。 – mpen 2009-08-31 02:05:41

0

當我解決這個問題,他可以通過步行塊向左或向右。

在這個階段,你是否確定你正在從碰撞檢測中獲得正確的結果?

然後問地圖他的瓷磚是否與任何東西碰撞。如果是這樣,那麼地圖會說明在四個方向的每一個方向上有多少像素重疊。

如果在旅行方向上有任何x重疊,則可以使用此數據來禁止x運動。就個人而言,如果xoverlap爲零或者符號與運動方向相反,我會在右側返回一個正確的重疊並在左側返回負數重疊,然後只允許x運動。那麼對於Y而言,除了檢查1而不是0之外,你需要做的只是相同的事情。

0

這是一個簡單的箱子碰撞測試。這顯然很簡單,等到你做多邊形碰撞測試!

//! (collision detection) 
inline BOOL Sprite::TestCollision(Sprite* pTestSprite) 
{ 
    //! Get the collision box. 
    RECT& rcTest = pTestSprite->GetCollision(); 

    //! box collision check. 
    return m_rcCollision.left <= rcTest.right && rcTest.left <= m_rcCollision.right && 
     m_rcCollision.top <= rcTest.bottom && rcTest.top <= m_rcCollision.bottom; 
} 

現在就怎樣做才能阻止精靈或反彈或什麼的,它會像這樣: (注:這種情況下,檢查對邊界衝突,但基本上是同樣的事情與執行其他物體)。如果只是軸線對齊的方塊碰撞,您所要做的就是將碰撞對象與其他碰撞對象的水平或垂直邊緣對齊。如果對象從左側碰撞,請對齊另一個對象的左側邊緣。簡單。如果您想要反彈或停止,請相應更改速度。

在本例中,我使用更新後的位置製作測試變量,然後執行碰撞測試,然後執行下面的例程或者在沒有碰撞的情況下設置新的位置。 所以我們實際上在碰撞發生之前修復它。

// Update the position 
POINT ptNewPosition, ptSpriteSize, ptBoundsSize; 
ptNewPosition.x = m_rcPosition.left + m_ptVelocity.x; 
ptNewPosition.y = m_rcPosition.top + m_ptVelocity.y; 
ptSpriteSize.x = m_rcPosition.right - m_rcPosition.left; 
ptSpriteSize.y = m_rcPosition.bottom - m_rcPosition.top; 
ptBoundsSize.x = m_rcBounds.right - m_rcBounds.left; 
ptBoundsSize.y = m_rcBounds.bottom - m_rcBounds.top; 

// Check the bounds 
// Wrap? 
if (m_baBoundsAction == BA_WRAP) 
{ 
    if ((ptNewPosition.x + ptSpriteSize.x) < m_rcBounds.left) 
    ptNewPosition.x = m_rcBounds.right; 
    else if (ptNewPosition.x > m_rcBounds.right) 
    ptNewPosition.x = m_rcBounds.left - ptSpriteSize.x; 
    if ((ptNewPosition.y + ptSpriteSize.y) < m_rcBounds.top) 
    ptNewPosition.y = m_rcBounds.bottom; 
    else if (ptNewPosition.y > m_rcBounds.bottom) 
    ptNewPosition.y = m_rcBounds.top - ptSpriteSize.y; 
} 
// Bounce? 
else if (m_baBoundsAction == BA_BOUNCE) 
{ 
    BOOL bBounce = FALSE; 
    POINT ptNewVelocity = m_ptVelocity; 
    if (ptNewPosition.x < m_rcBounds.left) 
    { 
    bBounce = TRUE; 
    ptNewPosition.x = m_rcBounds.left; 
    ptNewVelocity.x = -ptNewVelocity.x; 
    } 
    else if ((ptNewPosition.x + ptSpriteSize.x) > m_rcBounds.right) 
    { 
    bBounce = TRUE; 
    ptNewPosition.x = m_rcBounds.right - ptSpriteSize.x; 
    ptNewVelocity.x = -ptNewVelocity.x; 
    } 
    if (ptNewPosition.y < m_rcBounds.top) 
    { 
    bBounce = TRUE; 
    ptNewPosition.y = m_rcBounds.top; 
    ptNewVelocity.y = -ptNewVelocity.y; 
    } 
    else if ((ptNewPosition.y + ptSpriteSize.y) > m_rcBounds.bottom) 
    { 
    bBounce = TRUE; 
    ptNewPosition.y = m_rcBounds.bottom - ptSpriteSize.y; 
    ptNewVelocity.y = -ptNewVelocity.y; 
    } 
    if (bBounce) 
    SetVelocity(ptNewVelocity); 
} 
// v0.1.1 (collision detection) 
// Die? 
else if (m_baBoundsAction == BA_DIE) 
{ 
    if ((ptNewPosition.x + ptSpriteSize.x) < m_rcBounds.left || ptNewPosition.x > m_rcBounds.right 
    || (ptNewPosition.y + ptSpriteSize.y) < m_rcBounds.top || ptNewPosition.y > m_rcBounds.bottom) 
    return SA_KILL; 
} 
// v0.1.1 ---------------------- 
// Stop (default) 
else 
{ 
    if (ptNewPosition.x < m_rcBounds.left || ptNewPosition.x > (m_rcBounds.right - ptSpriteSize.x)) 
    { 
    ptNewPosition.x = max(m_rcBounds.left, min(ptNewPosition.x, m_rcBounds.right - ptSpriteSize.x)); 
    SetVelocity(0, 0); 
    } 
    if (ptNewPosition.y < m_rcBounds.top || ptNewPosition.y > (m_rcBounds.bottom - ptSpriteSize.y)) 
    { 
    ptNewPosition.y = max(m_rcBounds.top, min(ptNewPosition.y, m_rcBounds.bottom - ptSpriteSize.y)); 
    SetVelocity(0, 0); 
    } 
}