การตรวจจับการชนกันที่รวดเร็วยิ่งขึ้น


13

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

Enemy class update method
    Loop through all enemies (continue; if the loop points at this object)
        If enemy object intersects with this object
            Push enemy object away from this enemy object

มันใช้งานได้ดี ตราบใดที่ฉันมี <เอนทิตีศัตรู <200 เท่านั้นนั่นคือ เมื่อฉันเข้าใกล้ศัตรู 300-350 หน่วยอัตราเฟรมของฉันเริ่มลดลงอย่างหนัก ครั้งแรกฉันคิดว่าการเรนเดอร์ไม่ดี สิ่งนี้ไม่ได้ช่วยเลยแน่นอนว่าฉันรู้ว่ามันเป็นวิธีการอัพเดท ส่วนที่หนักเพียงอย่างเดียวในวิธีการอัปเดตของพวกเขาคือชิ้นส่วนแต่ละตัวของศัตรูรอบด้าน เมื่อฉันเข้าใกล้ศัตรู 300 คนเกมจะทำซ้ำขั้นตอนที่ 90000 (300x300) ของฉัน ~

ฉันแน่ใจว่าต้องมีวิธีอื่นในการตรวจสอบการชนกันของข้อมูล แม้ว่าฉันจะไม่ทราบวิธีการ หน้าที่ฉันค้นหาเป็นเรื่องเกี่ยวกับวิธีการชนระหว่างวัตถุสองอย่างจริงหรือวิธีตรวจสอบการชนกันระหว่างวัตถุและไทล์ ฉันรู้สองสิ่งนี้แล้ว

TL; DR? ฉันจะตรวจสอบการชนกันของข้อมูลระหว่างหน่วยงานจำนวนมากได้อย่างไร

การแก้ไขอย่างรวดเร็ว: ถ้ามันเป็นความช่วยเหลือใด ๆ ฉันใช้ C # XNA


ฉันสงสัยว่าคุณได้รับมันไปที่ 90K ในตอนแรก Mine chokes ที่ 20K (ฉันกำลังตรวจจับ SAT MTV เต็ม) แต่ฉันวนลูปผ่านศัตรูทั้งหมดเป็นสิ่งเดียวที่ดูเหมือนเป็นไปได้ สิ่งที่คุณต้องทำคือการตรวจสอบว่าพวกเขาได้รับการตรวจสอบแล้วเพราะถ้าคุณทำอย่างที่คุณพูดทุกคนจะถูกทดสอบกับทุกคนสองครั้ง
Delusional Logic

3
นี่เป็นสำเนาที่เป็นไปได้ของgamedev.stackexchange.com/questions/39931/…
Markus von Broady

มีคำตอบที่ดีมากในคำถามที่ @MarkusvonBroady เชื่อมโยงอยู่
Cypher

เป็นไปได้ที่ซ้ำกันของการชน
Stephen

คำตอบ:


11

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

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

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

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

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

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

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

หวังว่านี่จะช่วยได้


1
นี่คือคำตอบที่คลุมเครือ และเราสามารถยอมรับที่จะพลาดการชนกันได้หรือไม่? ง่ายกว่ามากใช้โครงสร้างข้อมูลที่จะทำการแบ่งพาร์ติชั่นสำหรับคุณเช่น Quad Tree ที่ฉันพูดถึงที่นี่ แม้แต่ Quad Tree ก็ต้องการการปรับแต่งเล็กน้อยเพื่อหลีกเลี่ยงค่าใช้จ่ายดังนั้นฉันไม่สามารถจินตนาการความซับซ้อนของ 'โซลูชัน' ที่คุณพูดถึงได้ กฎการเขียนโปรแกรมพื้นฐาน: เพียงใช้โครงสร้างข้อมูลที่ถูกต้อง
GameAlchemist

@VincentPiel กราฟฉากไม่ซับซ้อนกว่าต้นไม้รูปสี่เหลี่ยม
Cypher

@ James: เห็นได้ชัดว่ามันซับซ้อนกว่า หากคุณไม่สนใจที่จะจับความเร็วเต็มที่ของ QuadTree คุณสามารถใช้ QuadTree lib บนเน็ตและทำงานได้อย่างสมบูรณ์ในเวลาไม่กี่ชั่วโมง ไม่มีคำถามเช่น: ฉันจะใส่อะไรในรายการแรกที่สองที่สามฉันจะตัดสินใจที่จะนำสิ่งที่อยู่ในรายการอื่น ... และไม่พลาดการปะทะกัน ทำไมต้องใช้จักรยานเมื่อมีรถ?
GameAlchemist

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

6

คุณต้องจัดการกับการชนด้วยโครงสร้างข้อมูลที่เรียงลำดับดังนั้นคุณสามารถมี n * log (n) ครั้งแทนการแย่ n ^ 2 และ n * log (n) เกือบเป็นเส้นตรงอย่างที่คุณอาจจะรู้ ตัวอย่างหนึ่ง (คลาสสิก) คือควอดทรีมีบทช่วยสอนที่เรียบง่ายและเขียนได้ดีพร้อมกราฟิกและโค้ด (Java):

http://gamedev.tutsplus.com/tutorials/implementation/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space/

Rq: มันค่อนข้างง่ายในการค้นหาการใช้งานสำหรับ QuadTrees ในภาษาใด ๆ อย่างไรก็ตามคุณต้องคิดเกี่ยวกับ 'granularity' ที่ถูกต้องสำหรับต้นไม้และยิ่งต้นไม้มีขนาดใหญ่ยิ่งเรามีเอนทิตีที่ไม่พอดีกับโหนด
Rq 2: เนื่องจากการแบ่งพาร์ติชั่นอวกาศของคุณทำเพื่อการตรวจจับการชนเท่านั้นคุณจึงมีอิสระอย่างสมบูรณ์แบบในการแบ่งพื้นที่ตามที่คุณต้องการ ตัวอย่างเช่นฉันจะไม่แบ่งออกเป็นสี่ส่วนเช่นกัน แต่ฉันจะใช้ baricenter ของหน่วยงานระดับปัจจุบันเป็นศูนย์กลางสำหรับการแบ่งใหม่ 1) อัลกอริทึมยังคงเป็น n * log (n), 2) คุณปล่อยความเป็นไปได้ที่จะ 'สร้าง' ฉากออกมาจากต้นไม้ - แต่คุณไม่สนใจ - และ 3) คุณมีต้นไม้ที่สมดุลมากขึ้น .
Rq3: เมื่อคุณมีต้นไม้ของคุณ 'การชนกัน' ระหว่างหน้าจอและเอนทิตีจะให้คุณ ... เอนทิตีที่มองเห็นได้ !! ในอีกหนึ่งเวลาเช่น log (n) ดังนั้นทำไมไม่ถ้า n มีขนาดใหญ่ (กรณีที่เลวร้ายที่สุดคือเวลาใน n สำหรับวิธีนี้)


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

0

ต้นไม้พาร์ติชันพื้นที่ไบนารีควอดทรีอ็อกทรี (สำหรับ 3D) เป็นต้นไม้ที่เป็นไปได้ที่คุณสามารถสร้าง (หรือบำรุงรักษาถ้าคุณมีความทะเยอทะยาน) ในทุก ๆ การเรียกใช้การปรับปรุงสำหรับทุกวัตถุที่คุณต้องการใช้การชนกัน


3
นี่เหมาะสมกว่าที่จะแสดงความคิดเห็น ลองเพิ่มคำตอบให้มากขึ้น

0

ฉันค่อนข้างไร้เดียงสาเมื่อพูดถึงต้นไม้สี่หรือตุลาคม แต่ฉันคิดว่าวิธีนี้ควรทำ:

คุณจะต้องแก้ไขโครงสร้างผู้เล่น / คลาส เพิ่มอาร์เรย์ / เวกเตอร์ของพอยน์เตอร์ในโครงสร้างผู้เล่นอื่น

ตรวจสอบระยะห่างทุกวินาทีระหว่างผู้เล่นสองคน หากมันต่ำจนสามารถเข้าถึงได้ภายใน 1 วินาทีจากนั้นเพิ่มตัวชี้ของผู้เล่นนั้นไปยังอาเรย์การชนของผู้เล่นปัจจุบัน

ตอนนี้เพียงตรวจสอบการชนกันของผู้เล่นในรายการอื่น ๆ

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