1. Component based thường dùng trong các game engine là vì sao?
- Lý do ko phải là vì cấu trúc code như kế thừa chồng chéo. Mà do game engine cần quy định sẵn các GameObject để thực hiện rất nhiều low level task ví dụ như redering, culling..
2. Component based độc lập với OOP?
- Đầu tiên bạn cần phải phân biệt khái niệm OOP với ngôn ngữ lập trình. Theo bạn nói thì bất kỳ class implement System.Object trong C# là object trong OOP, cái này đúng trong hầu hết chương trình vì nó mặc định là như thế.
- Nhưng trong game engine với Component Based thì nó lại đưa ra khái niệm GameObject mới là Object trong 1 scene. Mà nó lại ko cho kế thừa hay viết lại GameObject mà chỉ có thể thêm bớt Component. Như vậy khi áp dụng khái niệm OOP vào sẽ xung đột. Đương nhiên nếu bạn khăng khăng khẳng định nó là OOP thì cũng đúng ko sai
![Big grin :D :D](https://data.voz.vn/styles/next/xenforo/smilies/popo/biggrin.png?v=01)
3. OOP cuối cùng cũng là khái niệm, vì nó xoắn suýt tốn time mình thấy rất vô ích nên mới comment có mấy phần phiến diện, chứ bản thân mình vẫn thường dùng OOP nếu thực sự cần.
Giải quyết từng ý nhé
1. Bạn đọc thêm về component design pattern (hay tên trong định nghĩa của GoF là Composite) ở đây. Mục đích chính, ngoài việc hạn chế kế thừa chồng chéo là để cho phép thay đổi hành vi của đối tượng lúc runtime.
https://en.wikipedia.org/wiki/Composite_pattern
https://gameprogrammingpatterns.com/component.html
2. Mình chưa hề nói gì đến ngôn ngữ áp dụng trong bất kỳ comment nào trước đó cả. Nguyên văn ý mình nói là Component, cụ thể là quan hệ GameObject-Component của Unity, chỉ là một design pattern ở mức kiến trúc.
Khi ấy về cơ bản thì mỗi GameObject có một mảng các Component object (quan hệ kết tập của OOP, composition). Các Component class khác nhau như custom MonoBehaviour, MeshRenderer, Rigidbody, BoxCollider, v.v.. đều có parent class, có member variable và có member method.
Định nghĩa của OOP là chương trình được tạo nên bởi các đối tượng, mỗi đối tượng đều đóng gói dữ liệu và hành vi của chúng. Tất cả các đặc tính trên của Unity Scripting API đều thỏa mãn định nghĩa này.
* Ghi chú riêng ý "OOP và ngôn ngữ lập trình" của bạn: "Theo bạn nói thì bất kỳ class implement System.Object trong C# là object trong OOP, cái này đúng trong hầu hết chương trình vì nó mặc định là như thế."
Mình nói "chương trình được tạo nên bởi các object": mình không nhắc tới System.Object của C#, mà mình nói về khái niệm "đối tượng" tổng quát của OOP thôi.
Nói khá hay, +1.
Unreal thì chưa mò, còn Unity thì khá chắc ECS trên đó chưa hoàn thiện.
Tiện thì cho hỏi, ngoài 2 engine kia ra thì b có suggest engine nào có Component based xịn hơn ko?
Component based là một design pattern phổ biến thím à, khá chắc kèo rằng các engine hiện đại đều áp dụng pattern này ở một vài mức độ. Unity thì cấm tiệt kế thừa GameObject như thím
@gbvn1 đã nói, nên lập trình viên chỉ kế thừa được một loại Component đặc biệt tên là MonoBehaviour. Unreal thì phức tạp hơn, AActor (tương tự GameObject của Unity) có rất nhiều class con cháu như APawn hay ACharacter, cũng không cấm viết các custom class. Component class cũng có nhiều loại như UActorComponent và USceneComponent.
Còn ECS là một kiến trúc/tư duy khác nữa nhé
- EC (Entity-Component): cái này là tương tự với framework của Unity và Unreal, tuân theo design pattern Composite ở trên, với class Entity bao gồm một collection của các Component instance. Các component có data và behaviour.
VD pseudocode:
C++:
class Entity
{
Vector3 position; // class Entity hoàn toàn có thể chứa thứ khác ngoài component
std::vector<Component*> components
};
class Component
{
Entity* owner;
};
class MoveComponent {
void Move()
{
// move owner using owner->position
}
};
- ECS (Entity-Component-System): Entity ở đây không phải là một class mà chỉ là một ID, còn Component hoàn toàn chứa data mà thôi. Tưởng tượng nó như một mini relational database ấy, cũng có các phép toán query (entity này có component nào, có bao nhiêu entity có cụm component ABC này,...), add/remove component cho entity. Behaviour giờ đây được đẩy cho các System.
C++:
using EntityId = int32;
using ComponentId = int32;
struct PositionComponent { EntityId owner; Vector3 value; }
struct MoveComponent { EntityId owner; float speed; }