องค์ประกอบ OOP หนักเทียบกับระบบส่วนประกอบของเอนทิตีบริสุทธิ์? [ปิด]


13

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

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

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

เมื่อฉันเริ่มอ่านมันฉันก็สามารถเห็นได้อย่างชัดเจนว่ามันสามารถแก้ปัญหาที่ฉันมีกับลำดับชั้นของ OOP ดั้งเดิมที่มีส่วนประกอบ สิ่งเหล่านี้อยู่ในการอ่านครั้งแรกอย่างไรก็ตาม เมื่อผมเจอมากขึ้น ... “รุนแรง” ES แนวทางดังกล่าวเป็นหนึ่งในT-เครื่อง

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

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

ตัวอย่างต่อไปนี้แสดงสิ่งที่ฉันหมายถึง (เป็นแรงบันดาลใจจากตัวอย่างที่ฉันพบใน Game Engine Architecture ตอนที่ 14)

ฉันจะมีต้นไม้เล็ก ๆ สำหรับยานพาหนะ คลาสรูทยานพาหนะจะมีองค์ประกอบการเรนเดอร์ส่วนประกอบการชนส่วนประกอบตำแหน่ง ฯลฯ

จากนั้นรถถัง subclass ของยานพาหนะจะสืบทอดส่วนประกอบเหล่านั้นจากนั้นและจะได้รับมันเป็นองค์ประกอบ "ปืนใหญ่" ของตัวเอง

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

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

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

ความคิดเห็นของคุณ?

PS: ฉันกำลังใช้ Java ดังนั้นการใช้การสืบทอดหลายอย่างเพื่อนำสิ่งนี้ไปใช้แทนการใช้ส่วนประกอบปกติเป็นไปไม่ได้

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


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

ฉันไม่ได้ แต่อย่างที่ฉันพูดฉันแทบจะไม่มีประสบการณ์ใด ๆ เลยและฉันก็ยังห่างไกลจากผู้ตัดสินที่ดีที่สุดสำหรับเรื่องนี้
Midori Ryuu

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

4
ฉันโหวตให้ปิดเช่นกัน เป็นคำถามที่ดีและเป็นลายลักษณ์อักษร แต่ไม่เหมาะสำหรับ GDSE คุณอาจลองโพสต์สิ่งนี้ใหม่ที่ GameDev.net
Sean Middleditch

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

คำตอบ:


8

ลองพิจารณาตัวอย่างนี้:

คุณกำลังทำ RTS ในแบบของตรรกะเสร็จสมบูรณ์คุณตัดสินใจที่จะทำให้ชั้นฐานGameObjectแล้วสอง subclasses, และBuilding Unitมันใช้งานได้ดีแน่นอนและคุณจะจบลงด้วยสิ่งที่มีลักษณะเช่นนี้:

  • GameObject
    • ModelComponent
    • CollisionComponent
    • ...
  • Building
    • ProductionComponent
    • ...
  • Unit
    • AimingAIComponent
    • WeaponComponent
    • ParticleEmitterComponent
    • AnimationComponent
    • ...

ตอนนี้คลาสย่อยของUnitคุณที่ทำไปแล้วมีส่วนประกอบทั้งหมดที่คุณต้องการแล้ว และเป็นโบนัสที่คุณต้องเป็นสถานที่เดียวที่จะนำรหัสการตั้งค่าทั้งหมดที่น่าเบื่อที่news ค่าWeaponComponentเชื่อมต่อไปยังAimingAIComponentและParticleEmitterComponent-wonderful!

และแน่นอนเพราะมันยังคงใช้เหตุผลเป็นส่วนประกอบในที่สุดเมื่อคุณตัดสินใจว่าคุณต้องการเพิ่มTowerคลาสนั่นคือสิ่งปลูกสร้าง แต่มีอาวุธคุณสามารถจัดการมันได้ คุณสามารถเพิ่มAimingAIComponentการWeaponComponentและParticleEmitterComponentการ subclass Buildingของคุณ แน่นอนว่าคุณต้องผ่านและขุดรหัสการเริ่มต้นจากUnitชั้นเรียนและวางไว้ที่อื่น แต่นั่นไม่ใช่การสูญเสียครั้งใหญ่

และตอนนี้ขึ้นอยู่กับการมองการณ์ไกลที่คุณมีคุณอาจหรือไม่อาจท้ายด้วยข้อบกพร่องที่ลึกซึ้ง ปรากฎว่าอาจมีรหัสบางส่วนในเกมที่มีลักษณะเช่นนี้:

if (myGameObject instanceof Unit)
    doSomething(((Unit)myGameObject).getWeaponComponent());

สิ่งนี้จะไม่ทำงานในTowerอาคารของคุณแม้ว่าคุณจะต้องการให้มันทำงานด้วยอาวุธก็ตาม ตอนนี้มันต้องมีลักษณะดังนี้:

WeaponComponent weapon = myGameObject.getComponent(WeaponComponent.class);
if (weapon)
    doSomething(weapon);

ดีกว่ามาก! มันเกิดขึ้นกับคุณหลังจากเปลี่ยนสิ่งนี้ซึ่งวิธีการเข้าถึงใด ๆที่คุณเขียนอาจสิ้นสุดในสถานการณ์นี้ ดังนั้นสิ่งที่ปลอดภัยที่สุดที่จะทำคือดึงพวกเขาออกทั้งหมดและเข้าถึงทุกส่วนประกอบผ่านทางนี้getComponentวิธีการที่สามารถทำงานร่วมกับประเภทรองใด ๆ (อีกวิธีหนึ่งคุณสามารถเพิ่มทุกประเภทของget*Component()ซูเปอร์GameObjectคลาสและแทนที่พวกเขาในคลาสย่อยเพื่อส่งกลับองค์ประกอบฉันจะถือว่าเป็นคนแรก)

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

หากคุณทำตามขั้นตอนนี้ไปสุดโต่งคุณจะต้องสร้างคลาสย่อยของคุณให้อยู่ในถุงที่มีส่วนประกอบเฉื่อยอย่างสมบูรณ์ซึ่ง ณ จุดนั้นไม่มีจุดใดเลยที่มีคลาสย่อยรอบ ๆ คุณสามารถได้รับประโยชน์เกือบทั้งหมดจากการมีลำดับชั้นของคลาสด้วยลำดับชั้นเมธอดที่สร้างส่วนประกอบที่เหมาะสม แทนที่จะมีUnitระดับคุณจะมีaddUnitComponentsวิธีการที่ทำให้AnimationComponentและยังเรียกร้องaddWeaponComponentsซึ่งทำให้AimingAIComponentเป็นและWeaponComponent ParticleEmitterComponentผลลัพธ์คือคุณได้รับประโยชน์ทั้งหมดจากระบบเอนทิตีรหัสทั้งหมดที่นำมาใช้ใหม่ของลำดับชั้นและไม่มีสิ่งล่อใจให้ตรวจสอบinstanceofหรือส่งไปยังประเภทคลาสของคุณ


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

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

ในวิธีที่ง่ายขึ้น คุณสิ้นสุดการใช้มรดกเป็นรูปแบบโรงงานของคนจน
Zardoz89

2

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


1

เมื่อมาถึงการบูรณาการองค์ประกอบตามระบบการเล่นเกมที่มีอยู่ขึ้นอยู่กับเกมวัตถุที่มีบทความที่เขียนโปรแกรมคาวบอยhttp://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/ซึ่งอาจทำให้คุณชี้บางอย่างเกี่ยวกับ วิธีการเปลี่ยนสามารถทำได้

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

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

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

มันสามารถทำงานได้สำหรับคุณ แต่ฉันไม่ได้ผสมทั้งสองอย่างนอกช่วงการเปลี่ยนภาพจากสถาปัตยกรรมหนึ่งไปอีกสถาปัตยกรรมหนึ่ง

ป.ล. เขียนบนโทรศัพท์ดังนั้นฉันจึงลำบากในการเชื่อมโยงไปยังแหล่งข้อมูลภายนอก


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

@ MidoriRyuu หลีกเลี่ยงการสืบทอดทั้งหมดในวัตถุเอนทิตี คุณโชคดีพอที่จะใช้ภาษาที่มีการสะท้อน (และวิปัสสนา) ในตัว คุณสามารถใช้ไฟล์ (txt หรือ XML) เพื่อเริ่มต้นวัตถุของคุณด้วยพารามิเตอร์ที่เหมาะสม มันไม่ทำงานมากเกินไปและจะอนุญาตให้ปรับแต่งเกมโดยไม่ต้องทำการคอมไพล์ใหม่ แต่ให้คลาสเอนทิตีอย่างน้อยสำหรับการสื่อสารระหว่างส่วนประกอบและงานยูทิลิตี้อื่น ๆ PS ยังอยู่ในโทรศัพท์ :(
โคโยตี้
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.