在cocos2dx中進行矩形的碰撞檢測時需要對旋轉過的矩形做碰撞檢查,由於游戲沒有使用Box2D等物理引擎,所以采用了OBB(Oriented bounding box)方向包圍盒算法,這個算法是基於SAT(Separating Axis Theorem)分離軸定律的。
分離軸定律:兩個凸多邊形物體,如果我們能找到一個軸,使得兩個在物體在該軸上的投影互不重疊,則這兩個物體之間沒有碰撞發生,該軸為Separating Axis。也就是說兩個多邊形在所有軸上的投影都發生重疊,則判定為碰撞;否則,沒有發生碰撞。
現在,我們來考慮一下矩形,矩形有4條邊,那么就有4條軸,由於矩形的對邊是平行的,所以有兩條軸是重復的,我們僅需要檢查相鄰的兩個軸,那么兩個矩形就需要檢查4個軸。
檢查投影有兩種方法:第一種,把每個矩形的4個頂點投影到一個軸上,這樣算出4個頂點最長的連線距離,以后同樣對待第二個矩形,最后判斷2個矩形投影距離是否重疊。第二種,把2個矩形的半徑距離投影到軸上,以后把2個矩形的中心點連線投影到軸上,以后判斷2個矩形的中心連線投影,和2個矩形的半徑投影之和的大小。
由於已經有很多文章來介紹OBB的原理,所以這里並不過多解釋,我只將我實現的源碼列出來僅供大家參考,代碼已經經過測試,如下:
#ifndef _OBBRECT_H_ #define _OBBRECT_H_ #include <math.h> class OBBRect { public: OBBRect(float x, float y, float width, float height, float rotation = 0.0f) : _x(x), _y(y), _width(width), _height(height), _rotation(rotation) { resetVector(); } bool intersects(OBBRect& other) { float distanceVector[2] = { other._x - _x, other._y - _y }; for (int i = 0; i < 2; ++i) { if (getProjectionRadius(_vectors[i]) + other.getProjectionRadius(_vectors[i]) <= dot(distanceVector, _vectors[i])) { return false; } if (getProjectionRadius(other._vectors[i]) + other.getProjectionRadius(other._vectors[i]) <= dot(distanceVector, other._vectors[i])) { return false; } } return true; } private: void resetVector() { _vectors[0][0] = cos(_rotation); _vectors[0][1] = sin(_rotation); _vectors[1][0] = -_vectors[0][1]; _vectors[1][1] = _vectors[0][0]; } float dot(float a[2], float b[2]) { return abs(a[0] * b[0] + a[1] * b[1]); } float getProjectionRadius(float vector[2]) { return (_width * dot(_vectors[0], vector) / 2 + _height * dot(_vectors[1], vector) / 2); } float _x; float _y; float _width; float _height; float _rotation; float _vectors[2][2]; }; #endif // _OBBRECT_H_