Làm thế nào hướng đối tượng là trò chơi điện tử? [đóng cửa]


18

Tôi đã luôn tự hỏi mức độ định hướng đối tượng được sử dụng bởi các trò chơi video, đặc biệt là các dự án 3D lớn. Tôi nghĩ rằng sẽ rất tuyệt nếu cả hai trollwerewolfthừa hưởng các thuộc tính của nó từ enemyvà ghi đè lên một số trong số chúng. Nhưng có lẽ các lớp học quá nặng để thực tế, tôi không biết ...


2
Làm thế nào để định lượng (hoặc thậm chí đủ điều kiện khách quan) định hướng đối tượng? Bạn có muốn một câu trả lời trong Meyers hoặc Dahl-Nygaards?

Rõ ràng là chúng nặng đến nỗi một ngôn ngữ dựa trên OO nặng nề là tiêu chuẩn công nghiệp.
Vịt Cộng sản

4
Nếu bạn có nghĩa là C ++, thì nó được chọn vì đó là một ngôn ngữ tốt để khám phá lập trình chung an toàn kiểu theo cách có ý thức tốc độ; một vài tính năng OOP rõ ràng là một sai lầm đáng tiếc được giữ lại chỉ để tương thích ngược. ;)

Câu trả lời:


20

Để đến với ví dụ của bạn, tôi sẽ giải thích suy nghĩ của tôi về Entites trong các trò chơi video. Tôi sẽ không thảo luận về lợi thế và bất lợi chung của các đối tượng và các lớp, cả vai trò của chúng trong Trò chơi điện tử.

Các thực thể trong các trò chơi video nhỏ hầu hết được xác định bởi các lớp riêng biệt, trong các trò chơi lớn, chúng thường được xác định trong các tệp. Có hai cách tiếp cận chung để tuân theo:

Mở rộng : Trong ví dụ của bạn TrollWerewolfsẽ mở rộng Enemy, mở rộng Entity. Entityquan tâm đến những điều cơ bản như chuyển động, sức khỏe, v.v., trong khi Enemysẽ nêu các lớp con là kẻ thù và làm những việc khác (Minecraft tuân theo cách tiếp cận này).

Dựa trên thành phần : Cách tiếp cận thứ hai (và yêu thích của tôi) là một Entitylớp, có các thành phần. Một thành phần có thể Moveablehoặc Enemy. Các thành phần này chăm sóc một thứ như chuyển động hoặc vật lý. Phương pháp này phá vỡ các chuỗi mở rộng dài và giảm thiểu rủi ro xảy ra xung đột. Ví dụ: Làm thế nào bạn có thể tạo Kẻ thù không thể di chuyển, nếu chúng thừa hưởng từ một Nhân vật có thể di chuyển? .

Trong các trò chơi điện tử lớn như World of Warcraft hay Starcraft 2, các thực thể không phải là các lớp, mà là các bộ dữ liệu, trong đó chỉ định toàn bộ Thực thể. Viết kịch bản cũng rất quan trọng, bởi vì bạn xác định những gì Thực thể không có trong Lớp, nhưng trong Tập lệnh (nếu là duy nhất, không phải là những thứ như di chuyển).

Tôi hiện đang lập trình một RTS và tôi sử dụng cách tiếp cận dựa trên thành phần với các tệp Mô tả và Tập lệnh cho các Mục, Kỹ năng, Vật phẩm và mọi thứ khác động trong trò chơi.


2
Âm thanh xen kẽ. Tuy nhiên tôi sẽ không nói dối, tôi không biết a componentlà gì trong bối cảnh này. Một liên kết sẽ được nhiều đánh giá cao.
vemv

Một thành phần là một thực thể có trách nhiệm cho một chức năng duy nhất. Thực thể dựa trên thành phần sẽ sở hữu một thành phần (nếu là trường hợp) nó sẽ không kế thừa từ nó. Quyền sở hữu ngụ ý rằng một thực thể có thể hủy kích hoạt một trong các thành phần thay đổi hành vi của nó. Trong mô hình mở rộng cổ điển, hành vi là do "thuộc về" một siêu hạng. Một thực thể có thể là một thành phần và một thành phần có thể được mô hình hóa thành một lớp hoặc như một cấu trúc nếu bạn thích.
FxIII

Thành phần (đôi khi được gọi là hệ thống Thực thể) - bạn có thể tìm kiếm blog này để tìm ý tưởng t-machine.org Có các biến thể nhưng ý tưởng cơ bản là một thành phần là một đối tượng có mục đích đặc biệt và diễn viên của bạn liên kết với nhau một loạt các thành phần, như xây dựng mô hình từ Legos.
Patrick Hughes

2
Tôi bắt đầu một blog về phát triển trò chơi và viết bài viết đầu tiên về blog này. Không có gì mới, nhưng với một chút mã: jagamedev.wordpress.com/2011/06/26/ trên
Marco

23

Tôi nghĩ sẽ thật tuyệt khi cả troll và người sói đều thừa hưởng thuộc tính của nó từ kẻ thù và ghi đè lên một số trong số chúng.

Thật không may, cách tiếp cận đa hình này, phổ biến trong những năm 90, đã cho thấy nó là một ý tưởng tồi trong thực tế. Hãy tưởng tượng bạn thêm 'sói' vào danh sách kẻ thù - tốt, nó chia sẻ một số thuộc tính với người sói, vì vậy bạn muốn hợp nhất chúng thành một lớp cơ sở chung, ví dụ. "Sói". Bây giờ bạn thêm 'Người' vào danh sách kẻ thù, nhưng người sói đôi khi là con người, vì vậy họ cũng chia sẻ các thuộc tính, chẳng hạn như đi bằng 2 chân, có thể nói chuyện, v.v. Bạn có tạo cơ sở chung 'Người hình người' cho người và người sói không và sau đó bạn có phải ngăn người sói xuất phát từ WolfLike không? Hay bạn nhân bội thừa kế từ cả hai - trong trường hợp nào, thuộc tính nào được ưu tiên khi một thứ gì đó trong Humanoid đụng độ với thứ gì đó trong WolfLike?

Vấn đề là việc cố gắng và mô hình hóa thế giới thực như một cây các lớp là không hiệu quả. Lấy 3 thứ bất kỳ và có lẽ bạn có thể tìm thấy 4 cách khác nhau để đưa yếu tố hành vi của họ vào chia sẻ và không chia sẻ. Đây là lý do tại sao nhiều người đã chuyển sang mô hình dựa trên mô-đun hoặc thành phần thay vào đó, trong đó một đối tượng bao gồm một số đối tượng nhỏ hơn tạo nên tổng thể và các đối tượng nhỏ hơn có thể được hoán đổi hoặc thay đổi để tạo nên hành vi bạn muốn. Ở đây bạn có thể chỉ có 1 lớp Enemy và nó chứa các đối tượng hoặc thành phần phụ để di chuyển (ví dụ: Bipedal so với Quadrupedal), các phương thức tấn công của nó (ví dụ: cắn, vuốt, vũ khí, nắm đấm), da của nó (màu xanh lá cây cho troll, lông cho người sói và sói), v.v.

Điều này vẫn hoàn toàn hướng đối tượng, nhưng khái niệm về một đối tượng hữu ích khác với những gì thường được dạy trong sách giáo khoa. Thay vì có một cây thừa kế lớn gồm nhiều lớp trừu tượng khác nhau và một số lớp cụ thể ở đầu cây, bạn thường chỉ có 1 lớp cụ thể đại diện cho một khái niệm trừu tượng (ví dụ: 'kẻ thù') nhưng chứa nhiều lớp cụ thể hơn đại diện cho các khái niệm trừu tượng hơn (ví dụ như các cuộc tấn công, loại da). Đôi khi các lớp thứ hai này có thể được triển khai tốt nhất thông qua 1 mức kế thừa (ví dụ: lớp Tấn công cơ sở và một số lớp dẫn xuất cho các cuộc tấn công cụ thể) nhưng cây thừa kế sâu đã biến mất.

Nhưng có lẽ các lớp học quá nặng để thực tế, tôi không biết ...

Trong hầu hết các ngôn ngữ hiện đại, các lớp học không 'nặng'. Chúng chỉ là một cách viết mã khác và chúng thường chỉ bao gồm cách tiếp cận theo thủ tục mà bạn sẽ viết bằng mọi cách, ngoại trừ với cú pháp dễ dàng hơn. Nhưng bằng mọi cách, đừng viết một lớp trong đó một hàm sẽ làm. Các lớp học về bản chất không tốt hơn, chỉ là nơi chúng làm cho mã dễ quản lý hoặc dễ hiểu hơn.


3
Thích câu trả lời này :)
Czarek Tomczak

8

Tôi không chắc ý của bạn là "quá nặng", nhưng C ++ / OOP là ngôn ngữ chung của sự phát triển trò chơi vì những lý do chính đáng mà nó được sử dụng ở nơi khác.

Nói về bộ đệm thổi là một vấn đề thiết kế, không phải là một tính năng ngôn ngữ. C ++ không thể quá tệ vì nó đã được sử dụng trong các trò chơi trong 15-20 năm qua. Java không thể quá tệ vì nó được sử dụng trong môi trường thời gian chạy rất chặt chẽ của điện thoại thông minh.

Bây giờ đến câu hỏi thực sự: trong nhiều năm, hệ thống phân cấp lớp trở nên sâu sắc và bắt đầu phải chịu những vấn đề liên quan đến điều đó. Trong thời gian gần đây, hệ thống phân cấp lớp đã được làm phẳng và thành phần và các thiết kế dựa trên dữ liệu khác đang được thay vì kế thừa theo định hướng logic.

Đó là tất cả OOP và vẫn được sử dụng làm cơ sở khi thiết kế phần mềm mới, chỉ tập trung vào những gì các lớp thể hiện.


2

Các lớp học không liên quan đến bất kỳ thời gian chạy. Đa hình thời gian chạy chỉ là gọi thông qua một con trỏ hàm. Các chi phí này cực kỳ nhỏ so với các chi phí khác như Gọi cuộc gọi, đồng bộ hóa đồng thời, I / O đĩa, chuyển đổi chế độ nhân, địa phương bộ nhớ kém, sử dụng quá mức phân bổ bộ nhớ động, lựa chọn thuật toán kém, sử dụng ngôn ngữ kịch bản và danh sách tiếp tục. Có một lý do mà định hướng đối tượng về cơ bản đã thay thế những gì xuất hiện trước nó, và đó là vì nó tốt hơn nhiều.


Phân phối giữa các loại đa hình khác nhau được thực hiện theo cách cung cấp cho địa phương bộ nhớ kém. Ngay cả trong các triển khai trọng lượng nhẹ nhất như C ++ vtables hoặc Objective-C IMP bộ nhớ đệm, nếu bạn thực sự sử dụng đa hình để đối phó với các đối tượng thuộc các loại khác nhau, bạn sẽ thổi bộ nhớ cache của mình. Tất nhiên, nếu bạn không sử dụng tính đa hình hơn so với vtable trong bộ nhớ cache của bạn hoặc thông báo được lưu trong bộ nhớ cache của IMP dẫn đến vị trí chính xác, nhưng tại sao lại phải bận tâm? Và trong Java hoặc C #, chi phí nặng hơn và trong JavaScript hoặc Python, chi phí vẫn nặng hơn.

1
@Joe Wreschnig: Nếu bạn đang sử dụng những ngôn ngữ chậm hơn đó, thì chi phí của OO là không đáng kể so với các chi phí khác như giải thích / JIT. Quan trọng hơn, bạn có thể đưa ra lý thuyết những gì bạn muốn về địa phương bộ nhớ kém, nhưng thực tế là dự đoán chi nhánh, thực hiện không theo thứ tự và các tính năng tương tự trên CPU hầu như hoàn toàn phủ nhận chi phí. Khác, tại sao có quá nhiều phần mềm hiệu năng cao được viết bằng hướng đối tượng?
DeadMG

1

Một điều cần lưu ý là các khái niệm về mã hướng đối tượng thường có giá trị hơn so với việc thực hiện bằng ngôn ngữ. Cụ thể, việc phải thực hiện 1000 lượt gọi cập nhật ảo trên các thực thể trong một vòng lặp chính có thể gây ra sự lộn xộn trong bộ đệm trong C ++ trên các nền tảng như 360 hoặc PS3 - vì vậy việc triển khai có thể tránh các từ khóa "ảo" hoặc thậm chí là "lớp" của tốc độ.

Thông thường mặc dù nó vẫn sẽ tuân theo các khái niệm kế thừa và đóng gói OO - chỉ thực hiện chúng theo cách khác với ngôn ngữ (ví dụ: các mẫu đệ quy tò mò, thành phần thay vì kế thừa (phương pháp dựa trên thành phần được mô tả bởi Marco)). Nếu kế thừa luôn có thể được giải quyết tại thời gian biên dịch thì các vấn đề về hiệu năng sẽ biến mất, nhưng mã có thể trở nên hơi rườm rà với các mẫu, triển khai RTTI tùy chỉnh (một lần nữa, các công cụ tích hợp thường chậm chính xác) hoặc logic thời gian biên dịch trong macro, v.v.

Trong Objective-C cho iOS / Mac có những vấn đề tương tự, nhưng tồi tệ hơn với sơ đồ nhắn tin (ngay cả với các công cụ lưu trữ ưa thích) ...


0

Phương thức mà tôi sẽ cố gắng sử dụng kết hợp kế thừa lớp và các thành phần. (Trước hết, tôi không biến Enemy thành một lớp - Tôi biến nó thành một thành phần.) Tôi không thích ý tưởng sử dụng một lớp Entity chung cho mọi thứ và sau đó thêm các thành phần cần thiết để bổ sung thực thể. Thay vào đó, tôi thích có một lớp tự động thêm các thành phần (và giá trị mặc định) trong hàm tạo. Sau đó, các lớp con thêm các thành phần bổ sung của chúng trong hàm tạo của chúng, vì vậy lớp con sẽ có các thành phần và các thành phần lớp cha của nó. Ví dụ, một lớp Vũ khí sẽ thêm các thành phần cơ bản phổ biến cho tất cả các vũ khí, và sau đó lớp phụ Kiếm sẽ thêm bất kỳ thành phần bổ sung nào dành riêng cho kiếm. Tôi vẫn đang tranh luận về việc có nên sử dụng tài sản văn bản / xml để xác định giá trị cho các thực thể (hoặc thanh kiếm cụ thể chẳng hạn), hoặc để làm tất cả trong mã, hoặc kết hợp đúng là gì. Điều này vẫn cho phép trò chơi sử dụng thông tin và tính đa hình của ngôn ngữ mã và làm cho ObjectFactories đơn giản hơn nhiều.


3
Này Chris. Mặc dù chia sẻ kinh nghiệm và kế hoạch của bạn là tuyệt vời, nhưng nó không thực sự trực tiếp trả lời câu hỏi. Tôi nghĩ rằng câu hỏi liên quan nhiều hơn đến việc những thứ này thường được thực hiện như thế nào khi bạn trả lời về cách bạn dự định thực hiện nó . Chúng là những câu hỏi tương tự, nhưng không thực sự giống nhau.
MichaelHouse
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.