การตอบสนองรูปสี่เหลี่ยมผืนผ้าชนกัน


10

ฉันมีปัญหาในการรับสี่เหลี่ยมที่เคลื่อนย้ายได้เพื่อชนกับสี่เหลี่ยมมากกว่าหนึ่ง

ฉันกำลังใช้SFMLและมันมีฟังก์ชั่นintersectsที่ใช้งานง่ายที่เรียกว่าซึ่งใช้เวลา 2 สี่เหลี่ยมและส่งกลับจุดตัด ฉันมีเวกเตอร์ที่เต็มไปด้วยรูปสี่เหลี่ยมผืนผ้าซึ่งฉันต้องการให้สี่เหลี่ยมที่เคลื่อนย้ายได้ของฉันชนกัน ฉันวนลูปผ่านสิ่งนี้โดยใช้รหัสต่อไปนี้ (p คือสี่เหลี่ยมที่เคลื่อนที่ได้)

IsCollidingWithส่งกลับค่าบูล แต่ยังใช้ SFML intersectsเพื่อหาจุดแยก

while(unsigned i = 0; i!= testRects.size(); i++){
   if(p.IsCollidingWith(testRects[i]){
        p.Collide(testRects[i]);
   }
}

และCollide()รหัสจริง:

void gameObj::collide( gameObj collidingObject ){

 printf("%f %f\n", this->colliderResult.width, this->colliderResult.height);

if (this->colliderResult.width < this->colliderResult.height) {
    // collided on X
    if (this->getCollider().left < collidingObject.getCollider().left ) {
        this->move( -this->colliderResult.width , 0);
    }else {
        this->move( this->colliderResult.width, 0 );
    }

}

if(this->colliderResult.width > this->colliderResult.height){
    if (this->getCollider().top < collidingObject.getCollider().top ) {
        this->move( 0, -this->colliderResult.height);
    }else {     
        this->move( 0, this->colliderResult.height );
    }

}

และIsCollidingWith()รหัสคือ:

bool gameObj::isCollidingWith( gameObj testObject ){
if (this->getCollider().intersects( testObject.getCollider(), this->colliderResult )) {
    return true;
}else {
    return false;
}

ใช้งานได้ดีเมื่อมีเพียง 1 Rectในฉาก อย่างไรก็ตามเมื่อมีมากกว่าหนึ่งรายการRectจะทำให้เกิดปัญหาเมื่อแก้ไข 2 การชนในครั้งเดียว

มีความคิดวิธีจัดการกับสิ่งนี้อย่างถูกต้องหรือไม่? ฉันได้อัปโหลดวิดีโอไปยัง youtubeเพื่อแสดงปัญหาของฉัน คอนโซลทางด้านขวาสุดแสดงความกว้างและความสูงของทางแยก คุณสามารถเห็นบนคอนโซลที่พยายามคำนวณการชนกัน 2 ครั้งพร้อมกันฉันคิดว่านี่เป็นสาเหตุที่ทำให้เกิดปัญหา

ในที่สุดภาพด้านล่างดูเหมือนจะอธิบายปัญหาของฉันได้ดี:

การชนกันของสี่เหลี่ยมผืนผ้ากับสี่เหลี่ยมผืนผ้าอื่น ๆ อีกมากมาย


ลิงค์วิดีโอเสีย
XiaoChuan Yu

เป็นcolliderวัตถุที่ส่งกลับโดยthis->getCollider()การปรับปรุงโดยthis->move()??
XiaoChuan Yu

คุณช่วยเพิ่มข้อมูลเพิ่มเติมหน่อยได้ไหม? ปัญหาคืออะไรกันแน่? วิดีโอ YouTube ดูเหมือนจะแสดงพฤติกรรมที่สามารถคาดเดาได้และมีอีกสี่เหลี่ยมผืนผ้าเดียวในฉาก
Wackidev

คำตอบ:


3

ภาพของคุณแสดงให้เห็นถึงหนึ่งในปัญหามากมายที่พยายามใช้รูปทรงนูนโดยเฉพาะอย่างยิ่งรูปสี่เหลี่ยมผืนผ้าเพื่อจำลองพื้นผิวที่เรียบเหมือนพื้น อัลกอริธึมนำไปสู่การติดอยู่ที่ขอบด้านในของรูปร่างที่ประกอบขึ้นเป็นพื้น

การแก้ไขอย่างง่าย ๆ สำหรับสิ่งนั้นคือการตรวจสอบการชนในแนวตั้งเท่านั้นแก้ไขให้ถูกต้องจากนั้นตรวจสอบการชนกันในแนวนอนอีกครั้ง นอกจากว่าคุณกำลังล้มและพยายามเลื่อนกำแพงลงในกรณีนี้คุณต้องการตรวจสอบการชนในแนวนอนก่อน คุณจะรู้ได้อย่างไรว่าจะต้องตรวจสอบครั้งแรกเมื่อใด คุณสามารถทำได้โดยขึ้นอยู่กับว่าองค์ประกอบของความเร็วของคุณมีขนาดใหญ่กว่า (หากการเคลื่อนไหวในแนวนอนมีขนาดใหญ่กว่าให้ตรวจสอบการชนในแนวตั้งก่อนหรือตรวจสอบการชนตามแนวนอน)

สิ่งที่สามารถทำได้ง่ายขึ้น - และมีประสิทธิภาพมากขึ้น - คือการสร้างรายการขอบสำหรับโลกของคุณแทน นั่นคือสำหรับกล่องที่ประกอบขึ้นเป็นพื้นให้ตั้งค่าสถานะเพื่อระบุว่ามีเพียงขอบด้านบนสุดเท่านั้นที่สามารถชนกันได้จริงแล้วละเว้นการชนกับขอบอื่น ๆ คุณจะไม่สามารถใช้รูทีนการชนของ SFML สำหรับการทำเช่นนั้นได้ แต่โดยความจริงแล้วเพียงแค่การชนกันของกล่องอาจเป็นรหัสบิตที่ง่ายที่สุดที่คุณเคยเขียนในเกม เทคนิคนี้ใช้ได้ดีเป็นพิเศษหากโลกของคุณอยู่ในแนวเดียวกับกริด ฉันจะตรวจสอบบทเรียน Metanet ที่ยอดเยี่ยม (http://www.metanetsoftware.com/technique.html/) สำหรับเทคนิคนั้น

คุณกำลังจะเจอกับปัญหาอื่น ๆ อีกมากมายที่พยายามสร้างเกม platformer 2D ที่เรียบง่ายเหมือนที่คุณเป็น เท่าที่ผ่านมาทรัพยากรที่ดีที่สุดที่ฉันเคยเห็นสำหรับ latel นั้นคือสิ่งต่อไปนี้ซึ่งคุณควรอ่านแล้วอ่านอีกครั้ง:

http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/


1

บางทีวิธีแก้ปัญหาง่ายๆก็คือการตรวจสอบการชนกันของทุกสี่เหลี่ยมผืนผ้าและเลื่อนกลับไปในทิศทางตรงกันข้ามของการเคลื่อนไหวจนกว่าจะไม่พบการชนกัน หากวิธีนี้แก้ปัญหาได้การดำเนินการควรง่ายเกินไป


+1, ฉันเขียนเกี่ยวกับที่นี่จริง ๆ : gamedev.stackexchange.com/questions/38252/…
Markus von Broady

0

ฉันไม่คิดว่าการชนกัน 2 ครั้งเป็นปัญหา แต่เป็นปัญหาด้านประสิทธิภาพเท่านั้น เพื่อให้การจัดการการชนถูกต้องอาจต้องทำการทดสอบสองครั้ง การใช้ไดอะแกรมของคุณคิดว่าถ้าทดสอบกับ B ก่อนแล้วจะต้องทดสอบกับกล่องอื่นด้วยเช่นกันและอาจชนกับอีกกล่องหนึ่ง

หวังว่าจะเป็นประโยชน์หรือไม่


0

นี่ไม่ใช่วิธีการที่ดีที่สุดคุณควรพยายามกำหนดเวลาที่เร็วที่สุดเมื่อหรือจุดแรกตามเส้นทางของวัตถุเคลื่อนที่ที่เกิดการชนและย้ายวัตถุไปยังตำแหน่งนั้น (หรือตำแหน่งในเวลาที่คำนวณ) พยายาม ถูกต้องขึ้นอยู่กับตำแหน่งการเจาะหลังจากการเคลื่อนไหวเป็นปัญหามาก แต่คุณสามารถใช้กระบวนการปัจจุบันของคุณด้วยการเปลี่ยนแปลงเล็กน้อย เพียงแค่ตรวจสอบหาการชนกันจนกว่าจะไม่มี

bool collided = true;
while(collided) {
   collided = false
   while(unsigned i = 0; i!= testRects.size(); i++){
      if(p.IsCollidingWith(testRects[i]){
         collided = true
         p.Collide(testRects[i]);
      }
   }
}

โปรดทราบว่ามีสถานการณ์ที่สิ่งนี้จะนำไปสู่การวนรอบไม่สิ้นสุด (คิดว่าสถานการณ์ที่การย้ายกล่องออกจากการชนส่งผลให้เกิดการสะสมอีกครั้งและการย้ายกล่องออกจากการชนนั้นจะย้ายกลับไปที่ตำแหน่งการชนเดิมเหมือนเดิม)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.