จะอัพเดทสถานะเอนทิตีและแอนิเมชั่นในเกมที่อิงองค์ประกอบได้อย่างไร


10

ฉันกำลังพยายามออกแบบระบบเอนทิตีที่อิงองค์ประกอบเพื่อการเรียนรู้ (และใช้ในภายหลังในบางเกม) และฉันมีปัญหาบางอย่างเมื่อต้องอัพเดตสถานะเอนทิตี

ฉันไม่ต้องการให้มีการอัปเดตวิธี () ภายในคอมโพเนนต์เพื่อป้องกันการพึ่งพาระหว่างคอมโพเนนต์

สิ่งที่ฉันมีอยู่ในใจในขณะนี้คือส่วนประกอบเก็บข้อมูลและส่วนประกอบการปรับปรุงระบบ

ดังนั้นถ้าฉันมีเกม 2D ง่าย ๆ ที่มีบางหน่วยงาน (เช่นผู้เล่น, ศัตรู 1, ศัตรู 2) ที่มีองค์ประกอบการแปลง, การเคลื่อนไหว, สถานะ, ภาพเคลื่อนไหวและการแสดงผลฉันคิดว่าฉันควรจะมี:

  • MovementSystem ที่จะทำการเคลื่อนย้ายส่วนประกอบการเคลื่อนไหวทั้งหมดและอัพเดทส่วนประกอบของรัฐ
  • และ RenderSystem ที่อัพเดทองค์ประกอบภาพเคลื่อนไหว (องค์ประกอบภาพเคลื่อนไหวควรมีภาพเคลื่อนไหวหนึ่งภาพ (เช่นชุดของเฟรม / พื้นผิว) สำหรับแต่ละรัฐและอัปเดตหมายถึงการเลือกภาพเคลื่อนไหวที่สอดคล้องกับสถานะปัจจุบัน (เช่นการกระโดด, moving_left ฯลฯ ) และ อัปเดตดัชนีเฟรม) จากนั้น RenderSystem จะอัปเดตส่วนประกอบ Render ด้วยพื้นผิวที่สอดคล้องกับเฟรมปัจจุบันของ Animation ของแต่ละกิจการและแสดงทุกอย่างบนหน้าจอ

ฉันเห็นการใช้งานบางอย่างเช่นกรอบงานของ Artemis แต่ฉันไม่รู้วิธีแก้ปัญหานี้:

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

  • ผู้เล่น: "ไม่ได้ใช้งาน", "moving_right", "กระโดด"
  • ศัตรู 1: "moving_up", "moving_down"
  • ศัตรู 2: "moving_left", "moving_right"

อะไรคือวิธีการที่ได้รับการยอมรับมากที่สุดเพื่ออัพเดทสถานะปัจจุบันของแต่ละเอนทิตี สิ่งเดียวที่ฉันคิดได้คือการมีระบบแยกต่างหากสำหรับแต่ละกลุ่มของเอนทิตีและแยกสถานะและส่วนประกอบภาพเคลื่อนไหวดังนั้นฉันจะมี PlayerState, PlayerAnimation, Enemy1State, Enemy1Animation ... PlayerMovementSystem, PlayerRenderingSystem ... แต่ฉันคิดว่านี่เป็นสิ่งที่ไม่ดี วิธีการแก้ปัญหาและทำลายวัตถุประสงค์ของการมีระบบที่ใช้องค์ประกอบ

อย่างที่คุณเห็นฉันค่อนข้างหลงทางที่นี่ดังนั้นฉันจึงขอขอบคุณสำหรับความช่วยเหลือ

แก้ไข:ฉันคิดว่าวิธีแก้ปัญหาในการทำให้งานนี้เป็นไปตามที่ฉันตั้งใจไว้:

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

ตอนนี้ฉันกำลังพยายามหาวิธีออกแบบส่วนประกอบทั้งสองนี้ให้เพียงพอเพื่อให้ฉันสามารถนำกลับมาใช้ใหม่ได้ อาจมี UID สำหรับแต่ละรัฐ (เช่นการเดินการวิ่ง ... ) และการจัดเก็บภาพเคลื่อนไหวในแผนที่ไปยัง AnimationComponent ที่รหัสตัวระบุนี้เป็นทางออกที่ดี?


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

@ Byte56 ใช่ฉันอ่านมันเมื่อหลายชั่วโมงก่อน วิธีแก้ปัญหาที่คุณแนะนำมีความคล้ายคลึงกับแนวคิดที่ฉันเคยเปิดเผยที่นี่ แต่ปัญหาของฉันมาเมื่อ StateComponent และ AnimationComponent นั้นไม่เหมือนกันสำหรับเอนทิตีทั้งหมดที่ใช้ระบบ ฉันควรแยกระบบนั้นออกเป็นระบบที่เล็กกว่าซึ่งประมวลผลกลุ่มของเอนทิตีที่มีสภาวะและภาพเคลื่อนไหวที่เหมือนกันหรือไม่? (ดูส่วนสุดท้ายของการโพสต์เดิมของฉันสำหรับการชี้แจงดีกว่า)
miviclin

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

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

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

คำตอบ:


5

IMHO Movementส่วนประกอบควรมีสถานะปัจจุบัน ( Movement.state) และAnimationส่วนประกอบควรสังเกตการเปลี่ยนแปลงMovement.stateและอัปเดตแอนิเมชันปัจจุบัน ( Animation.animation) ตามนั้นโดยใช้การค้นหารหัสสถานะเป็นภาพเคลื่อนไหวอย่างง่าย (ตามที่แนะนำในตอนท้ายของ OP) เห็นได้ชัดว่าวิธีการนี้จะขึ้นอยู่กับAnimationMovement

โครงสร้างทางเลือกจะต้องมีStateองค์ประกอบทั่วไปซึ่งAnimationสังเกตและMovementปรับเปลี่ยนซึ่งโดยทั่วไปจะเป็นแบบจำลองมุมมอง - ตัวควบคุม (สถานะภาพเคลื่อนไหวการเคลื่อนไหวในกรณีนี้)

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

โชคดี.


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

กรณีแรก: Movementจะควบคุม State (ไม่สังเกต) กรณีสุดท้าย: ใช่Movementจะทำเช่นentity.dispatchEvent(...);นั้นและส่วนประกอบอื่น ๆ ทั้งหมดที่ฟังเหตุการณ์ประเภทนั้นจะได้รับ ประสิทธิภาพนั้นแย่กว่าการโทรด้วยวิธีบริสุทธิ์ แต่ไม่มากนัก คุณสามารถรวมวัตถุเหตุการณ์เช่น Btw คุณไม่ต้องใช้เอนทิตีเป็น "โหนดเหตุการณ์" คุณสามารถใช้ "event bus" โดยเฉพาะได้เช่นกันทำให้คลาสเอนทิตี้ของคุณหมดไป
Torious

2

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

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

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

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

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

ดังนั้นฉันจะเริ่มต้นด้วยองค์ประกอบ 'รัฐ': PlayerStateComponent, Enemy1State, Enemy2State องค์ประกอบของรัฐจะดูแลการเปลี่ยนแปลงสถานะในเวลาที่เหมาะสม สถานะเป็นสิ่งที่วัตถุของคุณจะมีอยู่มากดังนั้นมันจึงสามารถอยู่ใน GameObject

จากนั้นจะมี AnimationCompoment นี่จะมีพจนานุกรมภาพเคลื่อนไหวที่เป็นของรัฐ ในการอัปเดต () ให้เปลี่ยนภาพเคลื่อนไหวหากสถานะเปลี่ยนแปลง

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

การใช้งานที่ฉันเสนอนั้นค่อนข้างไร้เดียงสา แต่นี่คือการปรับปรุงที่เป็นไปได้เมื่อคุณเพิ่มการใช้งานมากขึ้น:

  • แทนที่ตัวแปร GameObject ด้วยพจนานุกรม แต่ละองค์ประกอบใช้พจนานุกรมเพื่อเก็บค่า (ตรวจสอบให้แน่ใจว่าได้จัดการการชนอย่างถูกต้อง ... )
  • แทนที่พจนานุกรมของค่าธรรมดาด้วยการอ้างอิงแทน: class FloatVariable () {ค่าสาธารณะ [... ]}
  • แทนที่จะเป็นองค์ประกอบหลายสถานะให้สร้าง StateComponent ทั่วไปซึ่งคุณสามารถสร้างเครื่องสถานะแปรผัน คุณต้องมีชุดเงื่อนไขทั่วไปที่รัฐสามารถเปลี่ยนแปลงได้: การกดปุ่ม, การป้อนข้อมูลเมาส์, การเปลี่ยนแปลงตัวแปร (คุณสามารถผูกสิ่งนั้นกับ FloatVariable ด้านบน)

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

0

นอกจากคำตอบของ ADB คุณสามารถใช้http://en.wikipedia.org/wiki/Dependency_injectซึ่งช่วยเมื่อคุณจำเป็นต้องสร้างส่วนประกอบจำนวนมากผ่านการส่งต่อพวกเขาเป็นการอ้างอิงถึงตัวสร้างของพวกเขา เห็นได้ชัดว่าพวกเขายังคงพึ่งพาซึ่งกันและกัน (หากจำเป็นต้องใช้ในฐานรหัสของคุณ) แต่คุณสามารถใส่การพึ่งพานั้นทั้งหมดไว้ในที่เดียวที่มีการติดตั้งการพึ่งพาและส่วนที่เหลือของรหัสของคุณไม่จำเป็นต้องรู้เกี่ยวกับการพึ่งพา

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

สำหรับระบบง่าย ๆ ที่คุณอาจไม่ได้ใช้โดยไม่ต้องใช้ DI หรือโค้ดที่สะอาดคลาส RenderingSystem ของคุณฟังดูเหมือนคุณจะต้องเรียกมันว่าเป็นแบบสแตติกหรืออย่างน้อยก็ให้มันมีอยู่ในแต่ละองค์ประกอบซึ่งค่อนข้างทำให้มันขึ้นอยู่กับกันและกัน หากคุณสนใจวิธีการที่สะอาดกว่านี้ให้ตรวจสอบลิงค์ของลิงค์ DI wiki ด้านบนและอ่านเกี่ยวกับ Clean Code: http://clean-code-developer.com/


ฉันมีหนึ่งระบบที่ส่วนประกอบค่อนข้างพึ่งพาซึ่งกันและกัน ฉันใช้การฉีดที่ต้องพึ่งพาอาศัยกันอย่างหนักและถึงแม้ว่าฉันจะชอบมันมากกว่าลำดับชั้นลึก ๆ ฉันพยายามสร้างมันขึ้นมาใหม่เพื่อหลีกเลี่ยงการเชื่อมต่อส่วนประกอบถ้ามันเป็นไปได้ ฉันจะไม่เรียกอะไรแบบคงที่ ฉันจะมี ComponentManager ที่ทุกระบบมีการเข้าถึง (ทุกระบบควรมีการอ้างอิงถึง) และ RendererSystem จะได้รับส่วนประกอบภาพเคลื่อนไหวทั้งหมดจากตัวจัดการคอมโพเนนต์และแสดงสถานะปัจจุบันของภาพเคลื่อนไหวแต่ละรายการ
miviclin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.