A * การค้นหาพา ธ ตาข่าย


15

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

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

ผมตั้งใจที่จะใช้ตาข่ายเดินเรือด้วยเหตุผลทั้งหมดออกเรียงรายอยู่ในนี้โพสต์บน ai-blog.net อย่างไรก็ตามปัญหาที่ฉันเผชิญคือสิ่งที่ A * คิดว่าเป็นเส้นทางที่สั้นที่สุดจากจุดกึ่งกลาง / ขอบของรูปหลายเหลี่ยมไม่จำเป็นต้องเป็นเส้นทางที่สั้นที่สุดหากคุณเดินทางผ่านส่วนใดส่วนหนึ่งของโหนด เพื่อให้ได้ความคิดที่ดีที่คุณสามารถดูคำถามที่ผมถามใน StackOverflow

ฉันได้รับคำตอบที่ดีเกี่ยวกับกราฟการมองเห็น ฉันได้ซื้อหนังสือเล่มนี้มาแล้ว ( Computational Geometry: Algorithms และ Applications ) และอ่านเพิ่มเติมในหัวข้ออย่างไรก็ตามฉันยังคงชอบการนำทางแบบเครือข่าย (ดู "การจัดการความซับซ้อน " จากหมายเหตุของ Amit เกี่ยวกับการหาเส้นทาง ) (ตามบันทึกด้านข้างบางทีฉันอาจใช้ Theta * เพื่อแปลง waypoints หลาย ๆ อันให้เป็นหนึ่งเส้นตรงหากสิ่งแรกและสิ่งสุดท้ายไม่ถูกบดบังหรือทุกครั้งที่ฉันย้ายกลับไปตรวจสอบที่จุดก่อนที่จะดูว่าฉันสามารถตรงจาก สิ่งนี้)

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

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

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


ฉันไม่แน่ใจ แต่ลิงก์เหล่านี้อาจช่วยได้: gamedev.stackexchange.com/questions/1327/ …gamedev.stackexchange.com/questions/8087/ ยังมีคำถามอีกข้อหนึ่งเกี่ยวกับการค้นหาเส้นทางที่ฉันไม่สามารถหาได้ในตอนนี้ ซึ่งได้รับรางวัลและได้รับคำตอบที่ดีมาก
Ali1S232

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

ที่จริงแล้วฉันเพิ่งอ่านบทความในgamedev.stackexchange.com/questions/8087/และดูเหมือนว่าจะทำงานโดยการค้นหาเส้นทางด้วย A * จากนั้นคำนวณค่าใช้จ่ายจริงด้วยอัลกอริทึมช่องทางที่แก้ไขแล้วค้นหาเส้นทางอื่นและคำนวณมัน ค่าใช้จ่ายจริงอีกครั้งและดูว่ามันจะสั้นกว่าอีก มันทำซ้ำจนกว่าจะรู้ว่าพบเส้นทางที่สั้นที่สุด นี่เป็นการแก้ปัญหาของฉันได้อย่างไรดูเหมือนว่ามันจะค่อนข้างช้าเนื่องจากคุณกำลังทำซ้ำทั้งการยืดและการค้นหาเส้นทางซึ่งจะมีค่าใช้จ่ายค่อนข้างสูง
angrydust

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

@JonathanDickinson ฉันรู้ว่าฉันไม่จำเป็นต้องมีเส้นทางที่จะถูกต้อง 100% เพื่อพิกเซลที่ผ่านมาและฉันรู้ว่าฉันสามารถใช้ A * ในการผลิตเส้นทางที่จะเป็นที่ส่วนใหญ่พียอมรับ สิ่งนี้กำลังดำเนินไปในทางยาวรอบสิ่งกีดขวางอย่างชัดเจนเช่นเดียวกับในคำถามก่อนหน้าของฉันเกี่ยวกับสแต็คล้นหรือในgamedev.stackexchange.com/questions/8087/…เป็นเรื่องมากเกินไป ฉันไม่สามารถให้ AI ของฉันเดินไปรอบ ๆ สิ่งกีดขวางได้!
angrydust

คำตอบ:


14

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

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

การค้นหาเส้นทาง

คุณมีส่วน A * ซึ่งเก่งมาก คุณได้ทำการสังเกตด้วยว่า A * จะไม่พบเส้นทางที่ตรงที่สุดเสมอไป จำเป็นอย่างยิ่งที่จะต้องเข้าใจว่านี่เป็นเพราะ A * เป็นอัลกอริทึมในการค้นหาเส้นทางที่สั้นที่สุดผ่านกราฟ (เป็นแนวคิดทางคณิตศาสตร์ที่โหนดไม่มีมิติ) เมื่อคุณนำไปใช้กับ mesh คุณต้องแมปโหนดกับองค์ประกอบของตาข่ายอย่างใด

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

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

การยืดเส้นทาง

อัลกอริทึมที่ใช้ใน Detour (ไลบรารีการนำทางที่มาพร้อมกับ Recast) นั้นค่อนข้างง่าย คุณควรสังเกตว่ามันจะยืดเส้นทางภายในขอบเขตของรูปหลายเหลี่ยมที่พบในระหว่างการค้นหา A * เท่านั้น ดังนั้นหากไม่พบเส้นทางที่แคบที่สุดรอบ ๆ สิ่งกีดขวางคุณจะไม่ได้รับเส้นทางที่คับแคบหลังจากใช้อัลกอริทึมนั้น ในทางปฏิบัติ navmeshes ที่ผลิตโดย recast มักจะมีรูปหลายเหลี่ยมเดียวที่คุณสามารถผ่านเมื่อนำทางจุดที่ทำให้หายใจไม่ออก (จุดที่ใกล้ที่สุดระหว่างสองอุปสรรค) และดังนั้น A * จะสร้างรายการของโหนดที่ใกล้เคียงกับสิ่งกีดขวางเสมอ เป็นไปได้ หากคุณกำลังใช้ไทล์เป็น navmesh สิ่งนี้จะไม่เกิดขึ้นและอัลกอริธึมที่ง่ายมากนี้จะแทรกการหมุนของปลอม

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

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

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

เป็นตัวแทนของ navmesh

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


ฉันเพิ่งอ่านสั้น ๆ แต่ฉันเข้าใจว่าคุณไม่ควรใช้สแควร์ของระยะทาง (หรือไม่ใช่สแควร์รูท) สำหรับ A *: theory.stanford.edu/~amitp/GameProgramming/ …
angrydust

ฉันไม่ได้กังวลเกี่ยวกับวิธีที่จะไปเกี่ยวกับเส้นทางยืด atm จริง ๆ สิ่งที่ฉันกังวลคือสิ่งที่คุณพูดว่า: "คุณควรสังเกตว่ามันจะตรงเส้นทางภายในขอบเขตของรูปหลายเหลี่ยมที่พบในระหว่างการค้นหา A * ถ้าเช่นนั้นไม่พบเส้นทางที่แคบที่สุดรอบ ๆ สิ่งกีดขวางคุณจะไม่ได้รับเส้นทางที่คับแคบหลังจากใช้อัลกอริทึมนั้นเช่นกัน "
angrydust

ฉันต้องการมี nav nav ที่ A * จะหาเส้นทางที่ครั้งหนึ่งเคยถูกทำให้สั้นที่สุดโดยไม่คำนึงถึงค่าใช้จ่ายในการเดินทางผ่านจุดยอด / จุดกึ่งกลาง ฉันขอขอบคุณที่สิ่งนี้สามารถทำได้ด้วยกราฟการมองเห็น แต่ฉันต้องการใช้ navmesh เพราะมันมีประโยชน์อื่น ๆ มากมายและเนื่องจากความซับซ้อนของกราฟการมองเห็นสามารถเติบโตได้อย่างรวดเร็ว: theory.stanford.edu/~amitp/GameProgramming/ ......
angrydust

@theguywholikeslinux คุณสามารถใช้ระยะทางยุคลิดsqrt(x*x + y*y)- x*x + y*yแต่ไม่โหนดราคาถูกต่อ
Jonathan Dickinson

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