ฉันสงสัยอยู่เสมอว่าการวางแนววัตถุในขอบเขตใดโดยวิดีโอเกมโดยเฉพาะโครงการ 3D ขนาดใหญ่ ฉันคิดว่ามันคงเจ๋งที่ทั้งสองtroll
และwerewolf
สืบทอดคุณลักษณะจากenemy
และเขียนทับบางส่วนของพวกเขา แต่บางทีชั้นเรียนอาจหนักเกินไปที่จะใช้งานได้จริงฉันไม่รู้ ...
ฉันสงสัยอยู่เสมอว่าการวางแนววัตถุในขอบเขตใดโดยวิดีโอเกมโดยเฉพาะโครงการ 3D ขนาดใหญ่ ฉันคิดว่ามันคงเจ๋งที่ทั้งสองtroll
และwerewolf
สืบทอดคุณลักษณะจากenemy
และเขียนทับบางส่วนของพวกเขา แต่บางทีชั้นเรียนอาจหนักเกินไปที่จะใช้งานได้จริงฉันไม่รู้ ...
คำตอบ:
มาถึงตัวอย่างของคุณฉันจะอธิบายความคิดของฉันเกี่ยวกับ Entites ในวิดีโอเกม ฉันจะไม่พูดถึงข้อดีและข้อเสียทั่วไปของวัตถุและคลาสรวมถึงบทบาททั้งหมดในวิดีโอเกม
เอนทิตีในวิดีโอเกมขนาดเล็กส่วนใหญ่จะถูกกำหนดโดยชั้นเรียนแยกในเกมใหญ่พวกเขามักจะถูกกำหนดในไฟล์ มีวิธีการทั่วไปสองวิธีในการติดตาม:
ขยาย : ในตัวอย่างของคุณTroll
และWerewolf
จะขยายซึ่งทอดตัวEnemy
ดูแลเกี่ยวกับสิ่งพื้นฐานเช่นการเคลื่อนไหวสุขภาพ ฯลฯ ในขณะที่จะระบุคลาสย่อยเป็นศัตรูและทำสิ่งอื่น ๆ (Minecraft ทำตามวิธีนี้)Entity
Entity
Enemy
ส่วนประกอบตาม : วิธีที่สอง (และรายการโปรดของฉัน) คือEntity
ชั้นหนึ่งซึ่งมีส่วนประกอบ ส่วนประกอบที่อาจจะหรือMoveable
Enemy
ส่วนประกอบเหล่านี้ดูแลสิ่งหนึ่งอย่างเช่นการเคลื่อนไหวหรือฟิสิกส์ วิธีนี้แบ่งส่วนต่อขยายที่ยาวและลดความเสี่ยงที่จะเกิดข้อขัดแย้ง ตัวอย่างเช่น: คุณจะสร้างศัตรูที่ไม่สามารถเคลื่อนที่ได้ได้อย่างไรหากพวกมันสืบทอดมาจากตัวละครที่เคลื่อนย้ายได้ .
ในวิดีโอเกมขนาดใหญ่เช่น World of Warcraft หรือ Starcraft 2, Entities ไม่ใช่คลาส แต่เป็นชุดของข้อมูลซึ่งระบุ Entity ทั้งหมด การเขียนสคริปต์ก็มีความสำคัญเช่นกันเพราะคุณกำหนดสิ่งที่เอ็นติตี้ไม่ได้อยู่ในคลาส แต่เป็นสคริปต์ (หากเป็นเอกลักษณ์ไม่เหมือนการเคลื่อนไหว)
ขณะนี้ฉันกำลังเขียนโปรแกรม RTS และฉันใช้วิธีการแบบคอมโพเนนต์กับ Descriptor และไฟล์สคริปต์สำหรับ Entites, ทักษะ, ไอเท็มและทุกอย่างอื่นที่มีชีวิตชีวาในเกม
component
อยู่ในบริบทนี้ ลิงค์จะนิยมมาก
ฉันคิดว่ามันคงเจ๋งที่ทั้งโทรลล์และมนุษย์หมาป่าจะสืบทอดคุณสมบัติของมันจากศัตรูและเขียนทับพวกมันบางส่วน
น่าเสียดายที่วิธีนี้มีความแตกต่างซึ่งเป็นที่นิยมใน 90s แสดงให้เห็นว่าตัวเองมีความคิดที่ไม่ดีในทางปฏิบัติ ลองนึกภาพคุณเพิ่ม 'wolf' ลงในรายชื่อศัตรู - มันแชร์คุณสมบัติบางอย่างกับมนุษย์หมาป่าดังนั้นคุณจึงต้องการรวมเหล่านั้นไว้ในคลาสฐานที่ใช้ร่วมกันเช่น 'WolfLike' ตอนนี้คุณเพิ่ม 'มนุษย์' ลงในรายการศัตรู แต่มนุษย์หมาป่าบางครั้งก็เป็นมนุษย์ดังนั้นพวกเขาจึงแบ่งปันคุณลักษณะเช่นกันเช่นเดินบน 2 ขาสามารถพูดคุย ฯลฯ คุณสร้างฐานร่วม 'Humanoid' สำหรับมนุษย์และมนุษย์หมาป่า และคุณต้องหยุดมนุษย์หมาป่าที่มาจาก WolfLike หรือไม่? หรือคุณคูณรับมรดกจากทั้งสองอย่าง - ซึ่งในกรณีนี้คุณลักษณะใดที่สำคัญกว่าเมื่อบางสิ่งใน Humanoid ปะทะกับบางสิ่งใน WolfLike
ปัญหาคือการพยายามสร้างแบบจำลองโลกแห่งความเป็นจริงเป็นต้นไม้ที่ไม่มีประสิทธิภาพ ทำอะไร 3 อย่างและคุณอาจพบวิธีที่แตกต่างกัน 4 วิธีในการคำนึงถึงพฤติกรรมของพวกเขาในการแชร์และไม่แชร์ นี่คือสาเหตุที่หลายคนหันไปใช้โมเดลแบบแยกส่วนหรือส่วนประกอบแทนโดยที่วัตถุประกอบด้วยวัตถุขนาดเล็กจำนวนมากที่ประกอบเป็นทั้งหมดและวัตถุขนาดเล็กสามารถเปลี่ยนหรือเปลี่ยนแปลงเพื่อให้สอดคล้องกับพฤติกรรมที่คุณต้องการ ที่นี่คุณอาจมีคลาสศัตรูเพียง 1 คลาสและมีวัตถุย่อยหรือส่วนประกอบสำหรับวิธีการเดิน (เช่น Bipedal vs. Quadrupedal) วิธีการโจมตี (เช่นกัด, กรงเล็บ, อาวุธ, กำปั้น), ผิวของมัน (สีเขียว สำหรับ trolls, ขนยาวสำหรับมนุษย์หมาป่าและหมาป่า) ฯลฯ
สิ่งนี้ยังคงเป็นเชิงวัตถุอย่างสมบูรณ์ แต่ความคิดของสิ่งที่เป็นประโยชน์นั้นแตกต่างจากสิ่งที่เคยสอนกันโดยทั่วไปในหนังสือเรียน แทนที่จะมีต้นไม้มรดกขนาดใหญ่ของคลาสนามธรรมที่หลากหลายและคลาสคอนกรีตจำนวนมากที่ปลายของต้นไม้คุณมักจะมีเพียง 1 คลาสคอนกรีตที่แสดงแนวคิดนามธรรม (เช่น 'ศัตรู') แต่มีคลาสคอนกรีตที่มากขึ้นซึ่งแสดงแนวคิดนามธรรมที่เป็นนามธรรมมากกว่า (เช่นการโจมตีประเภทของผิว) บางครั้งคลาสที่สองเหล่านี้สามารถใช้งานได้ดีที่สุดผ่านการสืบทอดระดับ 1 (เช่นคลาสการโจมตีพื้นฐานและคลาสที่ได้รับหลายคลาสสำหรับการโจมตีเฉพาะ) แต่โครงสร้างการสืบทอดลึกจะหายไป
แต่บางทีชั้นเรียนอาจหนักเกินไปที่จะใช้งานได้จริงฉันไม่รู้ ...
ในภาษาที่ทันสมัยส่วนใหญ่ชั้นเรียนจะไม่ 'หนัก' พวกมันเป็นอีกวิธีหนึ่งในการเขียนโค้ดและพวกเขามักจะห่อวิธีการที่คุณจะเขียนต่อไปยกเว้นด้วยไวยากรณ์ที่ง่ายกว่า แต่โดยทั้งหมดอย่าเขียนคลาสที่ฟังก์ชันจะทำ ชั้นเรียนไม่ได้ดีขึ้นอย่างแท้จริงเฉพาะที่พวกเขาทำให้รหัสง่ายต่อการจัดการหรือเข้าใจ
ฉันไม่แน่ใจว่าสิ่งที่คุณหมายถึง "หนักเกินไป" แต่ C ++ / OOP เป็นภาษากลางของการพัฒนาเกมด้วยเหตุผลเดียวกันกับที่ใช้ในที่อื่น
พูดถึงการเป่าแคชเป็นปัญหาการออกแบบไม่ใช่คุณสมบัติทางภาษา C ++ ต้องไม่เลวร้ายนักเพราะมันถูกใช้ในเกมมานานกว่า 15-20 ปีแล้ว Java นั้นไม่เลวร้ายนักเนื่องจากมันถูกใช้ในสภาพแวดล้อมรันไทม์ที่เข้มงวดของสมาร์ทโฟน
ต่อไปนี้เป็นคำถามที่แท้จริง: หลายปีที่ผ่านมาลำดับชั้นของชั้นเรียนลึกและเริ่มประสบปัญหาที่เกี่ยวข้อง ในช่วงเวลาที่ผ่านมาลำดับชั้นของคลาสนั้นแบนและองค์ประกอบและการออกแบบที่ขับเคลื่อนด้วยข้อมูลอื่น ๆ นั้นเป็นมากกว่าการสืบทอดเชิงตรรกะ
มันคือ OOP ทั้งหมดและยังคงใช้เป็นพื้นฐานในการออกแบบซอฟต์แวร์ใหม่เพียงแค่มุ่งเน้นไปที่สิ่งที่ชั้นเรียนรวบรวม
คลาสไม่เกี่ยวข้องกับค่าใช้จ่ายในการดำเนินการใด ๆ ความหลากหลายเวลาทำงานเป็นเพียงการเรียกผ่านตัวชี้ฟังก์ชั่น ค่าโสหุ้ยเหล่านี้มีน้อยมากเมื่อเทียบกับค่าใช้จ่ายอื่น ๆ เช่นการโทรแบบวาดการซิงโครไนซ์พร้อมกันดิสก์ I / O สวิตช์โหมดเคอร์เนลตำแหน่งหน่วยความจำไม่ดีการใช้หน่วยความจำแบบไดนามิกมากเกินไป ไปที่. มีเหตุผลที่การวางแนววัตถุได้แทนที่สิ่งที่เกิดขึ้นก่อนหน้านี้และเป็นเพราะมันดีกว่ามาก
สิ่งหนึ่งที่ต้องระวังคือแนวคิดของโค้ดเชิงวัตถุมักมีค่ามากกว่าการนำไปใช้ในภาษา โดยเฉพาะอย่างยิ่งการเรียกการอัปเดตเสมือน 1,000 ครั้งบนเอนทิตีในลูปหลักอาจทำให้เกิดความยุ่งเหยิงในแคชใน C ++ บนแพลตฟอร์มเช่น 360 หรือ PS3 ดังนั้นการนำไปใช้อาจหลีกเลี่ยงคำหลัก "เสมือน" หรือแม้แต่ "คลาส" เพื่อประโยชน์ ของความเร็ว
บ่อยครั้งที่มันจะยังคงเป็นไปตามแนวคิดของ OO เกี่ยวกับการสืบทอดและการห่อหุ้ม - เพียงนำพวกเขาไปใช้ในลักษณะที่แตกต่างกับภาษาของตัวเอง (เช่นเทมเพลตแบบเรียกซ้ำแบบซ้ำ ๆ หากการสืบทอดสามารถแก้ไขได้ตลอดเวลาการคอมไพล์แล้วปัญหาประสิทธิภาพจะหายไป แต่โค้ดอาจกลายเป็นปัญหาเล็กน้อยกับเทมเพลตการปรับใช้ RTTI แบบกำหนดเอง (อีกครั้งที่บิวท์อินมักจะช้า) มาโคร ฯลฯ
ใน Objective-C สำหรับ iOS / Mac มีความคล้ายคลึงกัน แต่ปัญหาที่เลวร้ายยิ่งกว่ากับรูปแบบการส่งข้อความ (แม้จะมีสิ่งแคชแฟนซี) ...
วิธีการที่ฉันจะพยายามใช้การสืบทอดคลาสและส่วนประกอบผสม (ก่อนอื่นฉันไม่ทำให้ Enemy เป็นคลาส - ฉันสร้างชิ้นส่วนนั้นขึ้นมา) ฉันไม่ชอบความคิดในการใช้คลาสเอนทิตี้ทั่วไปสำหรับทุกสิ่งจากนั้นเพิ่มส่วนประกอบที่จำเป็นเพื่อทำให้เอนทิตีออก แต่ฉันต้องการให้คลาสเพิ่มส่วนประกอบ (และค่าเริ่มต้น) ใน Constructor โดยอัตโนมัติ จากนั้นคลาสย่อยจะเพิ่มคอมโพเนนต์เพิ่มเติมลงในตัวสร้างดังนั้นคลาสย่อยจะมีส่วนประกอบและส่วนประกอบคลาสพาเรนต์ ตัวอย่างเช่นคลาสอาวุธจะเพิ่มองค์ประกอบพื้นฐานที่เหมือนกันกับอาวุธทั้งหมดแล้วคลาสย่อย Sword จะเพิ่มส่วนประกอบเพิ่มเติมใด ๆ สำหรับดาบโดยเฉพาะ ฉันยังคงถกเถียงกันว่าจะใช้เนื้อหาข้อความ / xml เพื่อกำหนดค่าสำหรับเอนทิตี (หรือยกตัวอย่างเช่นดาบ) หรือที่จะทำทั้งหมดในรหัสหรือสิ่งที่ผสมผสานที่ถูกต้องคือ สิ่งนี้ยังช่วยให้เกมใช้ข้อมูลประเภทของรหัสภาษาและ polymorphism และทำให้ ObjectFactories ง่ายกว่ามาก