Một Số Kế Hoạch Cải Tiến Cho Ant Engine - nói dối e blog

Một Số Kế Hoạch Cải Tiến Cho Ant Engine

Tôi đã phát triển game một mình được ba tháng nay. Trong suốt khoảng thời gian đó, tôi là người dùng duy nhất còn hoạt động trên Ant Engine – điều này mang lại cơ hội quý giá để tôi nhận ra những thiếu sót của engine khi làm việc như một nhà phát triển game độc lập. Hiện tại, tôi vẫn muốn tập trung nhiều hơn vào việc phát triển game, còn các công việc liên quan đến engine chỉ cần đủ dùng là được. Dù vậy, việc hoàn thiện engine lại là điều khiến tôi cảm thấy hứng thú hơn, bởi lẽ những công việc này tương đối trơn tru, dễ dàng suy nghĩ rõ ràng và xử lý mượt mà. Ngược lại, khi phát triển game một mình, cảm giác bực bội thường xuyên xuất hiện do tay không theo kịp ý tưởng.

Tôi vẫn muốn thử thách bản thân bằng cách thiết kế và hiện thực hóa game thật tốt. Những ý tưởng liên quan đến engine, tôi sẽ ghi chú lại trước. Có lẽ sau khi hoàn thành dự án game hiện tại, tích lũy thêm kinh nghiệm, tôi sẽ quay lại làm engine với cảm giác thỏa mãn hơn.

Đầu tiên, đối với tôi, trình soạn thảo trực quan không quá quan trọng nên tạm thời tôi sẽ không duy trì nó nữa. Thay vào đó, tôi cần những công cụ giúp nhanh chóng kiểm chứng các ý tưởng thiết kế game đang phát triển – những thứ này có thể tích hợp trực tiếp vào demo game, không cần đưa vào editor. Điều này cũng liên quan đến việc hiện tại chưa có sự tham gia của họa sĩ. Vì là người làm indie, tôi không quá bận tâm đến tiến độ: việc làm họa trước hay sau đều không khác biệt lớn. Bản thân tôi vốn yêu thích thể loại roguelike cổ điển, chỉ cần vài ký tự ASCII cũng đủ để tưởng tượng ra toàn bộ hình ảnh. Tôi cho rằng trong giai đoạn prototype, không cần thiết phải có họa sĩ sáng tạo trong editor – sử dụng các hình khối hình học đơn giản là đủ. Đây cũng chính là lý do vì sao ba tháng trước, tôi ưu tiên hoàn thiện chức năng “prefab hình học” trong Ant Engine.

Khi sử dụng Ant Engine, tôi nhận ra việc thiếu tài liệu API chi tiết khiến tôi phải liên tục đọc lại mã nguồn (vì nhiều module không do tôi viết, nên không thể nắm rõ toàn bộ). Chưa kể, không phải thiết kế module nào cũng khiến tôi hài lòng, điều này khiến tôi thường xuyên có ý định sửa đổi engine. Sau một thời gian, tôi đã tìm ra cách giải quyết vấn đề này. Tôi sẽ xây dựng thêm một framework phiên bản rút gọn, bắt đầu từ những chức năng cơ bản nhất theo nhu cầu phát triển game hiện tại, rồi dần hoàn thiện. Cách này giúp tôi tách biệt các phần đã có sẵn trong engine: các module ổn định sẽ được bao bọc đơn giản, còn những phần có vấn đề sẽ được cải tiến sâu hơn mà không làm ảnh hưởng đến mã nguồn cũ.

Do đặc thù khác nhau giữa các thể loại game, cách sử dụng engine cũng sẽ có sự khác biệt lớn. Tôi hy vọng có thể xây dựng nhiều framework thứ cấp nhắm vào từng thể loại cụ thể. Khi đó, việc phát triển game trên các framework này sẽ cho phép tôi tự tin hơn trong việc tối ưu hóa phần nền tảng phía dưới. Tôi mong muốn đưa hệ thống ECS trở về thiết kế nguyên bản hơn: tập trung vào dữ liệu, tránh thêm quá nhiều module hỗ trợ.

Gần đây, tôi cũng dành nhiều thời gian cải tiến giao diện người dùng (UI). Về giải pháp RmlUI, tôi khá hài lòng vì cách tiếp cận kiểu web có cơ sở người dùng khổng lồ, mọi chi tiết đều được mài giũa kỹ lưỡng. Tuy nhiên, một số chi tiết hiện tại, đặc biệt là cơ chế truyền thông điệp giữa lớp UI và logic game, vẫn còn tồn tại thiết kế chưa hợp lý.

Hiện tại, UI và phần render/logic game đang chạy trên hai máy ảo Lua (Lua VM) cách biệt, ở hai luồng khác nhau, giao tiếp thông qua việc truyền thông điệp. Engine đã bao bọc quá trình này một cách đơn giản và cung cấp phương thức RPC. Tuy nhiên, nếu gọi RPC từ logic game đến UI một cách trực tiếp, sẽ xảy ra hiện tượng deadlock. Lý do là vì logic game thường được thực thi trong một stage của hệ thống ECS, trong khi xử lý yêu cầu RPC từ UI lại nằm ở stage khác. Để tránh deadlock, tôi phải cẩn thận sử dụng các chức năng bất đồng bộ của ltask. Sau khi thực hiện một vài lớp bao bọc đơn giản, tình hình đã được cải thiện. Lớp bao bọc này tạo ra một đối tượng “model”, tự động đồng bộ dữ liệu giữa hai tầng (chỉ đồng bộ phần khác biệt). Khi thiết lập trạng thái của model từ phía logic game, giao diện UI sẽ tự động cập nhật. Tuy nhiên, lớp bao bọc này vẫn còn thô sơ, cần được cải tiến thêm sau khi tôi xây dựng nhiều module UI hơn.

Từ đây, tôi nhận ra hệ thống ECS có lẽ nên bổ sung thêm một stage bất đồng bộ (async stage). Hiện tại, nếu gọi ltask.call trong một stage thông thường, toàn bộ khung hình (frame) sẽ bị nghẽn. Nếu có async stage, các tiến trình yield sẽ được tiếp tục ở stage tương ứng của khung hình tiếp theo. Cách này cũng có thể thay thế cơ chế callback onready khi tạo instance, cho phép viết mã tự nhiên hơn bằng cách đưa các xử lý thông điệp vào async stage. Trước đây tôi đã thử nghiệm ý tưởng tương tự nhưng vẫn chưa hoàn toàn hài lòng, nên tạm thời chưa đưa vào engine.

Module hoạt ảnh (animation) hiện vẫn còn yếu kém. Tuy nhiên, vì đang làm prototype nên tôi chưa cần đến nó. Khi phát triển game hành động trong tương lai, nhu cầu này sẽ tăng cao. Do đó, ưu tiên phát triển module này vẫn còn thấp, sẽ giải quyết khi thực sự cần dùng.

Hệ thống vật liệu (material system) lại là phần đáng được cải tiến hơn. Trong quá trình phát triển, tôi gặp phải một yêu cầu đơn giản: thay đổi đối tượng sang chế độ trong suốt khi chạy chương trình. Việc này đã khiến tôi đau đầu suốt vài ngày trời. Cuối cùng, tôi đành quay lại giải pháp từng dùng năm ngoái: tạo patch dữ liệu prefab trong editor, đồng thời tiền tạo sẵn các vật liệu trong suốt cho từng prefab. Khi chạy chương trình, tôi chỉ cần chọn giữa prefab trong suốt và không trong suốt (vì engine hiện chưa hỗ trợ gán vật liệu hoàn toàn khác nhau cho đối tượng khi đang chạy).

Vấn đề vật liệu trong suốt này thực chất liên quan đến tối ưu hiệu năng. Về lý thuyết, chúng ta có thể để mọi đối tượng đều dùng vật liệu trong suốt, chỉ cần điều chỉnh độ trong suốt về 1.0 để hiển thị không trong suốt, hoặc 0 để ẩn đi. T

0%