“ The Game Object” - และการออกแบบส่วนประกอบ


25

ฉันทำงานโครงการอดิเรกบางอย่างเมื่อ 3-4 ปีที่แล้ว เกม 2D และ 3D ที่เรียบง่าย แต่เมื่อเร็ว ๆ นี้ฉันได้เริ่มโครงการที่ใหญ่กว่า Soo ในช่วงสองสามเดือนที่ผ่านมาฉันพยายามออกแบบคลาสเกมวัตถุซึ่งอาจเป็นฐานของวัตถุเกมทั้งหมดของฉัน ดังนั้นหลังจากการทดสอบแบบลองและแบบตายตัวฉันจึงหันไปหา Google ซึ่งชี้ให้ฉันเห็นอย่างรวดเร็วใน GDC PDF และ PowerPoint บางส่วน และตอนนี้ฉันกำลังพยายามเข้าใจวัตถุของเกมที่มีส่วนประกอบ

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

ฉันอยู่ภายใต้การแสดงผลว่าเป็นอะไรเช่นนี้ (ใน HealthComponent):

if(Health < 0) {
   AnimationComponent.PlayAnimation("played-died-animation")
}

แต่แล้วอีกครั้ง HealthComponent จะรู้ได้อย่างไรว่ามีการแนบออบเจกต์เกมกับ AnimationComponent ทางออกเดียวที่ฉันเห็นที่นี่คือ

  1. มีการตรวจสอบเพื่อดูว่า AnimationComponent แนบหรือไม่ (ทั้งในรหัสส่วนประกอบหรือด้านเครื่องยนต์)

  2. มีส่วนประกอบที่ต้องการส่วนประกอบอื่น ๆ แต่ดูเหมือนว่าจะต่อสู้กับการออกแบบองค์ประกอบทั้งหมด

  3. เขียนเหมือน HealthWithAnimationComponent, HealthNoAnimationComponent และ soo on ซึ่งดูเหมือนว่าจะต่อสู้กับแนวคิดการออกแบบองค์ประกอบทั้งหมดอีกครั้ง


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

1
ขึ้นอยู่กับประเภทของเกมคุณอาจไม่มีวัตถุในเกมที่มีองค์ประกอบด้านสุขภาพและไม่มีองค์ประกอบของภาพเคลื่อนไหว และ Gameobjects เหล่านี้ทั้งหมดอาจเป็นตัวแทนของบางอย่างเช่น Unit ดังนั้นคุณสามารถโยนองค์ประกอบสุขภาพและสร้าง UnitComponent ที่จะมีสุขภาพภาคสนามและรู้เกี่ยวกับองค์ประกอบทั้งหมดที่หน่วยจะต้องมี ส่วนประกอบที่ละเอียดมากนี้ไม่ได้ช่วยอะไรเลย - มีความเป็นจริงมากกว่าที่จะมีหนึ่งองค์ประกอบต่อโดเมน (การเรนเดอร์, เสียง, ฟิสิกส์, เกม - ลอจิก)
Kikaimaru

คำตอบ:


11

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

เมื่อองค์ประกอบด้านสุขภาพตรวจพบว่าเอนทิตีมี 'ตาย' มันจะส่งข้อความ 'ฉันตาย' เป็นความรับผิดชอบขององค์ประกอบภาพเคลื่อนไหวเพื่อตอบสนองต่อข้อความนี้โดยการเล่นภาพเคลื่อนไหวที่เหมาะสม

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


โอเคมันสมเหตุสมผลแล้ว แต่ใครบอกว่า "รัฐ" เช่น "ตาย" หรือ "พอร์ทัล - เสีย - แตก" ฯลฯ ส่วนประกอบหรือเครื่องมือ? เนื่องจากการเพิ่มสถานะ 'คนตาย' ให้กับสิ่งที่ไม่เคยมีส่วนร่วมด้านสุขภาพที่แนบมาดูเหมือนจะเสียฉัน ฉันเดาว่าฉันจะดำน้ำและเริ่มทดสอบโค้ดและดูว่าอะไรใช้งานได้
hayer

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

แค่อยากรู้อยากเห็นคุณจะจัดการกับ MovementComponent อย่างไร? เมื่อตรวจพบอินพุตก็ต้องเพิ่มความเร็วใน PositionComponent ข้อความจะเป็นอย่างไร
Tips48

8

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

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


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

Okey ตอนนี้ฉันหลงทางจริงๆ .. "ในทางตรงกันข้ามใน ES ถ้าคุณมี 100 หน่วยในสนามรบแต่ละอันที่แสดงโดย Entity คุณก็จะมีสำเนาของแต่ละวิธีที่สามารถเรียกใช้บนหน่วย - เพราะไม่มี เอนทิตีไม่มีวิธีการและส่วนประกอบไม่มีวิธีการแทนคุณมีระบบภายนอกสำหรับแต่ละด้านและระบบภายนอกนั้นมีวิธีการทั้งหมดที่สามารถเรียกใช้บนเอนทิตีที่มีส่วนประกอบที่ทำเครื่องหมายว่าเข้ากันได้กับสิ่งนี้ ระบบ." ข้อมูลใน GunComponent ถูกเก็บไว้ที่ไหน? ชอบปัดเศษ ฯลฯ หากเอนทิตีทั้งหมดแชร์องค์ประกอบเดียวกัน
แฮเยอร์

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

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

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

6

ในรหัสของคุณคุณสามารถมีวิธี (ฉันใช้พวกเขาอาจมีวิธีอื่น ๆ อยู่) เพื่อทราบว่าวัตถุเปลี่ยนสถานะ:

  1. ส่งข้อความ.
  2. อ่านข้อมูลโดยตรงจากส่วนประกอบ

1) มีการตรวจสอบเพื่อดูว่า AnimationComponent มีการแนบหรือไม่ (ทั้งในรหัสส่วนประกอบหรือด้านเครื่องยนต์)

สำหรับสิ่งนี้ฉันใช้, 1. ฟังก์ชั่น HasComponent ของ GameObject, หรือ 2. เมื่อคุณแนบส่วนประกอบคุณสามารถตรวจสอบการพึ่งพาในฟังก์ชั่นการสร้างบางอย่าง, หรือ 3. ถ้าฉันรู้ว่าวัตถุนั้นมีองค์ประกอบนี้, ฉันแค่ใช้มัน

2) มีส่วนประกอบที่ต้องใช้ส่วนประกอบอื่น ๆ แต่ดูเหมือนว่าจะต่อสู้กับการออกแบบส่วนประกอบทั้งหมด

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

3) เขียนเช่น HealthWithAnimationComponent, HealthNoAnimationComponent และ soo on ซึ่งดูเหมือนว่าจะต่อสู้กับแนวคิดการออกแบบองค์ประกอบทั้งหมดอีกครั้ง

มันเป็นความคิดที่ไม่ดีที่จะเขียนองค์ประกอบดังกล่าว ในแอปของฉันฉันสร้างองค์ประกอบสุขภาพที่เป็นอิสระมากที่สุด ตอนนี้ฉันกำลังคิดเกี่ยวกับรูปแบบการสังเกตการณ์บางอย่างที่แจ้งสมาชิกเกี่ยวกับเหตุการณ์เฉพาะ (เช่น "hit", "heal" เป็นต้น) ดังนั้น AnimationComponent จะต้องตัดสินใจด้วยตัวเองเมื่อเล่นภาพเคลื่อนไหว

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


1
ดีgoogle.no/… @ สไลด์ 16
hayer

@Bobenko โปรดให้ลิงก์ไปยังบทความเกี่ยวกับ CBES ฉันก็น่าสนใจเช่นกัน;)
Edward83

1
และlambdor.net/?p=171 @ ด้านล่างนี่เป็นบทสรุปของคำถามของฉันจะกำหนดฟังก์ชันการทำงานที่แตกต่างกันอย่างไรในแง่ขององค์ประกอบที่ซับซ้อนและไม่ใช่องค์ประกอบพื้นฐาน องค์ประกอบพื้นฐานที่สุดคืออะไร ส่วนประกอบพื้นฐานแตกต่างจากฟังก์ชั่นบริสุทธิ์อย่างไร? คอมโพเนนต์ที่มีอยู่จะสื่อสารกับข้อความใหม่จากส่วนประกอบใหม่ได้อย่างไร อะไรคือจุดสนใจของข้อความที่ส่วนประกอบไม่รู้จัก? เกิดอะไรขึ้นกับโมเดลอินพุท - โปรเซส - เอาท์พุทหลังจากทั้งหมด?
ว่าจ้าง

1
นี่เป็นคำตอบที่ดีสำหรับ CBES stackoverflow.com/a/3495647/903195บทความส่วนใหญ่ที่ฉันวิจัยมาจากคำตอบนี้ ฉันเริ่มต้นและสร้างแรงบันดาลใจกับcowboyprogramming.com/2007/01/05/evolve-your-heirachyจากนั้นใน Gems 5 (เท่าที่ฉันจำได้) มีบทความดีๆพร้อมตัวอย่าง
Yevhen

แต่สิ่งที่เกี่ยวกับแนวคิดการเขียนโปรแกรมฟังก์ชั่นปฏิกิริยาอื่นสำหรับฉันคำถามนี้ยังคงเปิดอยู่ แต่สำหรับคุณอาจเป็นทิศทางที่ดีสำหรับการวิจัย
Yevhen

3

มันเหมือนกับ Michael, Patrick Hughes และ Blecki กล่าว การแก้ปัญหาเพื่อหลีกเลี่ยงการเคลื่อนย้ายปัญหาโดยรอบคือการละทิ้งอุดมการณ์ที่ทำให้เกิดปัญหาตั้งแต่แรก

มันน้อยกว่า OOD และอื่น ๆ เช่นการเขียนโปรแกรมฟังก์ชั่น เมื่อฉันเริ่มการทดสอบด้วยการออกแบบโดยใช้ส่วนประกอบฉันพบปัญหานี้ตามถนน ฉันค้นหาเพิ่มเติมและพบว่า "การเขียนโปรแกรมแบบโต้ตอบปฏิกิริยาตอบสนอง" เป็นวิธีแก้ปัญหา

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

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

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