วิธีที่เร็วที่สุดในการจัดกลุ่มหน่วยที่สามารถมองเห็นซึ่งกันและกัน?


12

ในเกม 2D ที่ฉันทำงานด้วยเอ็นจิ้นเกมสามารถให้ฉันสำหรับแต่ละหน่วยรายการของหน่วยอื่น ๆ ที่อยู่ในระยะการมองของมัน

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

ตัวอย่างอาจช่วยให้เข้าใจคำถามได้ดีขึ้น (E = ศัตรู, O = หน่วยของตัวเอง) ก่อนอื่นข้อมูลที่ฉันจะได้รับจากเอ็นจิ้นเกม:

E1 can see E2, E3, O5
E2 can see E1
E3 can see E1
E4 can see O5
E5 can see O2
E6 can see E7, O9, O1
E7 can see E6
O1 can see E6
O2 can see O5, E5
O5 can see E1, E4, O2
O9 can see E6

จากนั้นฉันควรคำนวณกลุ่มดังนี้

G1 = E1, E2, E3, E4, E5, O2, O5
G2 = O1, O9, E6, E7

มันสามารถสันนิษฐานได้อย่างปลอดภัยว่ามีคุณสมบัติสับเปลี่ยนสำหรับมุมมอง: [ถ้า A เห็น B ดังนั้น B จะเห็น A]

เพียงเพื่อชี้แจง: ฉันได้เขียนการใช้งานไร้เดียงสาที่ลูปในแต่ละแถวของข้อมูลเครื่องยนต์เกม แต่จากลักษณะของมันดูเหมือนว่าปัญหาทั่วไปพอที่จะได้รับการศึกษาในเชิงลึกและมีอัลกอริทึมที่จัดตั้งขึ้นต่างๆ ผ่านโครงสร้างคล้ายต้นไม้บ้างไหม) ปัญหาของฉันคือฉันไม่สามารถหาวิธีที่จะอธิบายปัญหาของฉันที่ส่งคืน google hits ที่มีประโยชน์

ขอบคุณล่วงหน้าสำหรับความช่วยเหลือของคุณ!


1
ฉันคิดว่าคำถามนี้เป็นคำถามทั่วไปพอที่จะได้คำตอบที่ดีกว่าใน stackoverflow หรืออาจเป็นคณิตศาสตร์ (เซตทฤษฎี?) มันไม่ใช่ประเด็นที่เฉพาะเจาะจงสำหรับการพัฒนาเกม
Tor Valamo

1
@Tor - อาจเป็นจริง แต่ความจริงที่ว่าเรารู้ว่ามันเป็นเกมที่อาจทำให้ผู้คนสามารถสร้างคำตอบที่เฉพาะเจาะจงมากขึ้นสำหรับปัญหา
Robert Fraser

ฉันคิดว่าคุณสามารถทำสิ่งที่ชาญฉลาดด้วยการหมุนแป้นหมุนพื้นที่และแผนที่การมองเห็น - ฉันแค่ต้องคิดเกี่ยวกับมัน
Jonathan Dickinson

คำตอบ:


7

หากความสัมพันธ์ "สามารถเห็น" ของคุณนั้นสมมาตรดังนั้น "A สามารถเห็น B" บอกเป็นนัย "B สามารถเห็น A" กลุ่มที่คุณต้องการคำนวณคือองค์ประกอบที่เชื่อมต่อของกราฟที่กำหนดโดย "สามารถดู" ความสัมพันธ์ ดังที่คนอื่น ๆ ระบุไว้มีอัลกอริทึมง่าย ๆ สำหรับการคำนวณสิ่งเหล่านี้เช่น:

while ungrouped units remain:
    let u = arbitrary ungrouped unit
    let g = new group
    let s = temporary stack
    assign u to g
    push u onto s
    while s is not empty:
        let v = topmost unit in s
        remove v from s
        for each unit w that v can see:
            if w is ungrouped:
                assign w to g
                push w onto s
            end if
        end for
    end while
 end while

(คิวหรือคอลเลกชันอื่น ๆ ที่ดำเนินการอย่างมีประสิทธิภาพ "เพิ่มองค์ประกอบใหม่" และ "ลบและส่งคืนองค์ประกอบบางอย่าง" สามารถใช้แทนสแต็กsด้านบน)

หากความสัมพันธ์ "สามารถมองเห็น" ของคุณนั้นไม่ได้สมมาตรคุณต้องตัดสินใจว่าคุณต้องการให้กลุ่มของคุณเป็นองค์ประกอบที่แข็งแกร่งหรือเชื่อมต่ออย่างอ่อน สำหรับส่วนประกอบที่เชื่อมต่ออย่างอ่อน, ขั้นตอนวิธีการดังกล่าวข้างต้นการทำงานจะเป็นยกเว้นว่าสายจะถูกแทนที่ด้วยfor each unit w that v can see for each unit w that can see v, or that v can seeสำหรับส่วนประกอบที่เชื่อมต่ออย่างยิ่งคุณสามารถใช้อัลกอริทึมอย่างใดอย่างหนึ่ง ( Kosaraju's , Tarjan'sหรือGabow's ) ที่กล่าวถึงในหน้า Wikipedia ที่เชื่อมโยง

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


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

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

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

4

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

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

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


3
เพียงเพื่อเพิ่มคำศัพท์ทางเทคนิค: สิ่งที่คุณพยายามค้นหาคือส่วนประกอบที่เชื่อมต่อของกราฟและอัลกอริธึมมาตรฐานคือ: (1) ใส่โหนดทั้งหมดในรายการ (2) เลือกโหนด (3) ค้นหา โหนดที่เชื่อมต่อทั้งหมดโดยใช้ BFS / DFS (4) ลบโหนดทั้งหมดที่คุณพบจากรายการ (5) ทำซ้ำจนกว่าจะไม่มีโหนดเหลืออีก
นาธานรีด

3

ดูเหมือนว่าปัญหาการเชื่อมต่อกราฟมาตรฐาน อาจมีอัลกอริทึมบางอย่างสำหรับสิ่งนี้และอาจมีลักษณะดังต่อไปนี้:

remaining units = all units
for each unit in remaining units:
    current group = create a new group
    add this unit to current group
    for each unit visible to this unit:
        if unit is in a group already:
            merge current group into that existing group
            set current group as that existing group
        else:
            remove that unit from remaining units
            add that unit to current group

ฉันคาดว่าเป็นไปได้ที่จะใช้สิ่งนี้ผ่านต้นไม้เช่นการจัดกลุ่มแบบลำดับชั้น แต่ฉันสงสัยว่าจะทำงานได้เร็วขึ้น - ต้นไม้มีแนวโน้มที่จะเป็น O (log N) ในขณะที่การตรวจสอบส่วนใหญ่ที่ฉันให้ไว้ข้างต้น .


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

นี่คือสิ่งที่ฉันเรียกว่าการใช้งานไร้เดียงสาใน OP ของฉัน ดีใจที่ได้รู้ว่ามันอาจจะไม่เลวร้ายอย่างที่ฉันคิดตอนนั้น! :)
mac

วิธีที่คุณทำมันเป็นต้นไม้คือการใช้ชุดยูเนี่ยนมีการบีบอัดเส้นทาง นั่นไม่ไร้เดียงสามากและในความเป็นจริงแล้วเป็นสิ่งที่ดีที่สุด
Peter Taylor

2

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

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

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