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


30

ฉันกำลังใช้ชุดตัวเลือกของระบบเอนทิตีที่มี:

  • ระดับ Entityที่มีน้อยกว่าประชาชนที่ผูกส่วนประกอบเข้าด้วยกัน

  • กลุ่มของคลาสคอมโพเนนต์ที่ไม่มี "ตรรกะของคอมโพเนนต์" ซึ่งเป็นข้อมูลเท่านั้น

  • กลุ่มของคลาสระบบ (aka "ระบบย่อย", "ผู้จัดการ") สิ่งเหล่านี้ทำการประมวลผลตรรกะเอนทิตีทั้งหมด ในกรณีพื้นฐานส่วนใหญ่ระบบจะทำซ้ำรายการของเอนทิตีที่พวกเขาสนใจและดำเนินการกับแต่ละรายการ

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

ตัวแปรเริ่มต้นของการจัดการข้อความระบบมีดังนี้:

  1. เรียกใช้การอัปเดตในแต่ละระบบเกมตามลำดับ
  2. หากระบบทำบางสิ่งบางอย่างกับองค์ประกอบและการกระทำนั้นอาจเป็นที่สนใจของระบบอื่น ๆ ระบบจะส่งข้อความที่เหมาะสม (ตัวอย่างเช่นการเรียกระบบ

    messageChannel.Broadcast(new EntityMovedMessage(entity, oldPosition, newPosition))

    เมื่อใดก็ตามที่มีการย้ายเอนทิตี)

  3. แต่ละระบบที่สมัครรับข้อความที่ระบุจะได้รับวิธีการจัดการข้อความ

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

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

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

ในบางกรณีมันทำให้เกิดปัญหาเนื่องจากเนื้อหาของเซลล์ (รายการทั่วไปของวัตถุเอนทิตีใน C #) ได้รับการแก้ไขในขณะที่มันถูกทำซ้ำมากกว่าจึงทำให้เกิดข้อยกเว้นที่จะถูกโยนโดย iterator

ดังนั้น ... ฉันจะป้องกันไม่ให้ระบบการชนถูกขัดจังหวะในขณะที่ตรวจสอบการชนได้อย่างไร

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

สิ่งที่ฉันได้ลอง:

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

แก้ไข - ตอบคำถามข้อเสนอแนะ:

  • ใครจะแก้ไขเนื้อหาของเซลล์ในขณะที่ระบบการชนกันทำซ้ำมัน?

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

  • คุณไม่สามารถทำงานกับคิวข้อความที่ส่งออกทั่วโลกได้หรือไม่

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

public void Update(int deltaTime)
{   
    m_messageQueue.Enqueue(new TimePassedMessage(deltaTime));
    while (m_messageQueue.Count > 0)
    {
        Message message = m_messageQueue.Dequeue();
        this.Broadcast(message);
    }
}

private void Broadcast(Message message)
{       
    if (m_messageListenersByMessageType.ContainsKey(message.GetType()))
    {
        // NOTE: all IMessageListener objects here are systems.
        List<IMessageListener> messageListeners = m_messageListenersByMessageType[message.GetType()];
        foreach (IMessageListener listener in messageListeners)
        {
            listener.ReceiveMessage(message);
        }
    }
}

โค้ดมีลักษณะดังนี้ (สมมติว่าไม่ใช่กรอบเกมแรก):

  1. ระบบเริ่มการประมวลผล TimePassedMessage
  2. InputHandingSystemแปลงการกดปุ่มเป็นการกระทำเอนทิตี (ในกรณีนี้ลูกศรซ้ายจะเปลี่ยนเป็นการกระทำของ MoveWest) การกระทำของเอนทิตีถูกเก็บไว้ในส่วนประกอบของ ActionExecutor
  3. ActionExecutionSystemในการตอบสนองต่อการกระทำของนิติบุคคลเพิ่ม MovementDirectionChangeRequestedMessage ไปยังจุดสิ้นสุดของคิวข้อความ
  4. MovementSystemย้ายตำแหน่งเอนทิตีตามข้อมูลส่วนประกอบ Velocity และเพิ่มข้อความ PositionChangedMessage ไปยังจุดสิ้นสุดของคิว การเคลื่อนที่ทำได้โดยใช้ทิศทางการเคลื่อนที่ / ความเร็วของเฟรมก่อนหน้า (สมมุติว่าทิศเหนือ)
  5. ระบบหยุดการประมวลผล TimePassedMessage
  6. ระบบเริ่มประมวลผล MovementDirectionChangeRequestedMessage
  7. MovementSystemเปลี่ยนความเร็ว / ทิศทางการเคลื่อนย้ายเอนทิตีตามที่ร้องขอ
  8. ระบบหยุดประมวลผล MovementDirectionChangeRequestedMessage
  9. ระบบเริ่มประมวลผล PositionChangedMessage
  10. CollisionDetectionSystemตรวจพบว่าเนื่องจากเอนทิตีย้ายมันวิ่งเข้าไปในเอนทิตี้อื่น (รถถังเข้าไปในกำแพง) มันเพิ่ม CollisionOccuredMessage ให้กับคิว
  11. ระบบหยุดประมวลผล PositionChangedMessage
  12. ระบบเริ่มการประมวลผล CollisionOccuredMessage
  13. CollidingRigidBodySeparationSystemตอบสนองต่อการชนโดยการแยกถังและผนัง เนื่องจากผนังคงที่เฉพาะถังเท่านั้นที่ถูกย้าย ทิศทางการเคลื่อนไหวของรถถังถูกใช้เป็นตัวบ่งชี้ว่ารถถังมาจากไหน มันจะชดเชยในทิศทางตรงกันข้าม

BUG:เมื่อรถถังย้ายเฟรมนี้มันเคลื่อนที่โดยใช้ทิศทางการเคลื่อนที่จากเฟรมก่อนหน้า แต่เมื่อมันถูกแยกออกทิศทางการเคลื่อนไหวจากเฟรมนี้จะถูกใช้แม้ว่ามันจะแตกต่างกันแล้ว นั่นไม่ใช่วิธีที่ควรใช้!

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

  • คุณอาจต้องการอ่าน gamadu.com/artemis เพื่อดูว่าพวกเขาทำอะไรกับ Aspects ซึ่งขั้นตอนด้านปัญหาที่คุณเห็น

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

  • ดูเพิ่มเติมที่: "การสื่อสารของเอ็นติตี้: คิวข้อความ vs เผยแพร่ / สมัครสมาชิก vs สัญญาณ / สล็อต"

ฉันได้อ่านคำถาม gamedev.stackexchange ทั้งหมดเกี่ยวกับระบบนิติบุคคลแล้ว อันนี้ดูเหมือนจะไม่พูดถึงปัญหาที่ฉันเผชิญ ฉันพลาดอะไรไปรึเปล่า?

  • จัดการกับทั้งสองกรณีต่างกันการอัพเดตกริดไม่จำเป็นต้องพึ่งพาข้อความการเคลื่อนไหวเนื่องจากเป็นส่วนหนึ่งของระบบการชน

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


มีบางอย่างที่ไม่ชัดเจนสำหรับฉัน ใครจะแก้ไขเนื้อหาของเซลล์ในขณะที่ระบบการชนกันทำซ้ำมัน?
พอล Manta

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

หากคุณต้องการคงการออกแบบที่ซับซ้อนนี้ไว้คุณต้องทำตาม @RoyT คำแนะนำของมันเป็นวิธีเดียว (โดยไม่มีการส่งข้อความที่ซับซ้อนตามเวลา) เพื่อจัดการกับปัญหาการเรียงของคุณ คุณอาจต้องการอ่านgamadu.com/artemisเพื่อดูว่าพวกเขาทำอะไรกับ Aspects ซึ่งขั้นตอนด้านปัญหาที่คุณเห็น
Patrick Hughes

ดูเพิ่มเติมที่: gamedev.stackexchange.com/questions/1119/…
Crashworks

2
คุณอาจต้องการเรียนรู้ว่าAxumทำได้อย่างไรโดยการดาวน์โหลด CTP และรวบรวมโค้ดบางส่วน - จากนั้นทำการวิศวกรรมย้อนกลับผลลัพธ์ไปยัง C # โดยใช้ ILSpy การส่งข้อความเป็นคุณสมบัติที่สำคัญของภาษานางแบบนักแสดงและฉันมั่นใจว่า Microsoft รู้ว่าพวกเขากำลังทำอะไรอยู่ดังนั้นคุณอาจพบว่าพวกเขาใช้งานได้ดีที่สุด
Jonathan Dickinson

คำตอบ:


12

คุณคงเคยได้ยินเกี่ยวกับรูปแบบการต่อต้านวัตถุของพระเจ้า / บล็อบ ปัญหาของคุณก็คือลูป God / Blob การแก้ไขด้วยระบบส่งข้อความของคุณจะช่วยแก้ปัญหา Band-Aid ได้อย่างดีที่สุดและที่แย่ที่สุดคือเสียเวลาอย่างสมบูรณ์ ในความเป็นจริงปัญหาของคุณไม่มีอะไรเกี่ยวข้องกับการพัฒนาเกมเลย ฉันจับได้ว่าตัวเองพยายามที่จะปรับเปลี่ยนคอลเลกชันในขณะที่วนซ้ำมันหลายครั้งและการแก้ปัญหาก็เหมือนกันเสมอ: แบ่งย่อยแบ่งย่อยแบ่งย่อย

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

for each possible collision
    check for collision
    handle collision
    modify collision world to reflect change // exception happens here

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

for each possible collision
    check for collision, record it if a collision occurs

for each found collision
    handle collision, record the collision response (delete object, ignore, etc.)

for each collision response
    modify collision world according to response

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

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


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

11

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

ฉันจะบอกว่าคุณต้องการข้อความสองประเภท: ซิงโครนัสและ Asynchonous ข้อความที่ซิงโครนัสได้รับการจัดการทันทีในขณะที่อะซิงโครนัสได้รับการจัดการไม่ได้อยู่ในกรอบสแต็กเดียวกัน (แต่อาจได้รับการจัดการในเฟรมเกมเดียวกัน) การตัดสินใจที่มักจะทำบนฐาน "ต่อคลาสข้อความ" เช่น " ข้อความEnemyDiedทั้งหมดเป็นแบบอะซิงโครนัส"

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

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

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

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

ฉันจะป้องกันไม่ให้ระบบการชนถูกขัดจังหวะในขณะที่ตรวจสอบการชนได้อย่างไร

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

ปัญหา: หากระบบ A เพิ่มข้อความไปยังคิว B ของระบบมันจะทำงานได้ดีถ้าระบบ B หมายถึงได้รับการปรับปรุงในภายหลังกว่าระบบ A (ในเฟรมเกมเดียวกัน); มิฉะนั้นจะทำให้ข้อความประมวลผลเฟรมเกมถัดไป (ไม่เป็นที่ต้องการสำหรับบางระบบ)

ง่าย:

ในขณะที่ (! queue.empty ()) {que.pop (). handle (); }

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


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

5

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

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

ตัวอย่างเช่น CollisionSystem จะสร้างบัฟเฟอร์ที่เต็มไปด้วยเหตุการณ์การชนกัน ระบบอื่นที่รันหลังจากการชนกันสามารถทำซ้ำผ่านรายการและประมวลผลตามที่ต้องการ

มันเก็บรักษาลักษณะการทำงานแบบขนานที่เน้นข้อมูลของการออกแบบ ECS โดยไม่มีความซับซ้อนของการลงทะเบียนข้อความหรือสิ่งที่คล้ายกัน เฉพาะระบบที่สนใจเกี่ยวกับประเภทของเหตุการณ์เฉพาะที่ทำซ้ำผ่านคิวสำหรับประเภทนั้นและการทำซ้ำแบบ single-pass ซ้ำในคิวข้อความนั้นมีประสิทธิภาพเท่ากับที่คุณจะได้รับ

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


1
+1 แต่ฉันไม่สามารถเชื่อได้ว่าวิธีการนี้ไม่มีข้อเสีย สิ่งนี้ไม่ได้บังคับให้เราต้องพึ่งพาการเข้ารหัสระหว่างระบบหรือไม่ หรือบางทีการพึ่งพาซึ่งกันและกันเหล่านี้มีขึ้นเพื่อ hardcoded ไม่ทางใดก็ทางหนึ่ง?
Patryk Czachurski

2
@Daedalus: ถ้าตรรกะของเกมต้องการการอัพเดททางฟิสิกส์เพื่อทำตรรกะที่ถูกต้องคุณจะไม่พึ่งพามันได้อย่างไร แม้จะเป็นรุ่น pubsub คุณต้องสมัครสมาชิกประเภทข้อความดังกล่าวอย่างชัดเจนซึ่งสร้างขึ้นโดยระบบอื่นบางระบบเท่านั้น การหลีกเลี่ยงการพึ่งพานั้นยากและส่วนใหญ่จะหาชั้นที่เหมาะสม ยกตัวอย่างเช่นกราฟิกและฟิสิกส์นั้นมีความเป็นอิสระ แต่จะมีเลเยอร์กาวในระดับที่สูงขึ้นซึ่งจะทำให้แน่ใจว่าการอัพเดทการจำลองทางฟิสิกส์แบบสอดแทรกนั้นจะแสดงในกราฟิกและอื่น ๆ
Sean Middleditch

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