Sự Kết Hợp Giữa Hàng Hóa Và Xe Tải
Chúng tôi đang phát triển một trò chơi xoay quanh tự động hóa tương tự như Factorio. Trong quá trình phát triển, chúng tôi gặp phải nhiều vấn đề thuật toán thú vị và giải quyết chúng theo những cách rất sáng tạo. Trước đây tôi đã từng viết một bài về hệ thống chất lỏng, ví dụ như vậy.
Điểm khác biệt lớn nhất so với trải nghiệm Factorio nằm ở việc chúng tôi không sử dụng băng chuyền làm phương thức vận chuyển chính, mà thay vào đó xây dựng một hệ thống đường bộ và xe tải. Cách tiếp cận này không mới, từ hơn 20 năm trước trong tựa game Caesar III (cùng loạt với Pharaoh, Zeus và Rise of Nations) tôi đã từng trải nghiệm. Các trò chơi theo mô hình này chưa bao giờ biến mất khỏi thị trường, vài năm gần đây tôi đã chơi qua các tựa như Banished, Don’t Starve, RimWorld hay Beaver Fever - tất cả đều áp dụng cách vận chuyển tương tự.
Đặc điểm chung của các trò chơi này là cần xây dựng một hệ thống nhân công được nuôi bằng tài nguyên thành phố, qua đó nhân công sẽ làm việc để duy trì sự phát triển đô thị. Trong đó công tác vận chuyển đóng vai trò quan trọng. Tuy nhiên do giới hạn năng suất tài nguyên, số lượng nhân công thường không quá lớn để tạo thành vòng tuần hoàn tích cực. Do đó tỷ trọng công việc liên quan đến logistics không quá cao, phần lớn nhân công tập trung vào các công trình sản xuất.
Trò chơi của chúng tôi có phần gần với Factorio hơn khi không cần nhân công vận hành máy móc, hệ thống vận chuyển cũng thuần túy hơn. Chi phí duy trì xe tải không cao, khuyến khích người chơi tăng số lượng phương tiện để tối ưu hiệu suất vận chuyển. Khác với các series trò chơi kể trên, hệ thống đường bộ trong game có giới hạn rõ ràng. Xe cộ phải tuân thủ luật giao thông, nếu quá nhiều phương tiện sẽ xảy ra tình trạng ùn tắc. Do đó yếu tố giới hạn hiệu suất logistics là đường sá chứ không phải tài nguyên.
Tôi muốn người chơi trải nghiệm rằng: hệ thống vận chuyển tuân theo những quy tắc nhất định, người chơi có thể cảm nhận được sự tồn tại của quy tắc này, từ đó thông qua việc bố trí và điều chỉnh khác nhau để nâng cao hiệu quả tổng thể. Trò chơi không nên rõ ràng như hệ thống băng chuyền, cũng không nên trở thành một “hộp đen” mà người chơi không thể kiểm soát chi tiết.
Ban đầu tôi dự định xây dựng logic vận chuyển theo hướng đường sắt, người chơi tự quy hoạch tuyến đường, xe tải chỉ chạy trên tuyến đường đó và chỉ nhận hàng hóa dọc tuyến. Tuy nhiên trải nghiệm chơi và tương tác không thực sự tốt. Gần đây tôi đã chuyển sang quy tắc thông minh hơn, không giới hạn tuyến đường, để AI tự quyết định xe sẽ đi đâu nhận hàng và giao hàng ở đâu.
Hệ thống điều phối AI cho logistics này khá phức tạp. Tôi không muốn nó quá ngốc nghếch đến mức người chơi vừa chơi vừa chửi, cũng không muốn nó quá thông minh khiến phần logistics trở thành game “click chuột” không cần bất kỳ quyết định nào từ người chơi.
Độ phức tạp nằm ở việc hệ thống phải đồng thời điều phối ba yếu tố: cung cấp, nhu cầu và năng lực vận chuyển. Khi lượng cung vượt cầu, xe không nên nhận những đơn hàng không có điểm đến rõ ràng; khi năng lực vận chuyển dồi dào, xe không tải cần được điều phối sớm đến khu vực cần nhiều vận lực nhất; khi năng lực vận chuyển hạn chế, cần tránh tình trạng xe tập trung quá mức vào một khu vực nhỏ.
Hơn nữa, mạng lưới đường sá và các bên cung cầu đều mang tính động (người chơi có thể mở rộng hoặc xóa bỏ đường sá trong quá trình chơi), các công trình liên quan logistics cũng có thể bị phá bỏ hoặc xây mới. Điều này khiến điểm đến của xe trong hành trình có thể thay đổi bất ngờ, thậm chí mất hoàn toàn điểm đến ban đầu (hoặc trở nên không thể tiếp cận). Đây là yếu tố làm tăng độ phức tạp thuật toán.
Trong các series trò chơi trước đây, có cách tiếp cận là gắn nhân công logistics với công trình cụ thể. Ví dụ như công nhân lò bánh mì vừa làm bánh vừa chịu trách nhiệm thu gom nguyên liệu, công nhân kho hàng chỉ xử lý hàng hóa trong kho. Điều này đồng nghĩa với việc yếu tố “năng lực vận chuyển” bị gắn chết với công trình, không tham gia vào điều phối tổng thể. Thuật toán lúc này đơn giản hơn nhiều.
Một cách tiếp cận khác dựa trên giả định nhân công ít nhưng việc nhiều. Người chơi sẽ thiết lập sở thích và mức ưu tiên cho từng nhân công, khi có nhiệm vụ logistics phát sinh, hệ thống sẽ ghép nối nhân công theo mức ưu tiên. Lúc này yếu tố “năng lực vận chuyển” cũng bị bỏ qua.
Trong trò chơi của chúng tôi, năng lực vận chuyển có thể rất dồi dào, và tôi cũng không muốn người chơi phải quan tâm đến từng chiếc xe cụ thể để điều khiển chi tiết.
Vì vậy khi thiết kế thuật toán điều phối ban đầu, tôi đồng thời xem xét sự tương tác giữa ba yếu tố. Từ phía nhu cầu tìm kiếm phía cung cấp phù hợp, sau đó khóa hai bên cùng hàng hóa và vị trí nhận hàng, rồi mới ghép nối với phương tiện. Khi xe xuất phát, tất cả tài nguyên liên quan sẽ bị khóa cho đến khi đơn hàng hoàn thành hoặc trạng thái vận chuyển bị thay đổi (ví dụ đường sá bị phá hủy, điểm đến không thể tiếp cận, hoặc phía cung/nhận bị phá bỏ…), lúc đó mới quay lại trạng thái trước đó.
Quy trình này khá phức tạp, tôi viết mất vài ngày vẫn chưa rõ ràng.
Sau đó tôi nhận ra độ phức tạp này xuất phát từ việc phải xử lý ba chiều dữ liệu cùng lúc. Để đơn giản hóa thuật toán, chúng tôi cần trước tiên đơn giản hóa hệ thống. Cụ thể là chia hệ thống logistics thành hai hệ thống con độc lập:
Thứ nhất, giống