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


16

คำถามของฉันคือ:

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

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

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

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

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

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

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

ใครบ้างมีความคิดอื่น ๆ เกี่ยวกับวิธีการทำเช่นนี้?

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


6
ฉันทำสิ่งนี้: ฉันมีหน้าจอ MenuScreen PauseScreen GameScreen แต่ละหน้าจอสามารถสร้างโลกของตัวเอง (คอนเทนเนอร์สำหรับเอนทิตี) และระบบ (เช่น RenderingSystem) แล้วใน GameScreen ฉันสร้างโลกเอนทิตีด้วย CameraComponent และตั้ง CameraComponent พื้นหลังหน้าจอ วิธีนี้ฉันสามารถเพิ่ม InventoryScreen ที่จะมีเอนทิตีและระบบของตัวเอง (เช่นตัวเรนเดอร์ที่ง่าย) สามารถป้อนข้อมูลจากหน้าจอสู่โลกดังนั้นผู้ใช้งานของคุณจะตัดสินใจว่าจะส่งผ่านข้อมูลไปยังหน้าจอ (ถ้ามุ่งเน้นการมองเห็น ฯลฯ ) และที่จะผ่านการป้อนข้อมูลไปยังโลกและหน่วยงาน
Kikaimaru


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

1
ตกลงพิจารณาพวกเขาที่เกี่ยวข้องแล้ว คำถามที่ดี.
MichaelHouse

1
สิ่งอื่นที่ต้องคำนึงถึงซึ่งสร้างความรำคาญให้กับระบบที่ใช้องค์ประกอบของฉันในอดีต: multi-layer UI กล่องโต้ตอบปรากฏขึ้นด้านบนของโลกหรือหน้าจอหลายระดับ มันเกิดขึ้นมาแล้วในทุก ๆ เกมที่ฉันทำดังนั้นฉันจะบอกให้คุณพิจารณาผู้อนุมัติที่สามารถแก้ปัญหานั้นได้
ADB

คำตอบ:


14

สิ่งที่มักใช้เป็นสื่อกลาง Intent Systemซึ่งเป็นนามธรรมอินพุตและติดตามบริบทและนักเล่นเกมที่เกี่ยวข้อง

ระบบ Intent จะหยุดการส่งสัญญาณอินพุตเมื่อการจำลองหยุดชั่วคราว นอกจากนี้ยังจัดการการแมประหว่างเหตุการณ์ของตัวควบคุมและ intents (เลื่อนไปในทิศทาง, วิ่ง, ยิง, โหลดซ้ำ ... )

วิธีนี้ conponents อื่น ๆ ของคุณไม่ได้ขึ้นอยู่กับ gamepads / input ที่เฉพาะเจาะจง (BUTTON_A, BUTTON_B และ BUTTON_X, BUTTON_O ... ) แต่พวกมันตอบสนองต่อ intents เดียวกัน (IntentRun, IntentReload ... )

ข้อดีอีกอย่างคือระบบความตั้งใจสามารถรับรู้ถึงตัวควบคุมที่มีอยู่ถูกเพิ่ม / ลบออกได้เนื่องจากมันสามารถส่งความตั้งใจไปยังผู้สมัครสมาชิกใด ๆ ได้แม้จะอยู่นอกการจำลองที่คุณสามารถจัดการกับเจตนาเช่นAddPlayer(controllerID)นั้นได้

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

คุณสามารถจัดการ Intent Contexts ซึ่งจะสร้าง intents เมื่อแนบกับระบบ

บริบทสามารถจัดลำดับความสำคัญเช่น:

  • SimulationAvailableContext ส่งความตั้งใจไปที่การจำลองขณะที่มันพร้อมใช้งาน (แต่ไม่ได้ทำงาน) ตัวอย่างเช่นย้ายกล้องซูมเข้าซูมออกเพิ่ม / ลบผู้เล่น ...
  • SimulationRunningContext ส่งความตั้งใจไปที่การจำลองในขณะที่มันไม่ได้หยุดเล่นย้ายส่งหน่วยไปยังตำแหน่งยิง ...

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

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

วิธีหนึ่งที่มักใช้ในการเล่น / หยุดการจำลองเกมโดยไม่ทำลายการปรับปรุงที่ไม่เกี่ยวข้องกับการจำลองคือการใช้ชุดเวลาที่แตกต่างกัน กล่าวคือGenericSystem::onTime(Long time, Long deltaTime, Long simTime, Long simDeltaTime)กล่าวคือ

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


ฉันชอบความจริงที่ว่าสิ่งนี้ไม่จำเป็นต้องเรียกใช้ฟังก์ชัน "State Changed" ในทุกหน่วยงาน คุณต้องกังวลเกี่ยวกับความตั้งใจผิดที่ถูกส่งไปในเวลาที่ผิด แต่ฉันคิดว่ามันดีกว่าทางเลือกอื่น
โทมัสมาร์เนล

เอนทิตีของคุณสามารถเพิกเฉยเช่น Intent เช่น Jump ในขณะที่สถานะของพวกเขาไม่อนุญาตให้กระโดด (เช่นไม่แตะพื้น) แต่พวกเขาไม่ต้องกังวลเกี่ยวกับการรับเจตนาเช่นนั้นขณะที่เกมหยุดชั่วคราว
โคโยตี้

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

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

เฮ้ @ โคโยตี้ระบบนี้ฟังดูน่าสนใจมาก คุณสามารถให้ข้อมูลเพิ่มเติมโดยตอบคำถามนี้ได้ไหม ขอบคุณ!
pek

2

วิธีการเกี่ยวกับการสร้างระบบเหตุการณ์ระดับโลกแล้วมีองค์ประกอบฟังเหตุการณ์สำหรับแต่ละกิจการของคุณ? หลังจากเหตุการณ์ "Game State Change" คุณสามารถเล่นซอกับส่วนประกอบแต่ละรายการสำหรับแต่ละเอนทิตีเฉพาะ

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

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

สิ่งที่ฉันเพิ่งอธิบายนั้นเป็นตัวอย่างที่ใช้งานได้จริงของโซลูชันที่สี่ของคุณ

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