หากนี่เป็นครั้งแรกของคุณสำหรับคำถามนี้ฉันขอแนะนำให้อ่านส่วนอัปเดตด้านล่างก่อนจากนั้นส่วนนี้ นี่คือการสังเคราะห์ปัญหาแม้ว่า:
โดยพื้นฐานแล้วฉันมีระบบตรวจจับการชนและการแก้ปัญหาด้วยระบบแบ่งพาร์ติชันแบบกริดซึ่งการเรียงลำดับการชนและการชนมีความสำคัญ ร่างกายหนึ่งคนในแต่ละครั้งจะต้องเคลื่อนที่จากนั้นตรวจจับการชนแล้วแก้ไขการชน ถ้าฉันย้ายร่างกายทั้งหมดในครั้งเดียวจากนั้นสร้างคู่การชนกันที่เป็นไปได้มันจะเร็วขึ้นอย่างเห็นได้ชัด แต่ตัวแบ่งความละเอียดเนื่องจากการเรียงลำดับของการชนกันไม่ได้รับการเคารพ ถ้าฉันขยับร่างกายหนึ่งครั้งฉันก็ต้องบังคับให้ร่างกายตรวจสอบการชนและมันจะกลายเป็นปัญหา ^ 2 ใส่กลุ่มในการผสมและคุณสามารถจินตนาการได้ว่าทำไมมันถึงช้ามากอย่างรวดเร็วด้วยร่างกายจำนวนมาก
อัปเดต:ฉันทำงานอย่างหนักกับสิ่งนี้ แต่ไม่สามารถจัดการเพื่อเพิ่มประสิทธิภาพอะไรได้เลย
ฉันค้นพบปัญหาใหญ่เช่นกัน: เครื่องยนต์ของฉันขึ้นอยู่กับการชนกันของข้อมูล
ฉันพยายามที่มีการใช้งานของคนรุ่นชนคู่ที่ไม่ซ้ำกันซึ่งแน่นอนเพิ่มความเร็วในการทุกอย่างด้วยเป็นจำนวนมาก แต่ยากจนชนการสั่งซื้อของ
ให้ฉันอธิบาย:
ในการออกแบบดั้งเดิมของฉัน (ไม่สร้างคู่) สิ่งนี้เกิดขึ้น:
- เคลื่อนไหวร่างกายเดียว
- หลังจากที่มันเคลื่อนไหวแล้วมันจะรีเฟรชเซลล์และทำให้ร่างกายได้รับการชนกัน
- หากมันทับร่างกายที่ต้องแก้ไขให้แก้ไขการชนกัน
นี่หมายความว่าหากร่างกายเคลื่อนไหวและชนกับกำแพง (หรือร่างกายอื่น ๆ ) เฉพาะร่างกายที่เคลื่อนไหวเท่านั้นที่จะแก้ไขการชนและร่างกายอื่น ๆ จะไม่ได้รับผลกระทบ
นี่คือความปรารถนาที่พฤติกรรมของฉัน
ผมเข้าใจว่ามันไม่ธรรมดาสำหรับเครื่องยนต์ฟิสิกส์ แต่มันก็มีประโยชน์มากสำหรับสไตล์ย้อนยุคเกม
ในการออกแบบกริดปกติ (สร้างคู่ที่ไม่ซ้ำกัน) สิ่งนี้เกิดขึ้น:
- ทุกสิ่งเคลื่อนไหว
- หลังจากย้ายวัตถุทั้งหมดแล้วให้รีเฟรชเซลล์ทั้งหมด
- สร้างคู่การชนกันที่ไม่ซ้ำกัน
- สำหรับแต่ละคู่จัดการการตรวจจับการชนและความละเอียด
ในกรณีนี้การเคลื่อนที่พร้อมกันอาจส่งผลให้มีสองวัตถุซ้อนทับกันและพวกมันจะแก้ไขในเวลาเดียวกัน - สิ่งนี้ทำให้ร่างกาย "ผลักกันอีกรอบ" อย่างมีประสิทธิภาพ
ลักษณะการทำงานนี้เป็นเรื่องธรรมดาสำหรับเครื่องยนต์ฟิสิกส์แต่มันเป็นเรื่องที่ยอมรับไม่ได้ในกรณีของฉัน
ฉันยังพบปัญหาอื่นซึ่งสำคัญ (แม้ว่าจะไม่เกิดขึ้นในสถานการณ์จริง):
- พิจารณาร่างของกลุ่ม A, B และ W
- การชนกันและแก้ไขกับ W และ A
- B ชนกันและแก้ไขกับ W และ B
- A ไม่ทำอะไรเลยกับ B
- B ไม่ทำอะไรเลยกับ A
อาจมีสถานการณ์ที่วัตถุ A และ B จำนวนมากครอบครองเซลล์เดียวกัน - ในกรณีนั้นมีการวนซ้ำที่ไม่จำเป็นระหว่างเนื้อความที่ไม่ต้องตอบสนองต่อกันและกัน (หรือตรวจจับการชนเท่านั้น แต่ไม่สามารถแก้ไขได้) .
สำหรับ 100 ศพที่ครอบครองเซลล์เดียวกันมันจะวนซ้ำ100 ^ 100 ! สิ่งนี้เกิดขึ้นเพราะคู่ที่ไม่ซ้ำกันไม่ได้ถูกสร้างขึ้น แต่ฉันไม่สามารถสร้างคู่ที่ไม่ซ้ำกันได้มิฉะนั้นฉันจะได้รับพฤติกรรมที่ฉันไม่ต้องการ
มีวิธีเพิ่มประสิทธิภาพของเอ็นจิ้นการชนประเภทนี้หรือไม่?
นี่คือแนวทางที่ต้องเคารพ:
ลำดับการปะทะนั้นสำคัญมาก!
- ร่างกายจะต้องย้ายในเวลาหนึ่งแล้วตรวจสอบการชนหนึ่งที่เวลาและการแก้ปัญหาหลังจากเคลื่อนไหวในช่วงเวลาหนึ่ง
ร่างกายต้องมี 3 กลุ่มบิตเซ็ต
- กลุ่ม : กลุ่มที่ร่างกายเป็นของ
- GroupsToCheck : กลุ่มที่ร่างกายต้องตรวจจับการชนกัน
- GroupsNoResolve : กลุ่มที่ร่างกายต้องไม่แก้ไขการชนกัน
- อาจมีสถานการณ์ที่ฉันต้องการให้ตรวจพบการชนกัน แต่ไม่สามารถแก้ไขได้
Pre-UPDATE:
คำนำ : ฉันรู้ว่าการเพิ่มประสิทธิภาพคอขวดนี้ไม่จำเป็น - เครื่องยนต์นั้นเร็วมากแล้ว อย่างไรก็ตามเพื่อความสนุกสนานและเพื่อการศึกษาฉันชอบที่จะหาวิธีทำให้เครื่องยนต์ทำงานได้เร็วขึ้น
ฉันกำลังสร้างเอนจิ้นการตรวจจับ / ตอบสนองการชนกันของ C ++ 2D โดยเน้นที่ความยืดหยุ่นและความเร็ว
นี่เป็นแผนภาพพื้นฐานของสถาปัตยกรรม:
โดยทั่วไปชั้นหลักคือWorld
ซึ่งเป็นเจ้าของ (จัดการหน่วยความจำ) ของResolverBase*
เป็นและSpatialBase*
vector<Body*>
SpatialBase
เป็นคลาสเสมือนจริงที่เกี่ยวข้องกับการตรวจจับการชนกันในวงกว้าง
ResolverBase
เป็นคลาสเสมือนจริงที่เกี่ยวข้องกับการแก้ปัญหาการชนกันของข้อมูล
ร่างกายสื่อสารWorld::SpatialBase*
กับSpatialInfo
วัตถุด้วยตัวเอง
มีชั้นGrid : SpatialBase
บรรยากาศหนึ่งชั้น: ซึ่งเป็นตาราง 2D พื้นฐานที่คงที่ GridInfo : SpatialInfo
มันมีของมันชั้นข้อมูลของตัวเอง
นี่คือลักษณะของสถาปัตยกรรม:
Grid
ชั้นเป็นเจ้าของอาร์เรย์ 2 Cell*
มิติของ Cell
ชั้นมีคอลเลกชันของ (ไม่ได้เป็นเจ้าของ) Body*
: กvector<Body*>
ซึ่งมีร่างกายทั้งหมดที่อยู่ในเซลล์
GridInfo
วัตถุยังมีพอยน์เตอร์ที่ไม่ได้เป็นเจ้าของต่อเซลล์ที่ร่างกายอยู่
อย่างที่ฉันพูดไปก่อนหน้านี้เครื่องยนต์นั้นใช้กลุ่ม
Body::getGroups()
ส่งคืนกลุ่มstd::bitset
ทั้งหมดที่ร่างกายเป็นส่วนหนึ่งของBody::getGroupsToCheck()
ส่งคืนกลุ่มstd::bitset
ทั้งหมดที่ร่างกายต้องตรวจสอบการชนกัน
ร่างกายสามารถครอบครองมากกว่าเซลล์เดียว GridInfo เก็บพอยน์เตอร์ที่ไม่ได้เป็นเจ้าของไปยังเซลล์ที่ถูกครอบครองเสมอ
หลังจากร่างกายเคลื่อนที่เพียงครั้งเดียวการตรวจจับการชนจะเกิดขึ้น ฉันคิดว่าวัตถุทั้งหมดเป็นกล่องที่มีขอบเขตเป็นแนวแกน
การตรวจจับการชนกันของเฟสกว้างทำงานอย่างไร:
ส่วนที่ 1: อัปเดตข้อมูลเชิงพื้นที่
สำหรับแต่ละBody
body
:
- คำนวณเซลล์ที่ถูกครอบครองที่อยู่ด้านบนซ้ายสุดและเซลล์ที่ถูกครอบครองที่อยู่ทางขวาล่างซ้ายสุด
- หากแตกต่างจากเซลล์ก่อนหน้า
body.gridInfo.cells
จะถูกล้างและเต็มไปด้วยเซลล์ทั้งหมดที่ร่างกายครอบครอง (2D สำหรับการวนซ้ำจากเซลล์บนซ้ายไปยังเซลล์ล่างขวาสุด)
body
ตอนนี้รับประกันว่าจะรู้ว่าเซลล์ครอบครอง
ส่วนที่ 2: การตรวจสอบการชนจริง
สำหรับแต่ละBody
body
:
body.gridInfo.handleCollisions
ถูกเรียก:
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);
}
การชนกันจะได้รับการแก้ไขสำหรับทุก
bodiesToResolve
ๆแค่นั้นแหละ.
ดังนั้นฉันจึงพยายามปรับการตรวจจับการชนกันของระยะกว้างให้เหมาะสมในขณะนี้ ทุกครั้งที่ฉันลองอย่างอื่นนอกเหนือจากสถาปัตยกรรม / การตั้งค่าปัจจุบันสิ่งที่ไม่เป็นไปตามแผนที่วางไว้หรือฉันสมมุติว่าการจำลองที่ภายหลังได้รับการพิสูจน์แล้วว่าเป็นเท็จ
คำถามของฉันคือ: ฉันจะเพิ่มประสิทธิภาพระยะกว้างของเอ็นจิ้นการชนได้อย่างไร
มีการเพิ่มประสิทธิภาพเวทมนต์ C ++ บางประเภทที่สามารถนำไปใช้ที่นี่ได้หรือไม่?
สามารถออกแบบสถาปัตยกรรมใหม่เพื่อให้มีประสิทธิภาพมากขึ้นได้หรือไม่
- การใช้งานจริง: SSVSCollsion
- Body.h , Body.cpp
- World.h , World.cpp
- Grid.h , Grid.cpp
- Cell.h , Cell.cpp
- GridInfo.h , GridInfo.cpp
Callgrind output สำหรับรุ่นล่าสุด: http://txtup.co/rLJgz
getBodiesToCheck()
ถูกเรียก 5462334 ครั้งและใช้เวลา 35,1% ของเวลาการทำโปรไฟล์ทั้งหมด (คำแนะนำเวลาอ่านเข้าถึง)