วิธีการจัดโปรแกรมเกมใน C ++? การใช้การรับมรดกของฉันเป็นความคิดที่ดีหรือไม่?


11

ฉันเป็นผู้เริ่มต้นทั้งในการพัฒนาเกมและการเขียนโปรแกรม

ฉันพยายามเรียนรู้หลักการบางอย่างในการสร้างเอ็นจิ้นเกม
ฉันต้องการสร้างเกมง่ายๆฉันอยู่ในจุดที่ฉันพยายามนำเอ็นจิ้นเกมมาใช้

ดังนั้นฉันคิดว่าเอ็นจิ้นเกมของฉันควรควบคุมสิ่งนี้:

- Moving the objects in the scene
- Checking the collisions
- Adjusting movements based on collisions
- Passing the polygons to the rendering engine

ฉันออกแบบวัตถุของฉันเช่นนี้:

class GlObject{
private:
    idEnum ObjId;
    //other identifiers
public:
    void move_obj(); //the movements are the same for all the objects (nextpos = pos + vel)
    void rotate_obj(); //rotations are the same for every objects too
    virtual Polygon generate_mesh() = 0; // the polygons are different
}

และฉันมีวัตถุต่าง ๆ 4 อย่างในเกมของฉัน: เครื่องบิน, สิ่งกีดขวาง, ผู้เล่น, สัญลักษณ์แสดงหัวข้อย่อยและฉันได้ออกแบบสิ่งเหล่านี้:

class Player : public GlObject{ 
private:
    std::string name;
public:
    Player();
    Bullet fire() const; //this method is unique to the class player
    void generate_mesh();
}

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

นี่เป็นความคิดที่ดีหรือไม่?

class GameEngine{
private:
    std::vector<GlObject*> objects; //an array containg all the object present
    Player* hPlayer; //hPlayer is to be read as human player, and is a pointer to hold the reference to an object inside the array
public:
    GameEngine();
    //other stuff
}

ตัวสร้าง GameEngine จะเป็นเช่นนี้:

GameEngine::GameEngine(){
    hPlayer = new Player;
    objects.push_back(hPlayer);
}

ความจริงที่ว่าฉันกำลังใช้ตัวชี้เป็นเพราะฉันจำเป็นต้องเรียกfire()ที่ไม่ซ้ำกับวัตถุ Player

ดังนั้นคำถามของฉันคือ: มันเป็นความคิดที่ดี? การใช้มรดกของฉันผิดที่นี่หรือไม่?



ฉันเคยเห็นพวกเขาหลังจากโพสต์และการแต่งเพลงเป็นความคิดที่ดีจริงๆ! ฉันกลัวที่จะจบลงด้วยการใช้ c กับคลาสแทนการออกแบบ c ++ จริง ๆ !
Pella86

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

คำตอบ:


12

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

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

โดยทั่วไปสกอตต์เมเยอร์สมีบางสิ่งที่ดีที่จะพูดเกี่ยวกับมรดก หากคุณยังอยู่ในขั้นตอนของการพัฒนาให้อ่านหนังสือเล่มนี้ (Effective C ++)ก่อนดำเนินการต่อ มันเป็นหนังสือที่ยอดเยี่ยมและเป็นข้อกำหนดสำหรับนักเขียนโค้ดทุกคนที่ทำงานใน บริษัท ของเรา แต่เพื่อสรุปคำแนะนำ: หากคุณกำลังเขียนชั้นเรียนและพิจารณาใช้มรดกให้ชัดเจนว่าความสัมพันธ์ระหว่างชั้นเรียนกับบรรพบุรุษนั้นคือความสัมพันธ์แบบ 'เป็น' นั่นคือ B ทุกตัวเป็น A อย่าเพียงใช้การสืบทอดเป็นวิธีที่ง่ายในการให้ B เข้าถึงฟังก์ชันการทำงาน A ที่มีให้ซึ่งจะทำให้เกิดปัญหาสถาปัตยกรรมที่รุนแรงและมีวิธีอื่นที่จะทำ

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


ฉันสองความคิดเห็นเกี่ยวกับการสืบทอด กฎส่วนบุคคลของฉันคือ: อย่าทำอย่างนั้นถ้าคุณไม่ได้ทำหรือทำอย่างอื่นจะโง่ กล่าวอีกนัยหนึ่งการสืบทอดเป็นความคิดที่ไม่ดีใน 99% ของกรณี (อย่างน้อย :) นอกจากนี้อาจเป็นการดีที่จะแยกตรรกะเกม (หมุน / ย้าย) ออกจากการแสดงผล (generate_mesh ()) อีกสิ่งหนึ่งคือไฟ () - พิจารณาว่ามีรายการของการกระทำและฟังก์ชั่นการกระทำทั่วไป (my_action) - ด้วยวิธีนี้คุณจะไม่ได้รับฟังก์ชั่นที่แตกต่างกันหลายพันล้านรายการในทุกชั้นเรียน ไม่ว่าในกรณีใดให้ใช้งานง่ายและปรับโครงสร้างใหม่อย่างไร้ความปราณีเมื่อคุณเจอปัญหา
Gilead

8

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

นอกจากนี้บทความนี้เกี่ยวกับระบบนิติบุคคลที่เป็นแรงบันดาลใจให้ฉันทราบเมื่อครั้งแรกที่ผมอ่านมัน

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

ส่วนประกอบมีประโยชน์มากในหลายสถานการณ์ คุณสามารถใช้สิ่งเหล่านี้ได้มากขึ้น:

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

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

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

ความยืดหยุ่นในเวลา : ส่วนประกอบสามารถใช้เพื่อให้เข้ากันได้ระหว่างรุ่น ตัวอย่างเช่นเมื่อมีการเปลี่ยนแปลงระหว่างการวางจำหน่ายเกมคุณสามารถ (ไม่เสมอไป) เพียงเพิ่มส่วนประกอบใหม่ที่ใช้พฤติกรรมและการเปลี่ยนแปลงใหม่ จากนั้นเกมจะยกตัวอย่างส่วนประกอบที่ถูกต้องที่แนบมากับเอนทิตีของคุณขึ้นอยู่กับไฟล์บันทึกที่โหลด, การเชื่อมต่อเพียร์หรือเซิร์ฟเวอร์ที่ผู้เล่นเข้าร่วม สิ่งนี้มีประโยชน์มากในสถานการณ์ที่คุณไม่สามารถควบคุมวันที่วางจำหน่ายของเวอร์ชั่นใหม่บนทุกแพลตฟอร์ม (Steam, Mac App Store, iPhone, Android ... )

เพื่อความเข้าใจที่ดียิ่งขึ้นให้ดูที่คำถามที่ติดแท็ก[องค์ประกอบตาม]และ[ระบบนิติบุคคล]


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