Làm cách nào để tổ chức một công cụ trò chơi trong C ++? Là sử dụng thừa kế của tôi là một ý tưởng tốt?


11

Tôi là người mới bắt đầu cả về phát triển và lập trình trò chơi.

Tôi đang cố gắng học một số nguyên tắc trong việc xây dựng một công cụ trò chơi.
Tôi muốn tạo một trò chơi đơn giản, tôi đang ở điểm mà tôi đang cố gắng thực hiện công cụ trò chơi.

Vì vậy, tôi nghĩ rằng công cụ trò chơi của tôi nên kiểm soát những thứ này:

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

Tôi đã thiết kế các đối tượng của mình như thế này:

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
}

và tôi có 4 đối tượng khác nhau trong trò chơi của mình: máy bay, chướng ngại vật, người chơi, viên đạn và tôi đã thiết kế chúng như thế này:

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

Bây giờ trong công cụ trò chơi tôi muốn có một danh sách đối tượng chung, nơi tôi có thể kiểm tra ví dụ về va chạm, di chuyển đối tượng, v.v., nhưng tôi cũng muốn công cụ trò chơi sẽ nhận lệnh người dùng để điều khiển người chơi ...

Đây có phải là một ý tưởng tốt?

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
}

nhà xây dựng GameEngine sẽ như thế này:

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

Thực tế là tôi đang sử dụng một con trỏ là vì tôi cần gọi cái fire()đó là duy nhất cho đối tượng Người chơi.

Vì vậy, câu hỏi của tôi là: nó là một ý tưởng tốt? Là sử dụng thừa kế của tôi sai ở đây?



Tôi đã nhìn thấy chúng sau khi đăng, và thực sự sáng tác là một ý tưởng tuyệt vời! Tôi luôn lo sợ sẽ kết thúc việc sử dụng c với các lớp thay vì có một thiết kế c ++ thực sự!
Pella86

Tôi nghĩ có nhiều lý do để sử dụng sáng tác hơn là kế thừa ... Câu trả lời của tôi đưa ra một vài ví dụ xung quanh những lợi thế linh hoạt mà nó mang lại. Để có một ví dụ tốt về việc thực hiện kiểm tra các bài viết tôi liên kết.
Coyote

Câu trả lời:


12

Phụ thuộc vào những gì bạn có nghĩa là 'tốt'. Nó sẽ hoàn thành công việc, chắc chắn. Nó có rất nhiều mặt lên, và mặt dưới. Bạn sẽ không tìm thấy chúng cho đến khi động cơ của bạn phức tạp hơn nhiều. Xem câu hỏi này trên SO , để thảo luận về chủ đề này.

Dù sao cũng có rất nhiều ý kiến, nhưng nếu mã động cơ của bạn vẫn ở giai đoạn đầu, bạn sẽ khó giải thích cho bạn tại sao nó có thể xấu.

Nói chung, Scott Meyers có một số điều tuyệt vời để nói về thừa kế. Nếu bạn vẫn đang ở giai đoạn phát triển, hãy đọc cuốn sách này (C ++ hiệu quả) trước khi bạn tiếp tục. Đó là một cuốn sách tuyệt vời, và là một yêu cầu cho bất kỳ lập trình viên nào làm việc tại công ty chúng tôi. Nhưng để tóm tắt lời khuyên: nếu bạn đang viết một lớp và xem xét sử dụng tính kế thừa, hãy tuyệt đối rõ ràng rằng mối quan hệ giữa lớp và tổ tiên của nó là một mối quan hệ 'là một'. Nghĩa là, mỗi B là một A. Đừng chỉ sử dụng quyền thừa kế như một cách dễ dàng để cấp cho B quyền truy cập vào chức năng A cung cấp, cách đó sẽ dẫn đến các vấn đề kiến ​​trúc nghiêm trọng và có nhiều cách khác để làm điều đó.

Đơn giản thôi; đối với một động cơ có kích thước bất kỳ, bạn sẽ nhanh chóng thấy rằng các đối tượng hiếm khi rơi vào một cấu trúc phân cấp gọn gàng mà kế thừa hoạt động. Sử dụng nó khi thích hợp, nhưng đừng rơi vào cái bẫy của việc sử dụng nó cho mọi thứ - tìm hiểu các cách khác để liên kết các đối tượng.


Tôi thứ hai ý kiến ​​về thừa kế. Nguyên tắc cá nhân của tôi là: đừng làm điều đó trừ khi bạn phải làm hoặc làm theo bất kỳ cách nào khác sẽ là ngu ngốc. Nói cách khác, thừa kế là ý tưởng tồi trong 99% các trường hợp (ít nhất là :)). Ngoài ra, có thể tốt khi tách logic trò chơi (xoay / di chuyển) khỏi kết xuất (Gener_mesh ()). Một điều nữa là fire () - xem xét việc có một danh sách các hành động và chức năng hành động chung (my_action) - theo cách này bạn sẽ không kết thúc với một số lượng lớn các hàm khác nhau trải đều trên tất cả các lớp. Trong cả hai trường hợp, hãy giữ nó đơn giản và tái cấu trúc một cách tàn nhẫn khi bạn gặp phải vấn đề.
Gilead

8

Đối với dữ liệu logic và chức năng của các đối tượng (thực thể) trò chơi của bạn, tôi thực sự khuyên bạn nên sử dụng bố cục trên kế thừa. Một khởi đầu tốt sẽ là cách tiếp cận dựa trên thành phần. Nó được mô tả tốt trong bài viết Lập trình Cowboy này mô tả cách thức kiến ​​trúc này có thể được thực hiện và làm thế nào nó mang lại lợi ích cho nhượng quyền Tony Hawk.

Ngoài ra bài viết này về các hệ thống thực thể đã truyền cảm hứng cho tôi khi tôi lần đầu tiên đọc nó.

Kế thừa là một công cụ tuyệt vời cho đa hình. Ngoại trừ các dự án rất đơn giản, bạn nên tránh sử dụng nó như một cách để cấu trúc các thực thể và logic trò chơi của bạn. Nếu bạn đi theo kế thừa, chắc chắn bạn sẽ phải sao chép và duy trì các bản sao của cùng một mã để thực hiện các chức năng không thể được kế thừa từ cha mẹ chung. Và bạn có thể sẽ bắt đầu gây ô nhiễm các lớp học của mình bằng logic và dữ liệu được sử dụng phổ biến nhất để tránh sao chép quá nhiều mã.

Các thành phần rất tiện dụng trong nhiều tình huống. Bạn có thể đạt được nhiều hơn bằng cách sử dụng chúng:

Linh hoạt với các loại thực thể của bạn : Đôi khi trong quá trình phát triển trò chơi, một số thực thể phát triển đột ngột và trong khi nhà thiết kế trò chơi đưa ra quyết định, nhà phát triển sẽ phải thực hiện nó. Chỉ cần một vài bước để thêm một hành vi hiện có mà không cần sao chép mã. Các hệ thống dựa trên thành phần cho phép nhiều thay đổi được thực hiện bởi những người không lập trình. Ví dụ, mỗi loại thực thể thay vì được đại diện bởi một lớp có thể được biểu diễn bằng tệp mô tả chứa tất cả các tên thành phần và tham số cần thiết để định cấu hình loại. Điều này cho phép các lập trình viên không làm và kiểm tra các thay đổi mà không cần biên dịch lại trò chơi. Chỉ cần chỉnh sửa các tệp mô tả sẽ đủ để thêm, xóa hoặc thay đổi các thành phần được sử dụng bởi từng loại thực thể.

Linh hoạt với các trường hợp cụ thể và các tình huống cụ thể : Có những trường hợp bạn cần người chơi của mình có thể trang bị vũ khí hoặc vật phẩm, bạn có thể thêm một thành phần kiểm kê vào trình phát của mình. trong quá trình phát triển trò chơi của bạn, bạn sẽ cần các thực thể khác để có một kho đồ (ví dụ như kẻ thù). Và tại một thời điểm bạn có trong kịch bản của mình một tình huống trong đó một cái cây được cho là chứa một loại vật phẩm ẩn nào đó. Với các thành phần, bạn có thể thêm một thành phần kiểm kê ngay cả vào các thực thể loại không được thiết kế ban đầu để có một thành phần không có nỗ lực lập trình bổ sung.

Tính linh hoạt trong thời gian chạy : Các thành phần cung cấp một cách rất hiệu quả để thay đổi hành vi của các thực thể khi chạy. Bạn có thể thêm và xóa các thành phần trong thời gian chạy và do đó tạo hoặc xóa các hành vi và thuộc tính khi cần. Chúng cũng cho phép bạn tách các loại dữ liệu khác nhau thành các nhóm có thể (đôi khi) được tính toán song song trên nhiều GPU.

Linh hoạt trong thời gian : Các thành phần có thể được sử dụng để giữ khả năng tương thích giữa các phiên bản. Ví dụ: khi các thay đổi được thực hiện giữa các bản phát hành của một trò chơi, bạn có thể (không phải luôn luôn) chỉ cần thêm các thành phần mới thực hiện các hành vi và thay đổi mới. Sau đó, trò chơi sẽ khởi tạo đúng các thành phần được gắn vào các thực thể của bạn tùy thuộc vào tệp lưu được tải, kết nối ngang hàng hoặc máy chủ mà người chơi tham gia. Điều này cực kỳ tiện lợi trong các tình huống mà bạn không thể kiểm soát ngày phát hành của phiên bản mới trên tất cả các nền tảng (Steam, Mac App Store, iPhone, Android ...).

Để có cái nhìn sâu sắc hơn, hãy xem các câu hỏi được gắn thẻ [dựa trên thành phần][hệ thống thực thể] .


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.