Cách những con đường chậm thu hút cả người chơi trò chơi và nhà phát triển, đồng thời làm nổi bật những khả năng đáng kinh ngạc của mô hình 3D trong trình duyệt

Khám phá tiềm năng của WebGL với cảnh quan vô tận, được tạo theo quy trình của trò chơi lái xe giải trí này.

Slow Roads là một trò chơi lái xe phổ thông tập trung vào cảnh quan được tạo theo quy trình vô tận, tất cả đều được lưu trữ trong trình duyệt dưới dạng ứng dụng WebGL. Đối với nhiều người, trải nghiệm chuyên sâu như vậy có vẻ không phù hợp với bối cảnh hạn chế của trình duyệt. Và thực sự, việc khắc phục thái độ đó là một trong những mục tiêu của tôi với dự án này. Trong bài viết này, tôi sẽ phân tích một số kỹ thuật mà tôi đã sử dụng để vượt qua rào cản về hiệu suất trong nhiệm vụ làm nổi bật tiềm năng thường bị bỏ qua của công nghệ 3D trên web.

Phát triển 3D trong trình duyệt

Sau khi phát hành Slow Roads, tôi thấy một bình luận lặp đi lặp lại trong phần phản hồi: "Tôi không biết có thể làm được điều này trong trình duyệt". Nếu có cùng cảm nhận này, chắc chắn bạn không phải là người thiểu số; theo khảo sát Trạng thái của JS năm 2022, khoảng 80% nhà phát triển chưa thử nghiệm WebGL. Đối với tôi, thật đáng tiếc khi có thể bỏ lỡ nhiều tiềm năng, đặc biệt là khi nói đến việc chơi trò chơi trên trình duyệt. Với Slow Roads, tôi hy vọng có thể đưa WebGL lên tầm cao hơn và có thể giảm số lượng nhà phát triển từ chối cụm từ "công cụ phát triển trò chơi JavaScript hiệu suất cao".

WebGL có vẻ bí ẩn và phức tạp đối với nhiều người, nhưng trong những năm gần đây, hệ sinh thái phát triển của WebGL đã phát triển rất nhiều thành các công cụ và thư viện có khả năng cao và thuận tiện. Giờ đây, các nhà phát triển phía trước có thể dễ dàng tích hợp trải nghiệm người dùng 3D vào công việc của mình hơn bao giờ hết, ngay cả khi không có kinh nghiệm trước đó về đồ hoạ máy tính. Three.js, thư viện WebGL hàng đầu, đóng vai trò là nền tảng cho nhiều tiện ích mở rộng, bao gồm cả react-three-fiber giúp đưa các thành phần 3D vào khung React. Hiện tại, cũng có các trình chỉnh sửa trò chơi toàn diện dựa trên web như Babylon.js hoặc PlayCanvas. Các trình chỉnh sửa này cung cấp giao diện quen thuộc và chuỗi công cụ tích hợp.

Tuy nhiên, mặc dù các thư viện này có nhiều tiện ích đáng kể, nhưng các dự án đầy tham vọng cuối cùng vẫn bị ràng buộc bởi các giới hạn kỹ thuật. Những người hoài nghi về ý tưởng chơi trò chơi trên trình duyệt có thể nhấn mạnh rằng JavaScript là đơn luồng và bị hạn chế về tài nguyên. Tuy nhiên, việc vượt qua những giới hạn này sẽ mở ra giá trị ẩn: không có nền tảng nào khác cung cấp khả năng hỗ trợ tiếp cận tức thì và khả năng tương thích hàng loạt như trình duyệt. Người dùng trên mọi hệ thống có trình duyệt đều có thể bắt đầu phát chỉ bằng một lần nhấp, không cần cài đặt ứng dụng và không cần đăng nhập vào các dịch vụ. Chưa kể đến việc nhà phát triển tận hưởng sự tiện lợi tinh tế khi có các khung giao diện người dùng mạnh mẽ để xây dựng giao diện người dùng hoặc xử lý kết nối mạng cho các chế độ nhiều người chơi. Theo tôi, những giá trị này là yếu tố khiến trình duyệt trở thành một nền tảng tuyệt vời cho cả người chơi và nhà phát triển. Như Slow Roads đã chứng minh, các hạn chế kỹ thuật thường có thể được giảm thiểu xuống còn vấn đề về thiết kế.

Đạt được hiệu suất mượt mà trên Đường có tốc độ chậm

Vì các yếu tố cốt lõi của Slow Roads liên quan đến chuyển động tốc độ cao và việc tạo cảnh tốn kém, nên nhu cầu về hiệu suất mượt mà đã làm nổi bật mọi quyết định thiết kế của tôi. Chiến lược chính của tôi là bắt đầu bằng một thiết kế lối chơi tinh giản cho phép thực hiện các lối tắt theo ngữ cảnh trong cấu trúc của công cụ. Mặt hạn chế là bạn phải đánh đổi một số tính năng hữu ích để theo đuổi phong cách tối giản, nhưng kết quả là bạn có được một hệ thống được tuỳ chỉnh, được tối ưu hoá tối đa và hoạt động tốt trên nhiều trình duyệt và thiết bị.

Sau đây là thông tin chi tiết về các thành phần chính giúp giữ cho Slow Roads gọn gàng.

Định hình công cụ môi trường xung quanh lối chơi

Là thành phần chính của trò chơi, công cụ tạo môi trường không thể tránh khỏi việc tốn kém, chiếm tỷ lệ lớn nhất trong ngân sách cho bộ nhớ và điện toán. Thủ thuật được sử dụng ở đây là lên lịch và phân phối phép tính nặng trong một khoảng thời gian, để không làm gián đoạn tốc độ khung hình bằng các mức tăng hiệu suất.

Môi trường được tạo thành từ các ô hình học, khác nhau về kích thước và độ phân giải (được phân loại là "mức độ chi tiết" hoặc LoD) tuỳ thuộc vào khoảng cách mà các ô đó xuất hiện với máy ảnh. Trong các trò chơi thông thường có máy ảnh tự do di chuyển, các LoD khác nhau phải liên tục được tải và giải phóng để cung cấp thông tin chi tiết về môi trường xung quanh người chơi bất cứ nơi nào họ có thể chọn đến. Đây có thể là một thao tác tốn kém và lãng phí, đặc biệt là khi chính môi trường được tạo động. May mắn thay, quy ước này có thể bị đảo ngược hoàn toàn trong trường hợp Đường có tốc độ chậm nhờ kỳ vọng theo ngữ cảnh rằng người dùng sẽ ở trên đường. Thay vào đó, bạn có thể dành riêng hình học chi tiết cao cho hành lang hẹp ngay bên cạnh tuyến đường.

Sơ đồ cho thấy cách tạo đường trước có thể cho phép lập lịch biểu và lưu vào bộ nhớ đệm để tạo môi trường một cách chủ động.
Hình ảnh về hình học môi trường trong Slow Roads được kết xuất dưới dạng khung dây, cho biết các hành lang có hình học có độ phân giải cao ở hai bên đường. Các phần xa của môi trường (không bao giờ được nhìn thấy ở cự ly gần) được kết xuất ở độ phân giải thấp hơn nhiều.

Đường giữa của đường được tạo ra trước khi người chơi đến, cho phép dự đoán chính xác thời điểm và vị trí cần có thông tin chi tiết về môi trường. Kết quả là một hệ thống tinh gọn có thể chủ động lên lịch công việc tốn kém, chỉ tạo ra mức tối thiểu cần thiết tại mỗi thời điểm và không lãng phí công sức vào những chi tiết không được nhìn thấy. Kỹ thuật này chỉ có thể thực hiện được vì đường là một đường dẫn đơn, không phân nhánh – một ví dụ điển hình về việc đánh đổi lối chơi để phù hợp với các lối tắt kiến trúc.

Sơ đồ cho thấy cách tạo đường trước có thể cho phép lập lịch biểu và lưu vào bộ nhớ đệm để tạo môi trường một cách chủ động.
Bằng cách xem một khoảng cách nhất định dọc theo đường, các đoạn môi trường có thể được tạo trước và tạo dần dần ngay trước khi cần. Ngoài ra, mọi phần sẽ được truy cập lại trong tương lai gần đều có thể được xác định và lưu vào bộ nhớ đệm để tránh việc tạo lại không cần thiết.

Rất kén chọn với các định luật vật lý

Thứ hai sau nhu cầu tính toán của công cụ môi trường là mô phỏng vật lý. Slow Roads sử dụng một công cụ vật lý tuỳ chỉnh, tối giản, sử dụng mọi lối tắt có sẵn.

Điều quan trọng nhất ở đây là tránh mô phỏng quá nhiều đối tượng ngay từ đầu – dựa vào ngữ cảnh tối giản, zen bằng cách giảm bớt những thứ như va chạm động và đối tượng có thể huỷ bỏ. Giả định rằng xe sẽ ở trên đường có nghĩa là các va chạm với các vật thể ngoài đường có thể được bỏ qua một cách hợp lý. Ngoài ra, việc mã hoá đường dưới dạng đường giữa thưa thớt cho phép các thủ thuật tinh tế để phát hiện nhanh sự cố va chạm với mặt đường và lan can bảo vệ, tất cả đều dựa trên việc kiểm tra khoảng cách đến tâm đường. Khi đó, việc lái xe trên đường không trải nhựa sẽ tốn kém hơn, nhưng đây là một ví dụ khác về sự đánh đổi công bằng phù hợp với bối cảnh của trò chơi.

Quản lý mức sử dụng bộ nhớ

Là một tài nguyên khác bị trình duyệt hạn chế, bạn cần phải quản lý bộ nhớ một cách cẩn thận, mặc dù JavaScript được thu gom rác. Bạn có thể dễ dàng bỏ qua điều này, nhưng việc khai báo ngay cả một lượng nhỏ bộ nhớ mới trong vòng lặp trò chơi cũng có thể gây ra các vấn đề đáng kể khi chạy ở tốc độ 60 Hz. Ngoài việc tiêu tốn tài nguyên của người dùng trong bối cảnh họ có thể làm nhiều việc cùng lúc, các hoạt động thu thập rác lớn có thể mất vài khung hình để hoàn tất, gây ra hiện tượng giật đáng chú ý. Để tránh điều này, bạn có thể phân bổ trước bộ nhớ vòng lặp trong các biến lớp khi khởi tạo và tái chế trong mỗi khung.

Chế độ xem trước và sau của hồ sơ bộ nhớ trong quá trình tối ưu hoá cơ sở mã Slow Roads, cho thấy mức tiết kiệm đáng kể và giảm tỷ lệ thu gom rác.
Mặc dù mức sử dụng bộ nhớ tổng thể hầu như không thay đổi, nhưng việc phân bổ trước và tái chế bộ nhớ vòng lặp có thể làm giảm đáng kể tác động của các hoạt động thu gom rác tốn kém.

Điều quan trọng nữa là các cấu trúc dữ liệu nặng hơn, chẳng hạn như hình học và vùng đệm dữ liệu liên kết với chúng, phải được quản lý một cách tiết kiệm. Trong một trò chơi được tạo vô hạn như Slow Roads, hầu hết các hình học đều tồn tại trên một loại máy chạy bộ – sau khi một phần cũ bị bỏ lại phía sau, cấu trúc dữ liệu của phần đó có thể được lưu trữ và tái chế lại cho một phần sắp tới của thế giới, một mẫu thiết kế được gọi là gộp đối tượng.

Các phương pháp này giúp ưu tiên việc thực thi tinh gọn, với một số sự hy sinh về tính đơn giản của mã. Trong ngữ cảnh hiệu suất cao, điều quan trọng là phải lưu ý đến cách các tính năng tiện lợi đôi khi mượn từ ứng dụng để mang lại lợi ích cho nhà phát triển. Ví dụ: các phương thức như Object.keys() hoặc Array.map() rất tiện dụng, nhưng bạn dễ dàng bỏ qua việc mỗi phương thức tạo một mảng mới cho giá trị trả về. Việc hiểu rõ cách hoạt động bên trong của các hộp đen như vậy có thể giúp bạn thắt chặt mã và tránh các tác động lén lút đến hiệu suất.

Giảm thời gian tải bằng các thành phần được tạo theo quy trình

Mặc dù hiệu suất thời gian chạy phải là mối quan tâm chính của các nhà phát triển trò chơi, nhưng các tiên đề thông thường liên quan đến thời gian tải trang web ban đầu vẫn đúng. Người dùng có thể dễ dàng bỏ qua khi biết mình đang truy cập vào nội dung nặng, nhưng thời gian tải lâu vẫn có thể gây bất lợi cho trải nghiệm, nếu không phải là khả năng giữ chân người dùng. Trò chơi thường yêu cầu các thành phần lớn ở dạng hoạ tiết, âm thanh và mô hình 3D. Tối thiểu, bạn nên nén cẩn thận các thành phần này bất cứ khi nào có thể tiết kiệm chi tiết.

Ngoài ra, việc tạo tài sản theo quy trình trên ứng dụng khách có thể tránh được việc chuyển tài sản trong thời gian dài. Đây là một lợi ích rất lớn cho người dùng có kết nối chậm, đồng thời giúp nhà phát triển kiểm soát trực tiếp hơn cách cấu trúc trò chơi của họ – không chỉ đối với bước tải ban đầu, mà còn khi điều chỉnh mức độ chi tiết cho các chế độ cài đặt chất lượng khác nhau.

Hình ảnh so sánh minh hoạ cách chất lượng của hình học được tạo theo quy trình trong Slow Roads có thể được điều chỉnh linh hoạt cho phù hợp với nhu cầu về hiệu suất của người dùng.

Hầu hết các hình học trong Slow Roads đều được tạo theo quy trình và đơn giản, với chương trình đổ bóng tuỳ chỉnh kết hợp nhiều hoạ tiết để tạo chi tiết. Nhược điểm là các hoạ tiết này có thể là tài sản nặng, mặc dù có nhiều cơ hội tiết kiệm hơn ở đây, với các phương thức như hoạ tiết ngẫu nhiên có thể đạt được chi tiết cao hơn từ hoạ tiết nguồn nhỏ. Và ở cấp độ cao nhất, bạn cũng có thể tạo hoạ tiết hoàn toàn trên máy khách bằng các công cụ như texgen.js. Điều này cũng đúng đối với âm thanh, với Web Audio API cho phép tạo âm thanh bằng các nút âm thanh.

Nhờ lợi ích của tài sản quy trình, việc tạo môi trường ban đầu chỉ mất trung bình 3,2 giây. Để tận dụng tối đa kích thước tải xuống ban đầu nhỏ, một màn hình chờ đơn giản sẽ chào đón khách truy cập mới và trì hoãn việc khởi chạy cảnh tốn kém cho đến khi người dùng nhấn nút xác nhận. Vùng đệm này cũng đóng vai trò là vùng đệm thuận tiện cho các phiên bị trả về, giảm thiểu việc chuyển tải tài sản được tải động một cách lãng phí.

Biểu đồ thời gian tải cho thấy một đỉnh cao trong 3 giây đầu tiên chiếm hơn 60% người dùng, sau đó giảm nhanh. Biểu đồ này cho thấy hơn 97% người dùng thấy thời gian tải dưới 10 giây.

Áp dụng phương pháp linh hoạt để tối ưu hoá muộn

Tôi luôn coi cơ sở mã của Slow Roads là thử nghiệm, do đó đã áp dụng một phương pháp linh hoạt để phát triển. Khi làm việc với một cấu trúc hệ thống phức tạp và phát triển nhanh chóng, bạn có thể khó dự đoán được điểm tắc nghẽn quan trọng có thể xảy ra. Bạn nên tập trung vào việc triển khai nhanh các tính năng mong muốn thay vì triển khai một cách gọn gàng, sau đó quay lại để tối ưu hoá các hệ thống thực sự cần thiết. Trình phân tích hiệu suất trong Công cụ của Chrome cho nhà phát triển là một công cụ vô giá cho bước này và đã giúp tôi chẩn đoán một số vấn đề lớn với các phiên bản trò chơi trước đó. Là một nhà phát triển, thời gian của bạn rất quý giá, vì vậy, hãy đảm bảo rằng bạn không dành thời gian để cân nhắc những vấn đề có thể không đáng kể hoặc thừa thãi.

Theo dõi trải nghiệm người dùng

Trong khi triển khai tất cả các thủ thuật này, điều quan trọng là phải đảm bảo trò chơi hoạt động như mong đợi trong thực tế. Việc hỗ trợ nhiều chức năng phần cứng là một khía cạnh chính trong quá trình phát triển trò chơi, nhưng trò chơi trên web có thể nhắm đến một phạm vi rộng hơn nhiều, bao gồm cả máy tính để bàn cao cấp và thiết bị di động đã có tuổi đời hàng chục năm cùng một lúc. Cách đơn giản nhất để giải quyết vấn đề này là cung cấp các chế độ cài đặt để điều chỉnh các nút thắt cổ chai có nhiều khả năng xảy ra nhất trong cơ sở mã của bạn (cho cả các tác vụ chuyên sâu về GPU và CPU) như trình phân tích tài nguyên của bạn đã cho thấy.

Tuy nhiên, việc phân tích tài nguyên trên máy của riêng bạn chỉ có thể bao quát một số khía cạnh. Vì vậy, bạn nên khép lại vòng phản hồi với người dùng theo một cách nào đó. Đối với Slow Roads, tôi chạy số liệu phân tích đơn giản báo cáo về hiệu suất cùng với các yếu tố theo bối cảnh như độ phân giải màn hình. Những số liệu phân tích này được gửi đến phần phụ trợ Node cơ bản bằng socket.io, cùng với mọi ý kiến phản hồi bằng văn bản mà người dùng gửi qua biểu mẫu trong trò chơi. Trong giai đoạn đầu, những số liệu phân tích này đã phát hiện được nhiều vấn đề quan trọng có thể được giảm thiểu bằng những thay đổi đơn giản đối với trải nghiệm người dùng, chẳng hạn như làm nổi bật trình đơn cài đặt khi phát hiện FPS thấp liên tục hoặc cảnh báo rằng người dùng có thể cần bật tính năng tăng tốc phần cứng nếu hiệu suất đặc biệt kém.

Đường có tốc độ chậm ở phía trước

Ngay cả sau khi áp dụng tất cả các biện pháp này, vẫn còn một phần đáng kể cơ sở người chơi cần chơi ở chế độ cài đặt thấp hơn, chủ yếu là những người sử dụng thiết bị nhẹ không có GPU. Mặc dù phạm vi cài đặt chất lượng có sẵn dẫn đến việc phân phối hiệu suất khá đồng đều, nhưng chỉ 52% người chơi đạt được trên 55 FPS.

Một ma trận được xác định bằng chế độ cài đặt khoảng cách xem so với chế độ cài đặt chi tiết, cho biết số khung hình trung bình mỗi giây đạt được ở các chế độ ghép nối khác nhau. Mức phân phối khá đồng đều từ 45 đến 60, trong đó 60 là mục tiêu để đạt được hiệu suất tốt. Người dùng ở chế độ cài đặt thấp thường thấy FPS thấp hơn so với những người dùng ở chế độ cài đặt cao, làm nổi bật sự khác biệt về khả năng phần cứng của máy khách.
Xin lưu ý rằng dữ liệu này có phần bị lệch do những người dùng chạy trình duyệt với tính năng tăng tốc phần cứng bị tắt, thường gây ra hiệu suất thấp một cách giả tạo.

May mắn là vẫn còn nhiều cơ hội để tiết kiệm hiệu suất. Bên cạnh việc thêm các thủ thuật kết xuất khác để giảm nhu cầu GPU, tôi hy vọng có thể thử nghiệm với worker web trong việc tạo môi trường song song trong thời gian sắp tới, và cuối cùng có thể thấy cần phải kết hợp WASM hoặc WebGPU vào cơ sở mã. Mọi khoảng không mà tôi có thể giải phóng sẽ cho phép tạo ra các môi trường phong phú và đa dạng hơn. Đây sẽ là mục tiêu lâu dài cho phần còn lại của dự án.

Là một dự án theo đuổi sở thích, Slow Roads là một cách vô cùng thoả mãn để chứng minh rằng các trò chơi trên trình duyệt có thể phức tạp, hiệu quả và phổ biến đến mức nào. Nếu tôi đã thành công trong việc khơi dậy sự quan tâm của bạn đối với WebGL, hãy biết rằng Slow Roads về mặt công nghệ là một ví dụ khá sơ sài về toàn bộ khả năng của WebGL. Tôi khuyến khích bạn đọc khám phá bản minh hoạ Three.js, đặc biệt là những người quan tâm đến việc phát triển trò chơi trên web, hãy tham gia cộng đồng tại webgamedev.com.