Trang chủ » Blog » Đánh Đổi Trong Phát Triển Game: 6 Trục Quyết Định Cốt Lõi

Đánh Đổi Trong Phát Triển Game: 6 Trục Quyết Định Cốt Lõi

| Blog

Trong bài viết về ngân sách khung hình, câu hỏi trung tâm là: cái này lấy chỗ của cái gì. Câu hỏi đó đúng nhưng chưa đủ, vì nó giả định chỉ có một loại chỗ.

Thực tế có ít nhất sáu. Và điều làm cho phát triển game khó hơn phần lớn ngành phần mềm khác không phải là sáu ràng buộc đó nghiêm ngặt hơn, mà là chúng chuyển đổi được cho nhau. Gần như mọi kỹ thuật tối ưu, mọi mẫu kiến trúc, và cả rất nhiều quyết định thiết kế thuần túy, đều là hành động lấy bớt ở một trục để trả thêm vào trục khác.

Người mới vào nghề nhìn thấy các kỹ thuật rời rạc và học thuộc từng cái. Người làm lâu nhìn thấy cùng một phép toán lặp đi lặp lại dưới ba mươi cái tên khác nhau. Bài viết này trình bày cái phép toán đó.

Khái niệm gốc: đánh đổi thiết kế

Đánh đổi thiết kế là tình huống trong đó không tồn tại phương án tốt hơn về mọi mặt, chỉ tồn tại phương án chuyển chi phí từ chỗ này sang chỗ khác.

Điều này khác với tối ưu hóa theo nghĩa thông thường. Sửa một thuật toán từ bậc hai xuống bậc tuyến tính là cải thiện thật, không có ai phải trả giá. Nhưng những cải thiện kiểu đó là ngoại lệ hiếm, và trong một dự án đã trưởng thành thì chúng gần như đã được nhặt hết.

Phần lớn công việc còn lại là đánh đổi. Và kỹ năng nghề nghiệp không nằm ở chỗ tránh được đánh đổi, mà nằm ở chỗ luôn biết chính xác mình vừa chuyển chi phí sang trục nào, và trục đó có còn chỗ hay không.

Sáu trục

Đánh đổi trong phát triển game

Chú thích: Sáu trục và đơn vị đo của chúng. Bất kỳ quyết định nào trong dự án cũng có thể mô tả bằng câu lấy bớt ở trục A để trả thêm vào trục B.

Vài ghi chú ngắn cho từng trục trước khi đi tiếp.

Bộ nhớ không chỉ là dung lượng RAM. Nó gồm cả bộ nhớ hình ảnh, dung lượng ổ đĩa, và kích thước gói tải về, và trên di động thì kích thước gói tải về là ràng buộc kinh doanh chứ không chỉ kỹ thuật.

Tính toán đo bằng mili giây trong ngân sách khung hình, và cần tách riêng phần CPU với phần GPU vì chúng là hai ngân sách khác nhau.

Băng thông có hai dạng thường bị gộp làm một: băng thông mạng cho game trực tuyến, và băng thông bus bộ nhớ giữa CPU, GPU và bộ nhớ. Dạng thứ hai ít được nói tới nhưng thường là điểm nghẽn thật trên phần cứng hiện đại.

Độ trễ là khoảng thời gian từ nguyên nhân tới kết quả nhìn thấy được. Nó không giống tính toán: một hệ thống có thể tốn rất ít tính toán mà vẫn có độ trễ lớn, chẳng hạn khi phải chờ dữ liệu từ máy chủ.

Độ chính xác là mức sai lệch so với mô hình lý tưởng. Đây là trục dễ bị coi nhẹ nhất, vì bỏ bớt độ chính xác thường không nhìn thấy được ngay, và đó chính là điều làm nó thành đồng tiền hữu dụng nhất trong sáu trục.

Thời gian sản xuất là số người nhân số tuần. Đây là trục khác biệt về bản chất so với năm trục kia, và tôi sẽ quay lại ở cuối bài.

Mọi kỹ thuật tối ưu là một phép chuyển giữa hai trục

Bảng dưới đây là phần đáng in ra dán lên tường.

Kỹ thuật Lấy bớt ở Trả thêm vào
Mức chi tiết theo khoảng cách Tính toán Độ chính xác
Loại bỏ vật ngoài tầm nhìn Tính toán Độ chính xác, thời gian sản xuất
Gộp đối tượng tái sử dụng Tính toán Bộ nhớ
Bảng tra sẵn thay vì tính lại Tính toán Bộ nhớ
Nén kết cấu bề mặt Bộ nhớ, băng thông Độ chính xác, tính toán
Nướng ánh sáng sẵn Tính toán Bộ nhớ, thời gian sản xuất
Sinh nội dung theo thuật toán Bộ nhớ, thời gian sản xuất Tính toán, độ chính xác
Nạp dữ liệu theo dòng Bộ nhớ Độ trễ, thời gian sản xuất
Lượng tử hóa dữ liệu gửi qua mạng Băng thông Độ chính xác
Nội suy trạng thái mạng Băng thông Độ trễ
Dự đoán phía máy khách Độ trễ Tính toán, độ chính xác
Bước thời gian cố định Độ chính xác Tính toán

Đọc bảng này theo chiều dọc cho thấy một điều hữu ích. Trục độ chính xác xuất hiện ở cột phải nhiều hơn hẳn mọi trục khác. Lý do là nó thường rẻ nhất để trả: mắt người và tay người đều có ngưỡng phân giải hữu hạn, nên trong rất nhiều trường hợp ta bỏ đi được một lượng độ chính xác đáng kể mà không ai nhận ra.

Đó là kỹ năng nghề đúng nghĩa: biết chính xác chỗ nào người chơi nhìn thấy được sai lệch và chỗ nào không.

Đánh đổi trong phát triển game 1

Chú thích: Bàn trộn âm thanh là hình ảnh gần nhất với cách hoạt động của sáu trục. Không có cần gạt nào là đúng hay sai, chỉ có tổ hợp phù hợp với bản nhạc đang phát, và kéo một cần lên gần như luôn buộc phải hạ một cần khác xuống.

Nghiên cứu tình huống: netcode chạm vào cả sáu trục

Không ví dụ nào cho thấy sáu trục hoạt động cùng lúc rõ hơn bài toán mạng trong game nhiều người chơi.

Xuất phát điểm là một sự thật vật lý không thể lách. Độ trễ có một sàn cứng do tốc độ ánh sáng, gói tin bị mất và bị đảo thứ tự, và người chơi thì gian lận. Không kiến trúc mạng nào đánh bại được những ràng buộc đó, chúng chỉ giấu đi.

Phương án một là chờ. Kiến trúc lockstep hoặc trễ đầu vào cho tính nhất quán hoàn hảo từ khung hình này sang khung hình khác, và cái giá phải trả là độ trễ đầu vào. Người chơi có độ trễ mạng 100 mili giây sẽ chờ trọn một phần mười giây trước khi thấy nhân vật phản ứng. Đổi lại, mọi người chơi đều nhìn thấy đúng cùng một thứ.

Trên bảng sáu trục: rất rẻ về tính toán, rất rẻ về băng thông vì chỉ gửi lệnh bấm, tuyệt đối chính xác, và trả toàn bộ chi phí vào trục độ trễ.

Phương án hai là đoán rồi sửa. Rollback chạy một mô phỏng xác định và dự đoán lệnh bấm của đối thủ theo giả định họ tiếp tục làm điều vừa làm, mô phỏng tiến lên ngay lập tức để game cho cảm giác như chơi ngoại tuyến. Khi lệnh bấm thật đến và khác với dự đoán, máy khách quay lại trạng thái đã lưu ở khung hình đó và mô phỏng lại tới hiện tại với lệnh bấm đúng.

Đây là chỗ phép chuyển giữa các trục trở nên rất cụ thể. Rollback trả chi phí vào bốn trục cùng lúc.

Nó trả vào trục độ chính xác, dưới hình thức mất tính nhất quán. Dự đoán sai biểu hiện thành vật thể nhảy vị trí, xuất hiện hoặc biến mất đột ngột, và khoảng thời gian dự đoán càng dài thì khả năng sai càng cao.

Nó trả vào trục bộ nhớ, vì phải lưu lại lịch sử trạng thái để có chỗ mà quay về.

Nó trả vào trục thời gian sản xuất, vì rollback đòi hỏi mô phỏng phải hoàn toàn xác định, và đưa được một cơ sở mã lớn về trạng thái xác định là việc rất tốn công.

Và nó trả vào trục tính toán theo một cách đáng giật mình. Nếu một game chạy và dựng hình ở 60 khung hình mỗi giây, có 3 khung hình trễ đầu vào, và hỗ trợ độ trễ mạng tới 300 mili giây, thì nó phải quay lại và mô phỏng lại tới 15 khung hình bên trong đúng 16,66 mili giây. Nghĩa là ngân sách CPU cho một bước mô phỏng chỉ còn khoảng 1,1 mili giây, một mức giảm rất mạnh so với trọn 16,66 mili giây khi dùng kiến trúc lockstep.

Đánh đổi trong phát triển game 2

Chú thích: Cùng một game, cùng một phần cứng, nhưng ngân sách cho một bước mô phỏng chênh nhau hơn mười lần chỉ vì đổi kiến trúc mạng. Đây là cái giá bằng tính toán của việc mua độ trễ thấp.

Phương án ba là nội suy ảnh chụp. Ở đây chỉ người chơi cục bộ được dự đoán, còn mọi đối tượng khác được nội suy giữa hai ảnh chụp trạng thái thật. Máy khách tốn ít CPU hơn hẳn so với rollback đầy đủ, vì với phần lớn đối tượng nó không cần chạy logic game nào cả.

Cái giá nằm ở một chỗ rất đáng chú ý: hệ thống cố tình thêm độ trễ vào. Độ trễ nội suy là độ trễ mà ta thêm vào một cách có chủ đích để đổi lấy sự mượt mà, và đó là một đánh đổi chứ không phải một khiếm khuyết. Nếu không có nó, các thực thể sẽ nhảy giật giữa những ảnh chụp trạng thái vốn chỉ đến khoảng mười lần mỗi giây.

Ba phương án này không có phương án nào đúng. Game đối kháng chọn rollback vì với thể loại đó, việc rớt một chuỗi đòn có sức nặng lớn hơn nhiều so với việc bắn trượt một phát. Game bắn súng nhiều người chơi thường chọn nội suy kèm bù trễ, vì số lượng thực thể quá lớn để mô phỏng lại tất cả. Game chiến lược thời gian thực với hàng nghìn đơn vị thường chọn lockstep, vì băng thông để gửi trạng thái của từng đơn vị là không khả thi.

Cùng một bài toán, ba lời giải, ba cách phân bổ chi phí trên sáu trục.

Khung này dùng được cho cả quyết định thiết kế

Đây là điểm khiến bộ sáu trục đáng học hơn một danh sách kỹ thuật.

Độ chính xác đổi lấy tính đọc được. Nhân vật trong game thường được vẽ với tỷ lệ đầu lớn hơn thực tế, vũ khí lớn hơn thực tế, mũi tên bay theo quỹ đạo phi vật lý. Tất cả đều là hy sinh độ chính xác để người chơi đọc được tình huống nhanh hơn. Nhà thiết kế đang tiêu vào cùng một trục mà lập trình viên tiêu khi bật nén kết cấu bề mặt.

Độ trễ đổi lấy cảm giác công bằng. Coyote time và input buffering, đã bàn trong bài về vòng phản hồi, chính là việc chấp nhận sai lệch so với mô phỏng đúng để bù cho độ trễ trong vòng phản hồi của con người. Đây là đánh đổi giữa độ chính xác và độ trễ, thực hiện bởi nhà thiết kế chứ không phải bởi kỹ sư.

Thời gian sản xuất đổi lấy chiều sâu. Trong bài về tính nổi trội, số cặp tương tác tăng theo bậc hai của số thành phần. Quyết định thêm thành phần thứ chín vào một hệ thống tám thành phần là quyết định chi thêm tám cặp tương tác vào trục thời gian sản xuất, để mua thêm chiều sâu. Diễn đạt như vậy thì cuộc tranh luận trở nên định lượng được thay vì thành cuộc cãi vã về khẩu vị.

Bộ nhớ đổi lấy bề rộng nội dung. Trên di động, kích thước gói tải về ảnh hưởng trực tiếp tới tỷ lệ cài đặt, nên số lượng trang phục, bản đồ và đoạn nhạc đều là những khoản chi vào trục bộ nhớ, và quyết định đó thuộc về phía sản phẩm chứ không phải phía kỹ thuật.

Giá trị thực tế của việc dùng chung một khung cho cả hai phía là nó cho phép nhà thiết kế và kỹ sư tranh luận bằng cùng một ngôn ngữ. Câu “tính năng này quan trọng lắm” không so sánh được với câu “tính năng này tốn 2 mili giây”. Nhưng câu “tính năng này chi 2 mili giây tính toán để mua thêm khả năng đọc tình huống” thì so sánh được với mọi đề xuất khác đang cạnh tranh cùng ngân sách.

Ba sai lầm thường gặp

Sai lầm thứ nhất: đánh đổi mà không biết mình đang trả bằng gì. Đây là dạng phổ biến nhất và cũng nguy hiểm nhất, vì chi phí vẫn được trả, chỉ là không ai theo dõi. Một lập trình viên bật nén kết cấu để tiết kiệm bộ nhớ và vô tình đẩy chi phí giải nén sang trục tính toán trên GPU. Nếu không đo lại thì vấn đề chỉ lộ ra khi ai đó phát hiện game tụt khung hình trên máy cấu hình thấp, ba tháng sau.

Sai lầm thứ hai: tối ưu một trục tới cực trị. Mọi trục đều có vùng lợi ích giảm dần. Giảm bộ nhớ từ 4 gigabyte xuống 2 là cải thiện lớn. Giảm tiếp từ 2 xuống 1,9 thường tốn nhiều công hơn và mang lại ít hơn nhiều so với việc dùng công đó cho một trục khác đang căng hơn. Câu hỏi đúng luôn là trục nào đang là điểm nghẽn, chứ không phải trục nào đang cao nhất.

Sai lầm thứ ba: vay trên trục thứ sáu mà không ghi sổ. Nợ kỹ thuật, xét cho cùng, chính là một khoản vay trên trục thời gian sản xuất. Nó khác các trục khác ở chỗ khoản vay này có lãi kép: mỗi tuần không trả thì lượng công việc phải làm để trả lại tăng lên. Nợ kỹ thuật được ghi lại và có kế hoạch trả là một đánh đổi hợp lệ. Nợ kỹ thuật không ai ghi lại thì không phải đánh đổi, đó là một khoản lỗ chưa được ghi nhận.

Quy trình bốn bước khi phải đánh đổi

Một, xác định trục nào đang là điểm nghẽn thật. Điều này đòi hỏi đo chứ không đoán, và nó cũng là bước hay bị bỏ qua nhất.

Hai, liệt kê các phương án theo dạng lấy từ đâu, trả vào đâu. Chỉ cần viết ra dưới dạng hai cột như bảng ở trên là phần lớn phương án tự loại mình.

Ba, kiểm tra trục nhận có còn chỗ không. Chuyển chi phí sang một trục cũng đã cạn thì không giải quyết được gì, chỉ dời vấn đề sang chỗ khó nhìn hơn.

Bốn, ghi lại quyết định cùng lý do. Sáu tháng sau sẽ có người hỏi vì sao hệ thống này lại làm theo cách kỳ quặc như vậy, và nếu không có ghi chép thì câu trả lời hợp lý duy nhất họ nghĩ ra được là do người trước làm ẩu. Trong phần lớn trường hợp, sự thật là người trước đã đánh đổi có ý thức trên một trục mà hôm nay không còn ai nhớ là nó từng căng.

Vì sao trục thứ sáu khác năm trục kia

Kết bài bằng một khác biệt đáng chú ý.

Năm trục đầu tiên được tái tạo lại liên tục. Bộ nhớ được giải phóng rồi cấp lại, ngân sách khung hình bắt đầu lại từ đầu mười sáu mili giây một lần, băng thông trôi qua rồi lại có. Nếu một khung hình tiêu quá tay, khung sau vẫn có đủ ngân sách để làm lại cho đúng.

Trục thời gian sản xuất thì không. Một tuần đã tiêu là mất vĩnh viễn, và nó là trục duy nhất mà quyết định hôm nay ảnh hưởng trực tiếp tới khả năng đánh đổi của ngày mai. Một đội tiêu hết thời gian vào việc tối ưu quá sớm sẽ không còn thời gian để tìm ra trò chơi có vui hay không. Một đội không tiêu đủ thời gian vào kiến trúc sẽ mất khả năng đánh đổi trên năm trục kia, vì mọi thay đổi đều trở nên quá đắt.

Điều đó dẫn tới câu hỏi cuối cùng, và có lẽ là câu hỏi giá trị nhất trong toàn bộ bài viết: quyết định này đang mua cho tôi khả năng đánh đổi trong tương lai, hay đang tiêu mất nó.

Tài liệu tham khảo

  1. Edgegap, How to Mitigate Latency in Multiplayer Games: Input Delay vs Rollback. Nguồn của mô tả kiến trúc trễ đầu vào, chi phí CPU của việc mô phỏng lại, và lưu ý về chi phí băng thông. https://edgegap.com/blog/how-to-mitigate-latency-in-multiplayer-games-input-delay-vs-rollback
  2. SnapNet, Netcode Architectures Part 2: Rollback. Nguồn của phép tính 15 khung hình mô phỏng lại trong 16,66 mili giây và ngân sách 1,1 mili giây cho một bước. https://www.snapnet.dev/blog/netcode-architectures-part-2-rollback/
  3. SnapNet, Netcode Architectures Part 3: Snapshot Interpolation. Nguồn của lập luận vì sao nội suy ảnh chụp tốn ít CPU hơn rollback đầy đủ. https://snapnet.dev/blog/netcode-architectures-part-3-snapshot-interpolation/
  4. SnapNet, Input Delay vs Rollback. Nguồn của mô tả các dạng biểu hiện khi dự đoán sai. https://www.snapnet.dev/docs/core-concepts/input-delay-vs-rollback/
  5. Mighty Professional, Networking: Netcode and Rollback. Nguồn của luận điểm rằng netcode không đánh bại được vật lý mà chỉ giấu nó, và của phần độ trễ nội suy là đánh đổi có chủ đích. https://mightyprofessionalgaming.com/tutorials/netcode-from-scratch
  6. Respawn, How to Add Multiplayer to Your Game: An Introduction to Networking. Nguồn của mô tả cơ chế rollback trong game đối kháng. https://respawn.outlookindia.com/gaming/gaming-guides/how-to-add-multiplayer-to-your-game-an-introduction-to-networking
  7. Game Dev Cheat Sheet, Frame Budget Calculator for Unity Game Development. Nguồn của cách chia ngân sách khung hình giữa CPU và GPU. https://gamedevcheatsheet.com/frame-budget
  8. Generalist Programmer, Game Optimization: Performance Guide for 60+ FPS. Nguồn của các kỹ thuật đổi độ chính xác lấy tính toán như mức chi tiết theo khoảng cách và loại bỏ vật ngoài tầm nhìn. https://generalistprogrammer.com/tutorials/game-optimization-complete-performance-guide-2025
  9. Triverse, Low Poly vs High Poly. Nguồn của ví dụ gộp đối tượng để đổi bộ nhớ lấy số lệnh vẽ. https://triverse.ai/blog/low-poly-vs-high-poly
  10. Fiedler, Glenn. Fix Your Timestep, Gaffer on Games. Nguồn của đánh đổi giữa bước thời gian cố định và độ chính xác của mô phỏng. https://gafferongames.com/post/fix_your_timestep/

Tags:

0 Lời bình

Gửi Lời bình

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

BÀI VIẾT LIÊN QUAN

BẠN MUỐN HỌC LẬP TRÌNH?

GỌI NGAY

098 953 44 58

Đăng ký tư vấn lộ trình học lập trình

Đăng ký tư vấn, định hướng lộ trình học và giải đáp các thắc mắc về ngành nghề – Miễn phí – Online.

1 + 9 =