ฉันควรพิจารณาอะไรเมื่อออกแบบระบบตัวจัดการเหตุการณ์


9

ฉันพัตต์กับพื้นฐานของ Java engine engine และฉันมาถึงจุดที่ฉันพร้อมที่จะเพิ่มในระบบ Event Manager

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

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

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

ฉันคิดว่าฉันต้องเก็บชุดของเหตุการณ์ที่สมัครเป็นไปได้แต่ละรายการ - การเพิ่มและลบวัตถุเกมออกจากรายการตามต้องการ ฉันคิดว่ามันควรจะเป็นไปได้ที่จะสร้างคิวของเหตุการณ์ที่ต้องออกอากาศซึ่งในกรณีนี้ฉันสามารถเพิ่ม "EventManager.Update ()" ในเกมหลักและมีUpdate()วิธีออกอากาศกิจกรรมที่เกิดขึ้นในตอนท้าย ของแต่ละเฟรม ในที่สุดวัตถุแต่ละอันจะมีHandleEvent(Event e)วิธีการที่พวกเขาสามารถแยกวิเคราะห์และตอบสนองได้อย่างเหมาะสม


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


2
gamedev.stackexchange.com/questions/7718/…นี่คือ Q / AI ที่ให้ไว้ก่อนหน้านี้ที่สามารถช่วยคุณเริ่มต้นได้
James

@James Ah - ดูเหมือนลิงค์ที่ดี ขอบคุณ! ฉันคิดว่าฉันพลาดไปก่อนหน้านี้
Raven Dreamer

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

คำตอบ:


6

สิ่งนี้สามารถทำได้ง่ายอย่างที่คุณต้องการ

for each object in the subscriber list:
    object.notify(this event) // (or 'HandleEvent' if you prefer)

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


3
+1 สำหรับ "อย่าพยายามทำสิ่งที่ X ควรทำ - ทำสิ่งที่คุณต้องการให้ทำ" ในความเป็นจริงอย่าเพิ่มตัวจัดการเหตุการณ์เลยจนกว่าคุณจะรู้สึกว่าคุณต้องการวิธีการเรียกฟังก์ชั่น

@JoeWreschnig โอ้พระเจ้าใช่ =) "หาสิ่งที่คุณต้องการให้ทำ" นี่เป็นหนึ่งในสามของคำแนะนำที่นักพัฒนาควรคำนึงถึง
Patrick Hughes

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

3

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

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

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

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

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

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


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

0

การปฏิเสธความรับผิด

ฉันไม่ใช่โปรแกรมเมอร์ Java แต่ฉันเขียนบทความอธิบายวิธีสร้างระบบเหตุการณ์ใน C89 ซึ่งเป็นหนึ่งในภาษาที่ง่ายที่สุด (IMHO) ลองดูสิ

https://prdeving.wordpress.com/2017/04/03/event-driven-programming-with-c-89/

พื้นฐานของการจัดการเหตุการณ์ค่อนข้างง่าย

  • ลงทะเบียนกิจกรรมด้วยการติดต่อกลับ
  • เหตุการณ์ทริกเกอร์
  • วนรอบผู้ฟังเพื่อดูว่ามีการจับคู่หรือไม่
  • ตัวจัดการไฟถ้าพบ
  • ทำซ้ำ

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

จากนั้นคุณมีกิจกรรมย่อย (ลูปแบบง่าย) ที่ปรากฏเหตุการณ์แรกในสแต็กนั้นพยายามหาตัวจัดการมันและถ้ามีก็ให้รันด้วย params

แน่นอนกิจกรรมย่อยนี้สามารถเรียกใช้เมื่อใดก็ตามที่คุณต้องการเช่นหนึ่งครั้งต่อเฟรมหลังจากที่คุณเรียกUpdate()ใช้ฟังก์ชันของคุณ


-2

สำหรับฟิลด์ EventManager ให้ใช้ตัวแปรแบบคงที่ Singleton สำหรับ EventManager ก็เป็นแนวคิดที่ดีเช่นกัน

วิธีการของคุณฟังดูดี แต่อย่าลืมที่จะทำให้มันปลอดภัย

เป็นการดีที่จะเรียกใช้งาน IO-Events ก่อนหรือหลัง "GameEvent" ดังนั้นในหนึ่งเฟรมทุก ๆ "GameEvent" จะจัดการกับข้อมูลเดียวกัน


"กระทู้บันทึก"? Hmmm
U62

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