ตัวแทน AI จะเข้าถึงข้อมูลเกี่ยวกับสภาพแวดล้อมของพวกเขาได้อย่างไร


9

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

ในการพัฒนาเกมโดยใช้การออกแบบเชิงวัตถุฉันต้องการเข้าใจว่าตัวแทน AI เข้าถึงข้อมูลที่พวกเขาต้องการจากโลกของเกมเพื่อที่จะดำเนินการได้อย่างไร

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

ปัญหาของฉันคือฉันไม่แน่ใจว่าจะทำอย่างไร ตัวแทน AI จะเข้าถึงข้อมูลที่ต้องการเกี่ยวกับโลกของเกมได้อย่างไร

แนวทางหนึ่งที่เป็นไปได้คือเอเจนต์ร้องขอข้อมูลที่ต้องการจากโลกของเกมโดยตรง

มีคลาสที่เรียกว่า GameWorld มันจัดการตรรกะของเกมที่สำคัญ (วนรอบเกมการตรวจจับการชน ฯลฯ ) และยังมีการอ้างอิงถึงเอนทิตีทั้งหมดในเกม

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

ตัวอย่างเช่นตัวแทนอาจถูกตั้งโปรแกรมให้Seekผู้เล่นเมื่อเขา / เธอปิด ในการทำสิ่งนี้ตัวแทนจะต้องได้ตำแหน่งของผู้เล่น GameWorld.instance().getPlayerPosition()ดังนั้นมันก็สามารถขอได้โดยตรง:

ตัวแทนยังสามารถรับรายการเอนทิตีทั้งหมดในเกมและวิเคราะห์ตามความต้องการ (เพื่อค้นหาว่าเอนทิตีใกล้เคียงหรืออะไรอย่างอื่น): GameWorld.instance().getEntityList()

นี่เป็นวิธีที่ง่ายที่สุด: ตัวแทนติดต่อชั้น GameWorld โดยตรงและรับข้อมูลที่ต้องการ อย่างไรก็ตามนี่เป็นวิธีเดียวที่ฉันรู้ มีดีกว่าไหม

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


หากคุณสามารถเข้าถึงการสมัคร GDCVault ได้มีการพูดคุยที่ยอดเยี่ยมในปี 2556 ที่เรียกว่า "การสร้าง AI สำหรับโลกที่มีชีวิตที่น่าอยู่ของโลกแห่ง Hitman Absolution" ซึ่งจะอธิบายรายละเอียดของโมเดล AI
DMGregory

คำตอบ:


5

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

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

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

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

  • ท้ายที่สุดคุณอาจต้องการใช้อินเทอร์เฟซหรือส่วนประกอบสำหรับวัตถุที่ค้นหาได้ของคุณแทนที่จะเป็นมรดกซึ่งได้รับการบันทึกไว้ที่อื่นแล้ว iterating กว่ารายการEntitiesการตรวจสอบinstanceOfน่าจะเป็นสูตรสำหรับรหัสบอบบางสวยนาทีที่คุณต้องการทั้งสองStaticObjectและจะเป็นMovingObject Healable(ยกเว้นว่าจะใช้instanceOfงานได้กับอินเทอร์เฟซในภาษาที่คุณเลือก)


5

AI มีค่าใช้จ่ายสูงประสิทธิภาพมักเป็นปัจจัยผลักดันในงานสถาปัตยกรรม

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

(ตัวอย่างแต่ละตัวอย่างสมมติว่าเป็นการอัพเดทแบบลอจิกแบบโกลบอลระดับเดียว)

  • เส้นทางที่สั้นที่สุดAI แต่ละเครื่องจะคำนวณสถานะของแผนที่เพื่อการหาเส้นทาง A * ต้องการให้ AI แต่ละคนรู้สภาพแวดล้อม (ในพื้นที่) ทั้งหมดแล้วซึ่งจะต้องค้นหาดังนั้นเราต้องส่งข้อมูลเกี่ยวกับสิ่งกีดขวางบนแผนที่และพื้นที่ (มักจะเป็นอาร์เรย์บูลีน 2D) A * เป็นรูปแบบเฉพาะของอัลกอริธึมของ Dijkstra ซึ่งเป็นอัลกอริธึมการค้นหากราฟแบบเปิดที่สั้นที่สุด วิธีการดังกล่าวจะส่งคืนรายการที่แสดงถึงเส้นทางและในแต่ละขั้นตอน AI จะเลือกโหนดถัดไปในรายการนี้ไปยังขั้นตอนจนกว่าจะถึงเป้าหมายหรือต้องคำนวณซ้ำ (เช่นเนื่องจากการเปลี่ยนแปลงสิ่งกีดขวางบนแผนที่) หากไม่มีความรู้นี้จะไม่พบเส้นทางที่สั้นที่สุดจริง A * เป็นสาเหตุที่ AIs ในเกม RTS รู้วิธีได้รับจากจุด A ไปยังจุด B เสมอ - หากมีเส้นทาง มันจะคำนวณเส้นทางที่สั้นที่สุดสำหรับ AI แต่ละคน เนื่องจากความถูกต้องของเส้นทางขึ้นอยู่กับตำแหน่งของ AIs ที่ย้าย (และอาจปิดกั้นเส้นทางบางเส้นทาง) ก่อนหน้านี้ กระบวนการวนซ้ำที่ A * คำนวณค่าของเซลล์ในระหว่างการหาเส้นทางเป็นหนึ่งในการลู่เข้าทางคณิตศาสตร์ อาจกล่าวได้ว่าผลลัพธ์สุดท้ายนั้นมีความรู้สึกคล้ายกับกลิ่นที่ผสมกับความรู้สึกของการมองเห็น แต่โดยรวมแล้วมันค่อนข้างต่างกับความคิดของเรา

  • Collaborative diffusionนอกจากนี้ยังพบในเกมซึ่งคล้ายกับความรู้สึกของกลิ่นมากที่สุดตามการแพร่กระจายของก๊าซและอนุภาค ซีดีแก้ปัญหาของการประมวลผลค่าใช้จ่ายสูงที่พบใน A *: แทนสถานะแผนที่เดียวจะถูกจัดเก็บประมวลผลหนึ่งครั้งต่อการอัปเดตสำหรับ AIs ทั้งหมดและผลลัพธ์จะถูกเข้าถึงโดย AI แต่ละตัวในทางกลับกัน . ไม่เป็นเส้นทางเดียว (รายการเซลล์) ที่ส่งคืนโดยอัลกอริทึมการค้นหา ค่อนข้าง AI แต่ละคนจะตรวจสอบแผนที่หลังจากที่ได้รับการประมวลผลแล้วและย้ายไปยังเซลล์ใดก็ตามที่อยู่ติดกันมีค่าสูงสุด นี้เรียกว่าเนินเขาปีนเขา อย่างไรก็ตามขั้นตอนการประมวลผลแผนที่จะต้องมีอยู่แล้วมีการเข้าถึงข้อมูลแผนที่ก่อนซึ่งที่นี่ยังมีที่ตั้งของหน่วยงาน AI ทั้งหมด ดังนั้นแผนที่อ้างอิง AIs จากนั้น AIs อ้างอิงแผนที่

  • การมองเห็นด้วยคอมพิวเตอร์และการฉายรังสี + เส้นทางที่สั้นที่สุดในหุ่นยนต์โรเวอร์และโดรนสิ่งนี้กลายเป็นบรรทัดฐานเพื่อกำหนดขอบเขตของช่องว่างที่หุ่นยนต์นำทาง สิ่งนี้ทำให้หุ่นยนต์สามารถสร้างแบบจำลองปริมาตรเต็มรูปแบบของสภาพแวดล้อมของพวกเขาเช่นเดียวกับที่เราเห็นด้วยตาเปล่าหรือแม้แต่เสียงหรือสัมผัส (สำหรับคนตาบอดหรือคนหูหนวก) ซึ่งหุ่นยนต์นั้นอาจลดลงเป็นกราฟภูมิประเทศน้อยที่สุด ใช้ในเกมที่มี A *) ซึ่งอัลกอริทึมเส้นทางที่สั้นที่สุดอาจถูกนำไปใช้ ในตัวอย่างนี้ในขณะที่ "วิสัยทัศน์" อาจให้เบาะแสกับสภาพแวดล้อมในทันที แต่ก็ยังส่งผลให้การค้นหากราฟที่ให้เส้นทางไปยังเป้าหมายในท้ายที่สุด ใกล้เคียงกับความคิดของมนุษย์: ในการที่จะไปครัวจากห้องนอนฉันต้องผ่านห้องนั่งเล่น ความจริงที่ว่าฉันได้เห็นพวกเขาแล้วและรู้ว่าช่องว่างและพอร์ทัลของพวกเขาคือสิ่งที่ทำให้เกิดการเคลื่อนไหวที่คำนวณได้นี้ นี่คือโทโพโลยีกราฟซึ่งใช้อัลกอริธึมพา ธ ที่สั้นที่สุดแม้ว่าจะฝังอยู่ในโปรตีนที่อ่อนนุ่มแทนที่จะเป็นซิลิกอนแข็ง

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

คะแนนสถาปัตยกรรม

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

"รับรายการของเอนทิตีทั้งหมดและค้นหาสิ่งที่คุณต้องการ"

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


ขอบคุณสำหรับคำตอบ. เนื่องจากฉันเป็นผู้เริ่มต้นในการพัฒนาเกมฉันคิดว่าฉันจะยึดติดกับวิธีการ "รับรายชื่อจากเกมโลก" อย่างง่าย ๆ ในตอนนี้ :) คำถามหนึ่ง: ในคำถามของฉันฉันอธิบายGameWorldคลาสเป็นคลาสที่มีการอ้างอิงถึง หน่วยงานเกมทั้งหมดและยังมีตรรกะ 'เอนจิ้น' ที่สำคัญที่สุด: วนรอบเกมหลัก, การตรวจจับการชนและอื่น ๆ โดยทั่วไปแล้วมันเป็น 'คลาสหลัก' ของเกม คำถามของฉันคือ: วิธีนี้เป็นเรื่องธรรมดาในเกมหรือไม่? มี 'คลาสหลัก' หรือไม่ หรือฉันควรแยกมันออกเป็นคลาสที่เล็กกว่าและมีหนึ่งคลาสเป็นวัตถุ 'ฐานข้อมูลเอนทิตี' ที่สามารถสำรวจได้หรือไม่
Aviv Cohn

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

2

โดยทั่วไปฉันมี 2 วิธีในการสอบถามข้อมูล

  1. เมื่อ AIState เปลี่ยนแปลงเนื่องจากคุณตรวจพบการชนหรือแคชใด ๆ ที่อ้างอิงถึงวัตถุใดก็ตามที่มีความสำคัญ ด้วยวิธีนี้คุณจะรู้ว่าคุณต้องการอ้างอิงอะไร เมื่อมีระบบอื่นที่ต้องทำการค้นหาจำนวนมากทุก ๆ เฟรมฉันแนะนำให้ piggy ทำการสำรองข้อมูลเหล่านั้นเพื่อที่คุณจะได้ไม่ต้องทำการค้นหาหลายครั้ง ดังนั้น 'การชน' ที่ตรวจพบโดยโซนที่ทำให้ 'แจ้งเตือน' ของศัตรูส่งข้อความ / เหตุการณ์ที่ลงทะเบียนเขาด้วยวัตถุนั้นหากเขาไม่ได้อยู่แล้วและเปลี่ยนสถานะของเกมเป็นสิ่งที่ทำให้เขาทำธุรกิจของเขา gamestate ที่ คุณต้องการเหตุการณ์บางประเภทที่บอกให้คุณทำการเปลี่ยนแปลงฉันแค่ส่งการอ้างอิงไปยังสิ่งที่คุณใช้ในการโทรกลับเพื่อให้ข้อมูลนั้น สิ่งนี้สามารถขยายได้มากขึ้นจากนั้นต้องจัดการกับผู้เล่น บางทีคุณอาจต้องการให้ศัตรูติดตามศัตรูอื่นหรือวัตถุอื่น วิธีนี้คุณจะต้องเปลี่ยนแท็กอะไรก็ตามที่คุณระบุด้วย

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

    Transform* targetTransform = nullptr;
    EnemyAIState  AIState = EnemyAIState::Idle;
    void OnTriggerEnter(GameObject* go)
    {
       if(go->hasTag(TAG_PLAYER))
       {
       //Cache important information that will be needed during pursuit
       targetTransform = go->getComponent<Transform>();
       AIState = EnemyAIState::Pursue;
       }
    }
    
    void Update()
    {
       switch(AIState)
       {
          case EnemyAIState::Pursue:
           //Find position to move to
           Vector3 nextNode = PathSystem::Seek(
                              transform->position,targetTransform->position);
           /*Update the position towards the target by whatever speed the unit moves
             Depending on how robust your path system is you might want to raycast
             against obstacles it can't take into account or might clip the path.*/
            transform->Move((nextNode - transform->position).unitVector()*speed*Time::deltaTime());
            break;
        }
     }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.