Link Source code HD không che: https://goo.gl/CR9Cks
Các bạn nên mở sources code vừa đọc vừa so sánh với tut này vì mình sẽ giải thích những gì trong sources code.
1. Entity
- Mình đã trình bày về Entity ở phần trước, ở đây Entity mình sẽ thêm hàm callback để xử lý va chạm, áp dụng kế thừa cho những object có khả năng va chạm.
virtual void OnCollision(Entity *impactor, CollisionReturn data, SideCollisions side);
- Tham số truyền vào là Entity va chạm với nó, thông tin va chạm (vùng va chạm, có va chạm hay không), phía va chạm.
- CollisionReturn
struct CollisionReturn
{
bool IsCollided;
RECT RegionCollision;
};
Biến bool nếu = true là có va chạm, false là không va chạm.
RECT là phần giao nhau của 2 entity khi va chạm.
- SideCollisions
enum SideCollisions
{
Left, //0
Right, //1
Top, //2
Bottom, //3
TopLeft, //4
TopRight, //5
BottomLeft, //6
BottomRight, //7
NotKnow
};
Phía va chạm tương ứng có 8 trường hợp.2. Class GameCollision
- Các hàm static hỗ trợ trong việc xác định va chạm. Mình có chú thích rõ trong source code nên các bạn vào đó xem thêm nhé.
- Trong này mình sẽ giải thích hàm lấy phía va chạm:
static Entity::SideCollisions getSideCollision(Entity *e1, Entity::CollisionReturn data)
Trên ảnh là ý tưởng của mình về việc kiểm tra phía va chạm của vật thể, mình cũng có chú thích khá rõ trong code.
3. QuadTree
- Về lý thuyết Quadtree thì có rất nhiều trên mạng và tài liệu của Clb (mình post bài đầu tiên) có đính kèm theo và nói rất rõ về lý thuyết của Quadtree nên mình sẽ không trình bày lý thuyết Quadtree ở đây.
- Quadtree sử dụng rất nhiều đệ quy để quy xuất dạng cây nên các bạn phải nắm vững và hiểu được đệ quy.
- Thuộc tính:
- QuadTree **Nodes: mảng 1 chiều chứa con trỏ Quadtree, cứ mỗi con trỏ lại có 4 node con tương ứng 4 vùng
- std::vector<Entity*> mListEntity: chứa danh sách các Entity nằm trong Node này.
- int mLevel: mức phân cấp hiện tại của Quadtree
- RECT Bound: biên của Quadtree là 1 hình chữ nhật.
- Hàm
- int getIndex(RECT body): lấy index của một entity, tương ứng hình ở trên index từ 0 đến 3 là nằm gọn trong 1 node còn bằng -1 là nằm trên ít nhất 2 node. Hàm này mình kiểm tra xem body nếu mà nó nằm gọn trong 1 node (index 0 -> 3) thì mình sẽ kiểm tra tiếp đến khi nó nằm trên ít nhất 2 node con thì sẽ thêm nó vào list của node cha.
- void split(): tiếp tục phân node cha thành 4 node con.
- void getAllEntities(std::vector<Entity*> &entitiesOut): lấy tất cả các Entity của node đó và node con của nó.
- void getEntitiesCollideAble(std::vector<Entity*> &entitiesOut, Entity *entity): lấy danh sách những Entity có khả năng xảy ra va chạm với Entity truyền vào. Mình sẽ kiểm tra index của Entity từ đó sẽ chọn những Node có index tương tự vì Entity nằm gọn trong node đó thì mới có khả năng va chạm với các Entity của node đó.
4. Check Collision
- Để check collision thì mình sẽ sử dụng Quadtree để giảm tối đa số lần phải check collision giữa các object.
- mMap->GetQuadTree()->getEntitiesCollideAble(listCollision, mPlayer): hàm này sẽ giúp mình lấy danh sách những Entity có khả năng va chạm với mPlayer.
- Sau đó mình sẽ chạy 1 vòng for để kiểm tra hết những object này có va chạm với Player hay không.
Entity::CollisionReturn r = GameCollision::RecteAndRect(mPlayer->GetBound(),
listCollision.at(i)->GetBound());
- Tiếp đến mình có thông tin về việc Collision nếu va chạm với Player mình sẽ gửi thời hàm OnCollision của Player để Player gửi đến các State của nó và xử lý.
5. Hàm xử lý Collision
- Trong class Entity mình có thêm hàm xử lý Collision, hàm này được gọi khi có sự va chạm của 2 Entity với nhau, và mình cũng đã giải thích ở phía đầu.
- Mình bổ sung thêm trong class State của Player vì mỗi State sẽ có cách xử lý va chạm khác nhau, nên khi gọi hàm OnCollision của Player mình sẽ gọi hàm OnCollision của State hiện tại và xử lý trong class của State đó và không phải State nào cũng xử lý và chạm và cũng Update nên tùy thuộc State mà mình có override 2 hàm đó hay không.
- Ví dụ trong State Running
case Entity::Left:
{
//va cham phia ben trai player
if (this->mPlayerData->player->getMoveDirection() == Player::MoveToLeft)
{
this->mPlayerData->player->allowMoveLeft = false;
this->mPlayerData->player->AddPosition (data.RegionCollision.right - data.RegionCollision.left, 0);
this->mPlayerData->player->SetState(new PlayerStandingState(this->mPlayerData));
}
return;
}
Mình sẽ kiểm tra nếu Player đang chạy trang bên trái và va chạm bên trái thì mới xử lý cho Player đứng lại và chuyển sang StandingState. Phần Add Position là cộng trừ Position đi 1 đoạn, nếu va chạm bên trái sẽ đẩy Player ra để cho Player không đi chuyên qua Object.
Tổng kết
- Collision luôn và việc phức tạp trong game, nhất là những game yêu cầu về vật lý hay platform, có rất nhiều cách khách để xử lý collision cho hoản hảo hơn, tuy nhiên mình chỉ nghĩ được cách này là phú hợp các bạn có thể lên mạng tìm thêm khá nhiều cách khác để áp dụng.
- Các bạn có thể vào các State của Player để xem thêm phần xử lý Collision của từng state.
- Với viên gạch nếu bạn muốn nó vỡ thì phải tạo thêm State hoặc xử lý trực tiếp trong hàm OnCollision của chính nó.
0 Comment:
Post a Comment