Giới thiệu
Khi bắt đầu lập trình game, phương pháp lập trình Hướng đối tượng (Object Oriented Programming – OOP) là phương pháp rất quen thuộc. Các đối tượng sẽ kế thừa từ 1 lớp gọi là GameObject
, các đối tượng có các đặc điểm tương tự nhau sẽ được gom lại và kế thừa từ 1 đối tượng cơ sở. Phương pháp này khá hiệu quả đối với những game cỡ nhỏ, có ít loại đối tượng trong game. Tuy nhiên, khi cần nâng cấp game hoặc mở rộng thêm các tính năng khác, lập trình viên sẽ phải tuỳ biến chương trình rất nhiều để phù hợp với định hướng mới. Game ngày càng phức tạp và đa dạng, phương pháp này sẽ gây khó khăn cho lập trình viên.
Phương pháp lập trình Hướng thành phần (Component-base Development - CBD) ra đời, khắc phục các vấn đề mà OOP đơn thuần không thể làm được, đồng thời đem lại nhiều ưu điểm trong lập trình, bảo trì và nâng cấp game.
Bài viết này giới thiệu rõ phương pháp lập trình này và có cái nhìn khác hơn về lập trình game.
Nhược điểm của OOP
Giả sử thiết kế game thay đổi, các đối tượng có liên quan đều phải thay đổi theo. Điều này gây mất thời gian và có khả năng bỏ sót các đối tượng. Nâng cấp game đồng nghĩa với việc tuỳ biến source code rất nhiều.
1 quy tắc mà các lập trình viên đều biết là DRY – Don’t Repeat Yourself. Trừ 1 số trường hợp mà phương thức có mặt ở tất cả các đối tượng con, các phương thức đều phải được hiện thực lại ở từng đối tượng. Do đó đây sẽ là 1 sự lặp lại code 1 cách vô nghĩa.
Đối với các game có quy mô nhỏ, do số lượng đối tượng không nhiều và phức tạp, việc chỉnh sửa mã nguồn và lặp lại các đoạn code để phù hợp với định hướng mới là điều có thể chấp nhận được. Tuy nhiên đối với các game quy mô lớn hơn, phương pháp này là không hiệu quả, quá tốn chi phí công sức và thời gian. Do đó cần có 1 phương pháp khác khắc phục được các nhược điểm này, đó là lúc mà lập trình viên bắt đầu biết đến phương pháp lập trình Hướng thành phần.
Tư tưởng
Phương pháp CBD sẽ xem tất cả các đối tượng là giống nhau, không phân biệt Tank
hay Bullet
, Person
hay Animal
, ... Các đối tượng ban đầu sẽ ở trạng thái không có gì NULL
. Khi đối tượng cần có 1 chức năng, thì lập trình và thêm chức năng (component) đó vào cho đối tượng cụ thể. Nhờ các chức năng đặc trưng đó mà có thể phân biệt được các đối tượng với nhau.
Phương pháp CBD đã khắc phục được các nhược điểm của OOP, đồng thời mang lại nhiều ưu điểm vượt trội so với OOP trong lập trình game. Tuy nhiên, đổi lại việc thiết kế 1 chương trình theo CBD là phức tạp hơn, đòi hỏi lập trình viên tư duy theo hướng mở hơn.
Các ưu điểm của CBD
Giảm thời gian, chi phí build các chương trình lớn và phức tạp vì các đối tượng đều giống nhau, các chức năng thành phần đều là những con trỏ nên việc thực thi chương trình sẽ ít tốn thời gian hơn.
Tăng khả năng tuỳ biến, cải thiện chất lượng game, chất lượng sẽ được cải thiện bằng cách nâng cấp các component.
Dễ dàng sửa lỗi, bảo trì và nâng cấp do mỗi component sẽ có 1 chức năng riêng biệt và không lặp lại. Dễ dàng khoanh vùng chức năng nào còn thiếu sót để hoàn thiện nó.
Mô hình CBD
Các component sẽ được gắn vào từng Entity
thông qua con trỏ. Entity
sẽ quản lý các con trỏ này và cập nhật từng component sau mỗi vòng lặp.
Hiện thực
Với Component-based Development, ta có 1 số đối tượng bắt buộc như sau:
Entity
Entity là 1 đối tượng ở trong game, ban đầu tất cả các đối tượng đều không chứa dữ liệu về bất kỳ chức năng nào. Tuy nhiên, để tiện cho các thao tác sau này, có thể thêm 1 thuộc tính để phân biệt các Entity
. Sử dụng 1 thuộc tính kiểu chuỗi để lưu trữ tag
(nhóm đối tượng) của Entity
.
Component
Mỗi component là 1 chức năng riêng biệt, không trùng lặp nhau. Vì Entity
chỉ chứa danh sách các địa chỉ của component, nên cần 1 điểm chung giữa các component để có thể quản lý tập trung thành danh sách. Do đó, tất cả các component đều phải được kế thừa từ 1 lớp abstract Component.
1 số component quan trọng mà bất kỳ đối tượng nào cũng cần có là Transform
, Renderer
, ... các chức năng cần thiết có thể tự hiện thực dựa trên logic game.
Khi cần sử dụng 1 hàm riêng của 1 component, sử dụng kỹ thuật ép kiểu (casting) dữ liệu từ abstract component sang component cụ thể.
EntitySystem
Các Entity
được tạo ra sẽ cần 1 nơi để quản lý. Nhiệm vụ của EntitySystem
là lưu trữ danh sách các Entity
đã được tạo ra và cập nhật các Entity
sau mỗi vòng lặp. EntitySystem
là duy nhất trong 1 chương trình nên sử dụng Singleton Pattern để hiện thực.
CBD với Unity Engine và Cocos2d-x
Unity là 1 trong những Game engine phổ biến và dễ sử dụng nhất hiện nay. Unity được các nhà sáng lập định hướng theo CBD, các chức năng đặc trưng của các đối tượng sẽ do lập trình viên hiện thực và thêm vào đối tượng.
Project mẫu về CBD
Đây chỉ là project demo đơn giản giúp hiểu ý nghĩa của phương pháp CBD, trong project có sử dụng game loop và kỹ thuật giới hạn FPS.
Bài chung series
- CBP-0: Giới Thiệu về Component Base Development
- CBP-1: Tổng Quan về Project Ví Dụ
- CBP-2: Khai Báo Component Cơ Sở và Entity Cơ Bản
- CBP-3: Khai Báo Component Cơ Bản, Tích Hợp Component vào Entity
- CBP-4: Giao Tiếp với Entity – Hệ Thống Chỉ Lệnh
- CBP-5: Truyền và Lấy Thông Số từ Component
- CBP-6: Hàng Đợi Chỉ Lệnh
- CBP-7: Cài Đặt Phản Ứng cho Entity
- CBP-8: Component Điều Khiển và AI – Component Ra Lệnh
- CBP-9: Bộ Khởi Tạo Entity – Factory và Hệ Thống ID
- CBP-10: Hệ Thống Quản Lý Tập Trung Các Component Đặc Thù