วัตถุในเกม 2D ควรแสดงตัวหรือไม่?


16

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

ทำไมคนหนึ่งถึงดีกว่าอีกคนหนึ่ง?

ขอบคุณ


ทำไมคุณคิดว่าการผกผันดีกว่า?

1
@Martin เพราะวัตถุจะบอกเป็นนัยว่าบิตแมปที่จะใช้ต่อไปดังนั้นทำไมไม่เพียงแค่ทำ object-> render ()
jmasterx

คำตอบ:


11

ข้อควรพิจารณาสองประการ:

  • ตามที่คุณได้กล่าวถึงเทพดาแต่ละตัวจะต้อง "บอกใบ้" เกี่ยวกับบิตแมปที่จะใช้ แต่ถ้าเอนทิตีต้องแสดงตัวเอง 'คำใบ้' นั้นจะเป็นอะไร? หากเป็นการอ้างอิงถึงบิตแมปสไปรต์ชีท ฯลฯ ... สำหรับแต่ละสไปรต์คุณอาจต้องใช้หน่วยความจำมากกว่าที่จำเป็นหรือมีปัญหาในการจัดการหน่วยความจำนั้น ข้อดีของตัวเรนเดอร์ที่แยกต่างหากคือคุณมีคลาสเพียงหนึ่งชั้นที่รับผิดชอบการจัดการสินทรัพย์ใด ๆ ที่กล่าวว่าในเกมต่อสู้เหมือน SF2 คุณอาจมีเพียงสองสไปรต์;)

  • ดังที่กล่าวไว้ที่อื่นเมื่อใดก็ตามที่คุณต้องการเปลี่ยน API กราฟิกของคุณคุณจะต้องเปลี่ยนรหัสสำหรับ Sprite ทั้งหมดของคุณ

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

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

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

และฉันไม่รู้ว่าจะใช้กับ 3D ได้หรือไม่ (ซึ่งความคิดของ meshes และตัวแปรพิกัดที่คุณจะใช้อาจเชื่อมโยงกับ 3D API ของคุณได้ในขณะที่ x, y, h, w เป็นอิสระจาก 2D ใด ๆ API)

หวังว่านี่จะช่วยได้


11

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

ข้อดีของการเรนเดอร์แบบรวมศูนย์:

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

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

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


เกี่ยวกับการจัดเรียง z ถ้าวัตถุวาดตัวเองไม่สามารถตัดสินระบบเกี่ยวกับคำสั่งเรียกวิธีการวาดได้ ฉันหมายถึงการรวมศูนย์และไม่รวมศูนย์ดูเหมือนจะไม่สร้างความแตกต่างเกี่ยวกับการสั่งซื้อ z
GorillaApe

3

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

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

ไชโยเดวิด


แต่ในแง่นั้นผู้กำกับก็ไม่สามารถพูดได้ว่า acton-> setVisible (false); ?
jmasterx

แม้แต่ในกรณี setVisible (false) มันเป็นเอนทิตีภายนอกที่ทำการเรนเดอร์โดยการตรวจสอบตัวแปรที่มองเห็นของนักแสดงและทำการเรนเดอร์เฉพาะในกรณีที่เป็นจริง
Nav

การทำให้นักแสดงล่องหนไม่ได้ลบออกจากฉาก นอกจากนี้ยังต้องหยุดการมีส่วนร่วมในการชนเป็นต้น
finnw

3

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


3

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


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

2

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

ขึ้นอยู่กับสิ่งที่วัตถุของคุณกำลังทำจริง ๆ เมื่อคุณเรียกใช้ render () ตราบใดที่พวกเขาเพิ่งเรียกเมธอดไปรอบ ๆ เอ็นจิ้นกราฟิคของคุณมันก็ใช้ได้ดีเนื่องจาก logics <-> ความแตกต่างของกราฟิกจะยังคงได้รับ

ตัวอย่างเช่นหากวิธีการเรนเดอร์ () ของคุณนั้นเป็นวิธีการอำนวยความสะดวกและเป็นดังนี้:

void MyClass::render(const Graphics &g)
{
    g.draw(this);
}

หรือ

void MyClass::render()
{
   mySprite->render();
}

หรือ

void MyClass::render()
{
    mySprite->UseShader(thatshader);
    mySprite->render();
}

หรือใกล้เคียงกับที่ฉันไม่คิดว่ามันเป็นปัญหาใด ๆ

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