ข้อเสียของการใช้ DrawableGameComponent สำหรับทุก ๆ ครั้งของวัตถุในเกมคืออะไร?


25

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

ฉันมักจะไม่สนใจสิ่งต่าง ๆ เช่นนี้มากเกินไป แต่ในกรณีนี้ฉันอยากจะรู้ว่าทำไมคนส่วนใหญ่ที่เห็นได้ชัดเชื่อว่านี่ไม่ใช่วิธีที่จะไป บางทีฉันอาจจะหายไปบางสิ่งบางอย่าง


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

@AndrewRussell ฉันอ่านกระทู้นี้เมื่อไม่นานมานี้ (เนื่องจากคำตอบและคะแนนโหวตบางส่วน) และคิดว่าฉันไม่มีคุณสมบัติที่จะให้ความเห็นว่าคำตอบของคุณถูกต้องหรือไม่ อย่างที่คุณพูด แต่ฉันไม่คิดว่าคำตอบของ VeraShackle ควรเป็นคำตอบที่มี upvotes มากที่สุดดังนั้นฉันจึงทำเครื่องหมายคำตอบของคุณว่าถูกต้องอีกครั้ง
Kenji Kina

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

1
DrawableGameComponentเป็นส่วนหนึ่งของ core XNA API (อีกครั้ง: ส่วนใหญ่ด้วยเหตุผลทางประวัติศาสตร์) โปรแกรมเมอร์สามเณรใช้มันเพราะมันคือ "ที่นั่น" และ "ใช้งานได้" และพวกเขาไม่รู้อะไรเลย พวกเขาเห็นคำตอบของฉันบอกพวกเขาว่า " ผิด " และ - เนื่องจากธรรมชาติของจิตวิทยามนุษย์ - ปฏิเสธสิ่งนั้นและเลือก "อีกด้าน" ซึ่งเกิดขึ้นเป็นคำตอบที่ไม่เถียงโต้แย้งของ VeraShackle; ซึ่งเกิดขึ้นเพื่อรับแรงเพราะฉันไม่ได้โทรออกทันที (ดูความคิดเห็นเหล่านั้น) ฉันรู้สึกว่าการโต้แย้งในที่สุดของฉันยังคงมีเพียงพอ
Andrew Russell

1
ถ้าใครมีความสนใจในการซักถามความถูกต้องของคำตอบของฉันบนพื้นฐานของ upvotes นี้ในขณะที่มันเป็นความจริงที่ (GDSE เป็น aflush กับสามเณรดังกล่าว) คำตอบ VeraShackle ได้มีการจัดการที่จะได้รับทั้งคู่มากขึ้น upvotes กว่าผมในปีที่ผ่านมาไม่ลืม ว่าฉันมีหลายพันมากขึ้น upvotes ทั่วทั้งเครือข่ายส่วนใหญ่ใน XNA ฉันใช้งาน XNA API บนหลายแพลตฟอร์ม และฉันเป็นผู้พัฒนาเกมมืออาชีพที่ใช้ XNA โคตรของคำตอบของฉันไม่มีที่ติ
Andrew Russell

คำตอบ:


22

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

ดังนั้นคุณอาจมีส่วนประกอบเช่นกล้องหรือตัวนับ ... FPS หรือไม่ ... หรือ ...

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

ฉันคิดว่ามันเป็นเพราะเหตุนี้และไม่มีเวลาง่ายๆที่ GUI ถูกดึงมาก่อน XNA 1.0

แต่ API ยังคงใช้งานได้ ... นี่คือสาเหตุที่คุณไม่ควรใช้:

โดยพื้นฐานแล้วสิ่งที่ง่ายที่สุดในการเขียนและอ่านและแก้ไขข้อบกพร่องและบำรุงรักษาในฐานะนักพัฒนาเกม ทำสิ่งนี้ในรหัสการโหลดของคุณ:

player.DrawOrder = 100;
enemy.DrawOrder = 200;

ชัดเจนน้อยกว่าการทำสิ่งนี้:

virtual void Draw(GameTime gameTime)
{
    player.Draw();
    enemy.Draw();
}

โดยเฉพาะอย่างยิ่งเมื่อในเกมแห่งความเป็นจริงคุณอาจต้องเจออะไรทำนองนี้:

GraphicsDevice.Viewport = cameraOne.Viewport;
player.Draw(cameraOne, spriteBatch);
enemy.Draw(cameraOne, spriteBatch);

GraphicsDevice.Viewport = cameraTwo.Viewport;
player.Draw(cameraTwo, spriteBatch);
enemy.Draw(cameraTwo, spriteBatch);

(เป็นที่ยอมรับว่าคุณสามารถแบ่งปันกล้องและ spriteBatch โดยใช้Servicesสถาปัตยกรรมที่คล้ายกันแต่นั่นก็เป็นความคิดที่ไม่ดีด้วยเหตุผลเดียวกันมาก)

สถาปัตยกรรมนี้ - หรือไม่มี - มีน้ำหนักเบาและยืดหยุ่นมากขึ้น!

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

มันเป็นเหมือนความแตกต่างระหว่างการเขียนโปรแกรมเชิงเปรียบเทียบกับความจำเป็น ปรากฎว่าสำหรับการพัฒนาเกมการเขียนโปรแกรมที่จำเป็นนั้นดีกว่า


2
ฉันอยู่ภายใต้ความประทับใจที่พวกเขาใช้สำหรับการเขียนโปรแกรมแบบ Componentซึ่งดูเหมือนจะใช้กันอย่างแพร่หลายสำหรับการเขียนโปรแกรมเกม
BlueRaja - Danny Pflughoeft

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

1
ฉันยอมรับว่าสถาปัตยกรรม GameComponent / Service ไม่ใช่สิ่งที่มีประโยชน์และดูเหมือนว่าแนวคิด Office-like หรือเว็บแอปพลิเคชันที่ถูกบังคับให้เข้าสู่กรอบเกม แต่ฉันชอบที่จะใช้player.DrawOrder = 100;วิธีการมากกว่าสิ่งจำเป็นสำหรับการวาดคำสั่ง ตอนนี้ฉันเล่นเกม Flixel เสร็จแล้วซึ่งวาดวัตถุตามลำดับที่คุณเพิ่มเข้าไปในฉาก ระบบ FlxGroup บรรเทาบางสิ่งนี้ แต่การเรียงลำดับดัชนี Z บางประเภทในตัวน่าจะดี
michael.bartnett

@ michael.bartnett โปรดทราบว่า Flixel เป็นโหมดเก็บรักษา API ในขณะที่ XNA (ยกเว้นเห็นได้ชัดว่าระบบส่วนประกอบของเกม) เป็น API โหมดทันที หากคุณใช้ API โหมดคงไว้หรือใช้งานของคุณเองความสามารถในการเปลี่ยนคำสั่งซื้อแบบทันทีเป็นสิ่งสำคัญอย่างยิ่ง ในความเป็นจริงความจำเป็นในการเปลี่ยนลำดับการสั่งการทำงานเป็นสิ่งที่ดีในการทำบางสิ่งบางอย่างในโหมดเก็บรักษาไว้ (ตัวอย่างของระบบ Windowing มาถึง) แต่ถ้าคุณสามารถเขียนอะไรบางอย่างในโหมดทันทีหากแพลตฟอร์ม API (เช่น XNA) ถูกสร้างขึ้นด้วยวิธีนั้น IMO ที่คุณควรทำ
Andrew Russell

สำหรับการอ้างอิงเพิ่มเติมgamedev.stackexchange.com/a/112664/56
Kenji Kina

26

อืมม ลองท้าทายตัวนี้ดูเพื่อความสมดุลสักหน่อยที่นี่ฉันกลัว

ดูเหมือนจะมีการเรียกเก็บเงิน 5 ครั้งในการตอบของแอนดรูดังนั้นฉันจะพยายามและจัดการกับแต่ละเรื่อง:

1) ส่วนประกอบเป็นการออกแบบที่ล้าสมัยและถูกทอดทิ้ง

แนวคิดเกี่ยวกับรูปแบบการออกแบบขององค์ประกอบนั้นมีมานานก่อนที่ XNA - โดยพื้นฐานแล้วมันเป็นเพียงการตัดสินใจที่จะสร้างอ็อบเจกต์แทนที่จะเป็นเกมบนวัตถุโค้งที่เป็นบ้านของพฤติกรรม Update และ Draw ของพวกเขาเอง สำหรับวัตถุในการรวบรวมส่วนประกอบเกมจะเรียกวิธีการเหล่านี้ (และอีกสองสามอย่าง) โดยอัตโนมัติในเวลาที่เหมาะสม - วัตถุในเกมไม่จำเป็นต้อง 'รู้' รหัสใด ๆ เลย หากคุณต้องการที่จะใช้คลาสเกมของคุณอีกครั้งในเกมที่แตกต่างกัน (และวัตถุเกมที่แตกต่างกัน) การยกเลิกการเชื่อมต่อของวัตถุนี้ยังคงเป็นความคิดที่ดี ดูอย่างรวดเร็วเกี่ยวกับการสาธิตล่าสุด (ผลิตอย่างมืออาชีพ) ของ XNA4.0 จาก AppHub ยืนยันความประทับใจของฉันว่า Microsoft ยังคง (ค่อนข้างถูกต้องในมุมมองของฉัน) อย่างแน่นหนาอยู่ข้างหลังอันนี้

2) แอนดรูว์ไม่สามารถนึกถึงคลาสเกมที่สามารถใช้ซ้ำได้มากกว่า 2 คลาส

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

  • ผู้จัดการเกม / รัฐหน้าจอ
  • ParticleEmitters
  • ดั่งเดิม
  • ตัวควบคุม AI
  • อินพุตคอนโทรลเลอร์
  • ตัวควบคุมภาพเคลื่อนไหว
  • บิลบอร์ด
  • ผู้จัดการฟิสิกส์และการปะทะกัน
  • กล้อง

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

3) การควบคุมลำดับการวาดตามลำดับของการเรียกการวาดที่ชัดเจนจะดีกว่าที่จะใช้คุณสมบัติ DrawOrder ของส่วนประกอบ

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

4) การเรียกโหลดวิธีการวาดของวัตถุด้วยตัวคุณเองนั้นจะ 'เบา' มากกว่าการเรียกด้วยวิธีเฟรมเวิร์กที่มีอยู่

ทำไม? นอกจากนี้โครงการที่สำคัญที่สุดของตรรกะการอัปเดตและโค้ดการวาดของคุณจะบดบังวิธีการโทรของคุณในแง่ของประสิทธิภาพการทำงานในทุกกรณี

5) การวางโค้ดของคุณในไฟล์เดียวจะดีกว่าเมื่อทำการดีบั๊กมากกว่าที่จะวางไว้ในไฟล์ของแต่ละวัตถุ

ก่อนอื่นเมื่อฉันทำการดีบั๊กใน Visual Studio ตำแหน่งของเบรกพอยต์ในแง่ของไฟล์บนดิสก์แทบจะมองไม่เห็นทุกวันนี้ - IDE จัดการกับตำแหน่งโดยไม่ต้องมีละคร แต่ให้พิจารณาสักครู่ว่าคุณมีปัญหากับรูปวาด Skybox ของคุณ เป็นไปวิธีการวาด Skybox ของมันหนักกว่าตำแหน่ง Skybox วาดรหัสใน (น่าจะมีความยาวมาก) ต้นแบบวิธีการวาดในวัตถุเกม? ไม่จริง ๆ แล้วฉันจะโต้แย้งว่ามันเป็นสิ่งที่ตรงกันข้าม

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


2
ฉันเพิ่งสังเกตเห็นโพสต์นี้และฉันจะต้องออก rebuttal ที่แข็งแกร่ง: ฉันไม่มีปัญหากับการเรียนซ้ำ! (ซึ่งอาจมีวิธีการวาดและอัปเดตและอื่น ๆ ) ฉันกำลังนำปัญหาเฉพาะกับการใช้ ( Drawable) GameComponentเพื่อให้สถาปัตยกรรมเกมของคุณเนื่องจากสูญเสียการควบคุมอย่างชัดเจนเกี่ยวกับลำดับการวาด / อัปเดต (ซึ่งคุณเห็นด้วยในข้อ 3) ของอินเทอร์เฟซของพวกเขา (ซึ่งคุณไม่ได้ระบุ)
Andrew Russell

1
จุดที่คุณ # 4 ใช้คำว่า "น้ำหนักเบา" ของฉันเพื่อแสดงถึงประสิทธิภาพซึ่งจริงๆแล้วฉันหมายถึงความยืดหยุ่นทางสถาปัตยกรรมอย่างชัดเจน คะแนนที่เหลือของคุณ # 1, # 2 และโดยเฉพาะอย่างยิ่ง # 5 ดูเหมือนจะสร้างคนฟางที่ไร้สาระซึ่งฉันคิดว่าส่วนใหญ่ / รหัสทั้งหมดควรถูกผลักเข้าสู่คลาสเกมหลักของคุณ! อ่านคำตอบของฉันที่นี่เพื่อรับความคิดที่ละเอียดยิ่งขึ้นเกี่ยวกับสถาปัตยกรรม
Andrew Russell

5
ในที่สุด: หากคุณกำลังโพสต์คำตอบของฉันโดยบอกว่าฉันผิดมันก็เป็นมารยาทที่จะเพิ่มคำตอบให้กับคำตอบของฉันด้วยดังนั้นฉันจะเห็นการแจ้งเตือนเกี่ยวกับมันแทนที่จะต้องสะดุด มันสองเดือนต่อมา
Andrew Russell

ฉันอาจเข้าใจผิด แต่สิ่งนี้จะตอบคำถามได้อย่างไร ฉันควรใช้ GameComponent สำหรับสไปรต์ของฉันหรือไม่?
Superbest

ข้อโต้แย้งเพิ่มเติม: gamedev.stackexchange.com/a/112664/56
Kenji Kina

4

ฉันไม่เห็นด้วยเล็กน้อยกับแอนดรูว์ แต่ฉันก็คิดว่ามีเวลาและสถานที่สำหรับทุกสิ่ง ฉันจะไม่ใช้Drawable(GameComponent)สิ่งที่ง่ายเหมือน Sprite หรือ Enemy อย่างไรก็ตามฉันจะใช้มันเพื่อSpriteManagerหรือEnemyManagerหรือ

ย้อนกลับไปที่สิ่งที่แอนดรูว์พูดเกี่ยวกับลำดับการวาดและอัปเดตฉันคิดว่าSprite.DrawOrderมันจะสับสนมากสำหรับสไปรต์หลายรายการ ยิ่งไปกว่านั้นมันค่อนข้างง่ายในการตั้งค่าDrawOrderและUpdateOrderสำหรับผู้จัดการจำนวนเล็กน้อย (หรือเหมาะสม)(Drawable)GameComponentsของผู้จัดการที่มี

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


2

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

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


2

ในความคิดเห็นฉันโพสต์คำตอบแบบเก่าของฉันแบบย่อคำตอบ:

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

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


วัตถุรากรักษาสถานะของโลกของเกมมีUpdateวิธีการดังนี้:

void Update(UpdateContext updateContext, MultiInputState currentInput)

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

นอกจากนี้ยังมีวิธีการปรับปรุงเพิ่มเติมเช่น:

void PlayerJoin(int playerIndex, string playerName, UpdateContext updateContext)

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

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


สำหรับการวาดภาพเนื่องจากลักษณะของเกมมีระบบการเรียงและกำหนดเองที่รับอินพุตจากวิธีการเหล่านี้:

virtual void RegisterToDraw(SortedDrawList sortedDrawList, Definitions definitions)
virtual void RegisterShadow(ShadowCasterList shadowCasterList, Definitions definitions)

จากนั้นเมื่อมันรู้ว่าจะวาดอะไรโทรออกโดยอัตโนมัติ:

virtual void Draw(DrawContext drawContext, int tag)

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

นอกจากนี้ยังมีระบบเมนูในการวาด และระบบลำดับชั้นสำหรับการวาด UI รอบ ๆ HUD รอบ ๆ เกม


ตอนนี้เปรียบเทียบความต้องการเหล่านั้นกับสิ่งที่DrawableGameComponentให้:

public class DrawableGameComponent
{
    public virtual void Update(GameTime gameTime);
    public virtual void Draw(GameTime gameTime);
    public int UpdateOrder { get; set; }
    public int DrawOrder { get; set; }
}

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

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


สิ่งที่ผู้คนมักทำถ้าเริ่มDrawableGameComponentเส้นทางคือพวกเขาเริ่มสร้างโดยใช้แฮ็ก:

  • แทนที่จะเพิ่มวิธีการพวกเขาลงเอยที่น่าเกลียดในประเภทฐานของตัวเอง (ทำไมไม่ใช้เพียงแค่นั้นโดยตรง)

  • แทนที่จะเปลี่ยนรหัสสำหรับการเรียงลำดับและเรียกใช้Draw/ Updateพวกเขาทำสิ่งที่ช้ามากในการเปลี่ยนหมายเลขการสั่งซื้อแบบทันที

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

    นอกจากนี้ยังทำให้การใช้รหัสซ้ำยากขึ้นเพราะตอนนี้การพึ่งพาของคุณถูกซ่อนอยู่ภายใน "ส่วนประกอบ" แทนที่จะเผยแพร่ที่ขอบเขต API

  • หรือพวกเขาเกือบจะเห็นว่ามันบ้าไปหมดแล้วและเริ่มทำ "ผู้จัดการ" DrawableGameComponentเพื่อแก้ไขปัญหาเหล่านี้ ยกเว้นพวกเขายังมีปัญหาเหล่านี้ที่ขอบเขต "ผู้จัดการ"

    "ผู้จัดการ" เหล่านี้สามารถถูกแทนที่อย่างง่ายดายด้วยชุดของการเรียกใช้เมธอดตามลำดับที่ต้องการ สิ่งอื่นใดที่ซับซ้อนเกินไป

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


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

แน่นอนมันสามารถทำให้ "ทำงาน"! เราเป็นโปรแกรมเมอร์ - การทำสิ่งต่าง ๆ ให้ทำงานภายใต้ข้อ จำกัด ที่ผิดปกตินั้นเป็นหน้าที่ของเรา แต่ข้อ จำกัด นี้ไม่จำเป็นมีประโยชน์หรือมีเหตุผล ...


สิ่งที่ทำให้งุนงงเป็นพิเศษคือมันไม่น่าประหลาดใจที่จะก้าวไปข้างหน้าในประเด็นทั้งหมดนี้ ที่นี่ฉันจะให้รหัสแก่คุณด้วย:

public class Actor
{
    public virtual void Update(GameTime gameTime);
    public virtual void Draw(GameTime gameTime);
}

List<Actor> actors = new List<Actor>();

foreach(var actor in actors)
    actor.Update(gameTime);

foreach(var actor in actors)
    actor.Draw(gameTime);

(มันง่ายที่จะเพิ่มในการจัดเรียงตามDrawOrderและUpdateOrder. วิธีหนึ่งที่ง่ายคือการรักษาสองรายการและใช้List<T>.Sort(). นอกจากนี้ยังเป็นเรื่องเล็กน้อยที่จะจัดการLoad/ UnloadContent.)

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

เมื่อฉันรู้ว่าฉันต้องการระบบจับเวลาที่แตกต่างกันgameTimeหรือฉันต้องการพารามิเตอร์เพิ่มเติม (หรือUpdateContextวัตถุทั้งหมดที่มีประมาณ 15 สิ่ง) หรือฉันต้องการลำดับการปฏิบัติการที่แตกต่างกันโดยสิ้นเชิงสำหรับการวาดรูปหรือฉันต้องการวิธีพิเศษบางอย่าง สำหรับการอัปเดตต่าง ๆ ฉันสามารถดำเนินการต่อได้

และฉันสามารถทำได้ทันที ฉันไม่จำเป็นต้องกังวลเกี่ยวกับการเลือกDrawableGameComponentรหัสของฉัน หรือแย่กว่านั้นคือ: แฮ็คมันด้วยวิธีใดวิธีหนึ่งที่จะทำให้มันยากขึ้นในครั้งต่อไปที่ความต้องการดังกล่าวเกิดขึ้น


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

(ในทำนองเดียวกันมันสมเหตุสมผลดีที่จะใช้Servicesเมื่อสร้างประเภทเนื้อหาที่กำหนดเองContentManagerเท่านั้น)


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