Hệ Thống Chất Lỏng
Trong tựa game mô phỏng kiểu Factorio mà nhóm chúng tôi đang phát triển, hệ thống chất lỏng đóng vai trò trọng tâm trong cơ chế logistics. Cá nhân tôi cho rằng đây là subsystem phức tạp nhất cần xây dựng.
Factorio từng trải qua nhiều lần cải tiến hệ thống chất lỏng, với ít nhất ba bản cập nhật được ghi nhận trong nhật ký phát triển: “New fluid system”, “Fluid optimisations” và “New fluid system 2”. Là game thủ gắn bó 2000 giờ với tựa game này trong 5 năm qua, tôi nhận thấy quá trình hoàn thiện hệ thống này chưa từng dừng lại. Đến tận ngày nay, vẫn còn những hành vi “phi trực giác” tồn tại trong cách vận hành hệ thống chất lỏng.
Thiết kế hệ thống chất lỏng hiệu quả đòi hỏi cân bằng giữa hiệu suất và tính mô phỏng thực tế. Khi tựa game nhái lại Factorio là Dyson Sphere Program ra mắt, tôi đặc biệt quan tâm đến cách họ xử lý hệ thống ống dẫn. Tuy nhiên, điều tôi nhận được chỉ là sự thất vọng khi họ gần như loại bỏ hoàn toàn hệ thống chất lỏng.
Trong Factorio, tôi đặc biệt yêu thích các gameplay phụ sinh ra từ hệ thống chất lỏng. Chính vì vậy, ngay cả khi chưa xây dựng hệ thống băng chuyền, chúng tôi vẫn quyết tâm phát triển một subsystem chất lỏng riêng. Thiết kế của chúng tôi tham khảo các bài viết phân tích trước đây và bổ sung thêm những ý tưởng độc đáo.
Một hệ thống chất lỏng hấp dẫn cần giải quyết những vấn đề cốt lõi sau:
- Phân biệt với hệ thống điện: Chất lỏng phải có quá trình di chuyển rõ ràng, không lan tỏa tức thì khắp mạng lưới khi được bơm vào.
- Phân nhánh công bằng: Tại các điểm T, nếu hai nhánh ống dẫn giống nhau, lưu lượng phải chia đều. Tương tự, khi hợp lưu, lượng chất lỏng từ các nhánh phụ phải được hấp thụ đồng đều.
- Độc lập với thứ tự xây dựng: Quy tắc lưu thông chỉ dựa trên lượng chất lỏng trong ống, không phụ thuộc vào thứ tự xây dựng hay ID của ống.
- Bảo toàn khối lượng: Tổng lượng chất lỏng phải tuyệt đối không đổi, tránh sai lệch do tính toán số thực.
- Xử lý vòng lặp: Thuật toán phải hoạt động ổn định ngay cả khi mạng lưới có vòng kín do bơm tạo ra.
- Khả năng nâng cấp: Ống dẫn cần có cơ chế nâng cấp mở ra gameplay mới.
Factorio đã thu thập hàng ngàn ý kiến từ cộng đồng, trong đó có cả các kỹ sư cơ khí, điện tử, chuyên gia toán học và vật lý. Điều này chứng tỏ vấn đề vừa thú vị vừa phức tạp. Tuy nhiên, tôi không theo đuổi việc mô phỏng vật lý hoàn hảo - điều vừa khó kiểm soát vừa thiếu tính xác định. Mục tiêu của tôi là xây dựng hệ thống đơn giản, trực quan và vui vẻ.
Khi mới chơi Factorio, tôi từng bối rối trước nguyên lý hoạt động của hệ thống chất lỏng. Nhưng nhờ tính trực quan, điều này không cản trở trải nghiệm. Tuy nhiên, với vai trò nhà phát triển, tôi không thể để bản thân mù mờ. Ví dụ: Tại sao ống dẫn càng dài thì chất lỏng di chuyển càng chậm, buộc phải lắp bơm tăng áp?
Khác với băng chuyền - nơi vật phẩm di chuyển tức thời bất kể chiều dài, hệ thống ống dẫn có tốc độ truyền dẫn phụ thuộc vào độ dài. Khi ống quá dài, người chơi phải lắp bơm định kỳ để duy trì lưu tốc. Điều này xuất phát từ bản chất vật lý: Trong ống dẫn kín, chất lỏng di chuyển nhờ chênh lệch thế năng, tạo thành mặt dốc nghiêng. Ống càng dài, độ dốc càng thoải, khiến lưu lượng giảm mạnh.
Dựa trên nguyên lý này, tôi xây dựng thuật toán đơn giản: Xem chất lỏng như hệ thống tĩnh, nơi lưu lượng chỉ phụ thuộc vào mực nước trong từng đoạn ống. Chất lỏng luôn chảy từ nơi mực nước cao sang thấp, với tốc độ tỷ lệ thuận với chênh lệch mực nước. Thuật toán này đơn giản hơn cả của Factorio, vốn còn tính đến vận tốc lưu thông từ khung giờ trước.
Ban đầu tôi cố gắng thiết kế hệ thống xử lý song song từng đoạn ống độc lập, nhưng phải từ bỏ vì khó kiểm soát giới hạn dung tích khi có nhiều đầu vào/ra. Trong game “Oxygen Not Included”, họ dùng cơ chế áp suất cho phép vượt dung tích nhưng tăng rủi ro vỡ ống. Tuy tạo ra gameplay phong phú, cách tiếp cận này lại dễ sinh lỗi và bất ổn.
Cuối cùng tôi chọn phương pháp xử lý tuần tự có thứ tự:
Không dùng bơm:
- Từng đoạn ống tính toán mực nước, so sánh với các đoạn kề để xác định hướng lưu thông. Ghi nhận lượng chất lỏng dự kiến nhận được từ các đoạn thượng nguồn (dựa trên chênh lệch mực nước) - gọi là “khoảng trống dự trữ”.
- Thực hiện sắp xếp topo từ hạ nguồn đến thượng nguồn. Lưu kết quả để dùng cho khung giờ tiếp theo. Nếu phát hiện hướng ngược với khung giờ trước, chỉ sắp xếp lại phần liên quan.
- Xử lý lưu thông theo thứ tự đã sắp xếp. Lượng chất lỏng chảy ra không vượt quá khoảng trống dự trữ. Nếu có nhiều nhánh, phân chia theo tỷ lệ khoảng trống. Sau khi chảy, điều chỉnh lại khoảng trống dự trữ nếu còn dư.
Để đảm bảo tính xác định, tôi dùng số nguyên thay vì số thực, nhân hệ số 100 để mô phỏng số thập phân. Khi phân chia lưu lượng, đơn vị nhỏ nhất là 1. Các nhánh phân nhánh có lưu lượng chênh lệch tối đa 1 đơn vị.
Thêm bơm: Bơm hoạt động độc lập với mực nước, hút tối đa chất lỏng có thể theo tốc độ và dung tích giới hạn, sau đó xem bơm như đoạn ống bình thường để tiếp tục xử lý theo thuật toán trên.
Giải pháp này kết hợp giữa tính đơn giản và khả năng mở rộng, tạo nền tảng cho gameplay đa dạng xoay quanh hệ thống chất lỏng trong game của chúng tôi.