Nếu đây là lần đầu tiên bạn đặt câu hỏi này, tôi khuyên bạn nên đọc phần cập nhật trước bên dưới trước, sau đó là phần này. Đây là một tổng hợp của vấn đề, mặc dù:
Về cơ bản, tôi có một công cụ phát hiện và giải quyết va chạm với hệ thống phân vùng không gian lưới nơi các nhóm va chạm và va chạm có vấn đề. Một cơ thể tại một thời điểm phải di chuyển, sau đó phát hiện va chạm, sau đó giải quyết va chạm. Nếu tôi di chuyển tất cả các cơ thể cùng một lúc, sau đó tạo ra các cặp va chạm có thể xảy ra, thì rõ ràng là nhanh hơn, nhưng độ phân giải bị phá vỡ vì trật tự va chạm không được tôn trọng. Nếu tôi di chuyển một cơ thể một lần, tôi buộc phải đưa các cơ thể để kiểm tra va chạm và nó trở thành một vấn đề ^ 2. Đặt các nhóm trong hỗn hợp, và bạn có thể tưởng tượng tại sao nó trở nên rất chậm rất nhanh với rất nhiều cơ thể.
Cập nhật: Tôi đã làm việc rất chăm chỉ về vấn đề này, nhưng không thể quản lý để tối ưu hóa mọi thứ.
Tôi cũng phát hiện ra một vấn đề lớn : động cơ của tôi phụ thuộc vào trật tự va chạm.
Tôi đã thử thực hiện một thế hệ cặp va chạm độc đáo , chắc chắn tăng tốc mọi thứ lên rất nhiều, nhưng đã phá vỡ trật tự va chạm .
Hãy để tôi giải thích:
trong thiết kế ban đầu của tôi (không tạo cặp), điều này xảy ra:
- một cơ thể di chuyển
- sau khi nó di chuyển, nó làm mới các tế bào của nó và khiến các cơ thể nó va chạm với nhau
- Nếu nó đè lên một cơ thể, nó cần phải giải quyết, giải quyết va chạm
điều này có nghĩa là nếu một cơ thể di chuyển và va vào tường (hoặc bất kỳ cơ thể nào khác), chỉ có cơ thể đã di chuyển sẽ giải quyết va chạm của nó và cơ thể khác sẽ không bị ảnh hưởng.
Đây là hành vi tôi mong muốn .
Tôi hiểu rằng nó không phổ biến đối với các động cơ vật lý, nhưng nó có rất nhiều lợi thế cho các trò chơi theo phong cách retro .
trong thiết kế lưới thông thường (tạo các cặp duy nhất), điều này xảy ra:
- tất cả các cơ thể di chuyển
- sau khi tất cả các cơ thể đã di chuyển, làm mới tất cả các tế bào
- tạo các cặp va chạm độc đáo
- cho mỗi cặp, xử lý phát hiện va chạm và giải quyết
trong trường hợp này, một động thái đồng thời có thể dẫn đến hai cơ thể chồng chéo lên nhau và chúng sẽ giải quyết cùng một lúc - điều này thực sự khiến các cơ thể "đẩy nhau xung quanh" và phá vỡ sự ổn định va chạm với nhiều cơ thể
Hành vi này là phổ biến cho các động cơ vật lý, nhưng nó không được chấp nhận trong trường hợp của tôi .
Tôi cũng tìm thấy một vấn đề khác, đó là vấn đề chính (ngay cả khi nó không có khả năng xảy ra trong tình huống thực tế):
- xem xét các cơ quan của nhóm A, B và W
- A va chạm và giải quyết chống lại W và A
- B va chạm và giải quyết chống lại W và B
- A không làm gì chống lại B
- B không làm gì chống lại A
có thể xảy ra trường hợp rất nhiều cơ thể A và cơ thể B chiếm cùng một tế bào - trong trường hợp đó, có rất nhiều sự lặp lại không cần thiết giữa các cơ thể không được phản ứng với nhau (hoặc chỉ phát hiện va chạm nhưng không giải quyết được chúng) .
Đối với 100 cơ thể chiếm cùng một ô, đó là 100 ^ 100 lần lặp! Điều này xảy ra vì các cặp duy nhất không được tạo - nhưng tôi không thể tạo các cặp duy nhất , nếu không tôi sẽ có một hành vi mà tôi không mong muốn.
Có cách nào để tối ưu hóa loại động cơ va chạm này không?
Đây là những hướng dẫn phải được tôn trọng:
Thứ tự va chạm là vô cùng quan trọng!
- Các cơ quan phải di chuyển từng cái một , sau đó kiểm tra va chạm từng cái một và giải quyết sau khi di chuyển từng cái một .
Các cơ quan phải có 3 bitcoin nhóm
- Nhóm : nhóm cơ thể thuộc về
- GroupsToCheck : các nhóm cơ thể phải phát hiện va chạm chống lại
- GroupsNoResolve : nhóm cơ thể phải không được giải quyết va chạm chống lại
- Có thể có những tình huống tôi chỉ muốn phát hiện va chạm nhưng không được giải quyết
Cập nhật trước:
Lời nói đầu : Tôi biết rằng tối ưu hóa nút cổ chai này không phải là điều cần thiết - động cơ đã rất nhanh. Tôi, tuy nhiên, vì mục đích vui vẻ và giáo dục, rất thích tìm cách làm cho động cơ nhanh hơn nữa.
Tôi đang tạo ra một công cụ phát hiện / phản ứng va chạm C ++ 2D đa năng, chú trọng vào tính linh hoạt và tốc độ.
Đây là một sơ đồ rất cơ bản về kiến trúc của nó:
Về cơ bản, lớp chính là World
, sở hữu (quản lý bộ nhớ) của a ResolverBase*
, a SpatialBase*
và a vector<Body*>
.
SpatialBase
là một lớp ảo thuần túy liên quan đến phát hiện va chạm pha rộng.
ResolverBase
là một lớp ảo thuần túy liên quan đến độ phân giải va chạm.
Các cơ quan giao tiếp World::SpatialBase*
với SpatialInfo
các đối tượng, thuộc sở hữu của chính các cơ quan.
Hiện tại có một lớp không gian : Grid : SpatialBase
, là lưới 2D cố định cơ bản. Nó có lớp thông tin riêng,GridInfo : SpatialInfo
.
Đây là cách kiến trúc của nó trông:
Các Grid
lớp học sở hữu một mảng 2D của Cell*
. Các Cell
lớp có chứa một bộ sưu tập các (không thuộc sở hữu) Body*
: a vector<Body*>
, trong đó có tất cả các cơ quan có trong tế bào.
GridInfo
các đối tượng cũng chứa các con trỏ không sở hữu đến các tế bào mà cơ thể đang ở.
Như tôi đã nói trước đây, động cơ dựa trên các nhóm.
Body::getGroups()
trả về mộtstd::bitset
trong tất cả các nhóm mà cơ thể là một phần của.Body::getGroupsToCheck()
trả về mộtstd::bitset
trong tất cả các nhóm mà cơ thể phải kiểm tra va chạm.
Các cơ quan có thể chiếm nhiều hơn một tế bào. GridInfo luôn lưu trữ các con trỏ không sở hữu vào các ô bị chiếm.
Sau khi một cơ thể di chuyển, phát hiện va chạm xảy ra. Tôi giả sử rằng tất cả các cơ quan là hộp giới hạn liên kết trục.
Cách phát hiện va chạm pha rộng:
Phần 1: cập nhật thông tin không gian
Đối với mỗi Body
body
:
- Các ô chiếm dụng trên cùng bên trái và các ô chiếm dụng dưới cùng bên phải được tính toán.
- Nếu chúng khác với các ô trước đó,
body.gridInfo.cells
sẽ bị xóa và chứa đầy tất cả các ô mà cơ thể chiếm giữ (vòng lặp 2D cho từ ô trên cùng bên trái đến ô dưới cùng bên phải).
body
bây giờ được đảm bảo để biết những gì nó chiếm tế bào.
Phần 2: kiểm tra va chạm thực tế
Đối với mỗi Body
body
:
body.gridInfo.handleCollisions
được gọi là:
void GridInfo::handleCollisions(float mFrameTime)
{
static int paint{-1};
++paint;
for(const auto& c : cells)
for(const auto& b : c->getBodies())
{
if(b->paint == paint) continue;
base.handleCollision(mFrameTime, b);
b->paint = paint;
}
}
void Body::handleCollision(float mFrameTime, Body* mBody)
{
if(mBody == this || !mustCheck(*mBody) || !shape.isOverlapping(mBody->getShape())) return;
auto intersection(getMinIntersection(shape, mBody->getShape()));
onDetection({*mBody, mFrameTime, mBody->getUserData(), intersection});
mBody->onDetection({*this, mFrameTime, userData, -intersection});
if(!resolve || mustIgnoreResolution(*mBody)) return;
bodiesToResolve.push_back(mBody);
}
Va chạm sau đó được giải quyết cho mọi cơ thể trong
bodiesToResolve
.Đó là nó.
Vì vậy, bây giờ tôi đã cố gắng tối ưu hóa phát hiện va chạm ở pha rộng này. Mỗi lần tôi thử một cái gì đó khác với kiến trúc / thiết lập hiện tại, một cái gì đó không đi theo kế hoạch hoặc tôi đưa ra giả định về mô phỏng mà sau này được chứng minh là sai.
Câu hỏi của tôi là: làm thế nào tôi có thể tối ưu hóa pha rộng của động cơ va chạm ?
Có một số loại tối ưu hóa C ++ ma thuật có thể được áp dụng ở đây?
Kiến trúc có thể được thiết kế lại để cho phép hiệu suất cao hơn?
- Thực hiện thực tế: SSVSCollsion
- Body.h , Body.cpp
- World.h , World.cpp
- Grid.h , Grid.cpp
- Cell.h , Cell.cpp
- GridInfo.h , GridInfo.cpp
Đầu ra Callgrind cho phiên bản mới nhất: http://txtup.co/rLJgz
getBodiesToCheck()
được gọi là 5.462.334 lần, và mất 35,1% của toàn bộ thời gian profiling (Hướng dẫn đọc thời gian truy cập)