Hãy tưởng tượng một lập trình viên vừa hoàn thành tính năng nhảy cho nhân vật. Code chạy đúng, không có bug, đã qua code review, đã có unit test cho hàm tính quỹ đạo, hiệu năng tốt. Theo mọi tiêu chuẩn của ngành phần mềm, tính năng này đã xong.
Rồi một người khác cầm tay cầm lên chơi thử ba mươi giây và nói: nhảy thấy nặng quá.
Không có dòng nào trong bản đặc tả nói nhân vật phải nhảy nhẹ. Không có test nào phát hiện ra vấn đề. Không có log lỗi. Nhưng người kia đúng, và tính năng đó chưa xong. Nó sẽ còn được sửa đi sửa lại mười lần nữa, và lần nào cũng phải có người cầm tay cầm lên chơi mới biết đã đúng chưa.
Khoảnh khắc này là thứ tách game development ra khỏi mọi nhánh khác của ngành phần mềm. Nó không phải là chuyện game khó hơn hay dễ hơn. Nó là chuyện game khác về mặt cấu trúc, và có ba khác biệt cấu trúc đáng gọi tên.
Game development là gì
Trước khi vào ba khác biệt, cần nói gọn về phạm vi. Game development là quá trình tạo ra một phần mềm tương tác thời gian thực, trong đó phần mềm đó phải tạo ra một trải nghiệm cụ thể cho người dùng chứ không chỉ hoàn thành một nhiệm vụ cụ thể.
Điểm đáng chú ý đầu tiên là nó không phải một nghề mà là ít nhất năm nghề chồng lên nhau: lập trình, thiết kế game, mỹ thuật, âm thanh, và sản xuất. Trong một dự án nhỏ, một người có thể làm cả năm. Trong một dự án lớn, năm nhóm này nói năm thứ ngôn ngữ khác nhau và phần lớn khó khăn quản lý nằm ở chỗ dịch giữa chúng.
Nhưng sự đa ngành không phải điều làm game khác biệt. Rất nhiều sản phẩm phần mềm khác cũng đa ngành. Ba điều dưới đây mới là những khác biệt không tìm thấy ở nơi khác.
Chú thích: Một studio làm game trông giống hệt một công ty phần mềm bất kỳ. Khác biệt không nằm ở công cụ hay quy trình bề mặt, mà ở bản chất của thứ đang được xây dựng.
Khác biệt thứ nhất: yêu cầu không thể đặc tả trước
Trong phần lớn ngành phần mềm, yêu cầu tồn tại trước khi code tồn tại. Một hệ thống quản lý kho cần biết tồn kho là bao nhiêu, một cổng thanh toán cần trừ đúng số tiền, một ứng dụng đặt vé cần giữ chỗ. Người dùng có thể mô tả sai, ưu tiên có thể đổi, nhưng nguyên tắc là có một sự thật nghiệp vụ nằm sẵn ngoài kia và phần mềm phải khớp với nó.
Trong game, yêu cầu trung tâm là trải nghiệm, và trải nghiệm không tồn tại trước khi có thứ để chơi. Không ai viết được câu “khi người chơi nhảy qua khe, họ phải cảm thấy vừa đủ hồi hộp” thành một tiêu chí nghiệm thu. Câu đó chỉ trở nên có nghĩa sau khi khe đã được dựng, nhân vật đã nhảy được, và có người thật ngồi chơi.
Hệ quả là quy trình làm game đảo ngược so với quy trình phần mềm truyền thống. Thay vì đặc tả rồi xây, người ta xây một thứ tối thiểu rồi dùng nó để khám phá ra đặc tả. Vòng lặp cơ bản trong giai đoạn tiền sản xuất là dựng bản mẫu, cho chơi thử, thu phản hồi, rồi tinh chỉnh bản mẫu, lặp đi lặp lại. Vòng lặp này nhanh, bẩn, dùng xong vứt, không mở rộng được, và được tạo ra chỉ để học chứ không phải để dùng lâu dài.
Điều này dẫn tới một nguyên tắc mà người mới vào nghề hay vi phạm. Sai lầm phổ biến là cố biến bản mẫu thành nền móng của game. Bản mẫu không được xây để đưa vào sản xuất. Chúng lộn xộn, chắp vá và cố tình tạm bợ. Khi giá trị đã được kiểm chứng, việc cần làm không phải là mở rộng bản mẫu mà là bắt đầu lại từ nền sạch. Ở bất kỳ ngành phần mềm nào khác, viết code rồi vứt đi có chủ đích là một hành vi cần giải trình. Ở đây nó là quy trình chuẩn.
Sau giai đoạn bản mẫu là một cột mốc rất đặc thù của ngành game. Lát cắt dọc là một phần nhỏ của game nhưng chơi được, cho thấy toàn bộ các thành phần vận hành cùng nhau, và khác với bản mẫu ở chỗ nó có đầy đủ tài nguyên đồ họa, nhạc, hoạt ảnh. Khi làm Xenoblade Chronicles, Nintendo yêu cầu đội phát triển làm trọn vẹn một vùng đất với chất lượng thành phẩm. Lý do là một khi biết chính xác làm một vùng tốn bao nhiêu, và biết game sẽ có bao nhiêu vùng, họ ước lượng được thời gian và ngân sách để hoàn thành cả trò chơi.
Đây chính là điểm khiến việc ước lượng dự án game khét tiếng khó. Một công ty gia công phần mềm có thể báo giá dựa trên đặc tả. Một studio game không thể báo giá cho câu “làm cho nó vui”, nên họ phải tự bỏ tiền làm lát cắt dọc trước rồi mới biết cái còn lại đáng giá bao nhiêu.
Chú thích: Buổi chơi thử là công cụ đo lường chính của ngành game. Nó đóng vai trò mà bản đặc tả yêu cầu đóng ở các ngành phần mềm khác: xác định xem sản phẩm đã đúng hay chưa.
Khác biệt thứ hai: chất lượng đo bằng cảm nhận
Khác biệt thứ nhất nói về việc không biết phải xây gì. Khác biệt thứ hai nói về việc không biết đã xây đúng chưa.
Trong phần mềm thông thường, phần lớn tiêu chí chất lượng là nhị phân hoặc đo được: đúng hay sai, nhanh hay chậm, an toàn hay có lỗ hổng. Trong game, một phần rất lớn chất lượng nằm ở một thứ mà ngành gọi là game feel, tức cảm giác điều khiển.
Steve Swink định nghĩa game feel là cảm giác xúc giác và vận động khi điều khiển đối tượng ảo trong không gian mô phỏng theo thời gian thực, với các tương tác được nhấn mạnh bằng nhiều lớp đánh bóng cảm giác như hoạt ảnh, âm thanh và phản hồi hình ảnh. Trong mô hình của ông, khái niệm phản hồi thời gian thực có nghĩa rất cụ thể: chu trình từ lúc người chơi đọc phản hồi, ra quyết định, hành động, đến lúc game nhận hành động đó và trả về phản hồi mới phải nằm dưới khoảng 100 mili giây, tức ngưỡng mà độ trễ chưa bị người chơi nhận ra.
Ngưỡng nhạy cảm còn thấp hơn nhiều ở một số thể loại. Nghiên cứu cho thấy người chơi giỏi có thể cảm nhận được độ trễ thấp tới 15 mili giây, và các hệ thống hướng tới esports thường đặt mục tiêu tổng độ trễ dưới 50 mili giây. Ngưỡng chấp nhận được cao hơn với game thông thường, với game nền tảng thì hiệu suất người chơi vẫn ổn định tới khoảng 50 mili giây, sau đó bắt đầu suy giảm dần.
Điểm quan trọng là những con số này không tự động biến thành tiêu chí nghiệm thu. Một cú nhảy có độ trễ 40 mili giây vẫn có thể bị chê là nặng, còn một cú nhảy có độ trễ tương tự nhưng thêm hoạt ảnh co giãn và một khung hình dừng lúc chạm đất lại được khen là đã tay. Chất lượng ở đây là kết quả của cả một gói cảm giác chứ không phải của một chỉ số.
Hệ quả kỹ thuật của điều này khá thú vị, vì nó buộc lập trình viên game phải viết những đoạn code cố tình sai về mặt vật lý. Hai kỹ thuật kinh điển là coyote time, tức cho phép người chơi vẫn nhảy được trong vài khung hình sau khi đã rời khỏi mép nền, và input buffering, tức ghi nhớ lệnh bấm sớm để thực thi ngay khi hành động trước kết thúc. Cả hai đều là những lời nói dối có chủ đích với mô phỏng, và cả hai đều tồn tại vì chúng làm người chơi cảm thấy game công bằng hơn thực tế.
Ngành cũng có một từ riêng cho lớp phản hồi phi chức năng này. Juice là phần thẩm mỹ không làm thay đổi luật chơi mà chỉ làm thay đổi trải nghiệm chơi. Mở một cánh cửa là cơ chế. Cánh cửa kêu cọt kẹt, bụi rơi xuống từ khung, màn hình rung nhẹ khi tấm gỗ nặng xoay ra, đó là juice. Nhận định thường gặp trong nghề là một game có cơ chế tầm thường nhưng juice tốt thường thắng một game có cơ chế xuất sắc mà không có juice.
Với người quen ngành phần mềm khác, đây là một cú sốc về giá trị. Rất nhiều công sức trong game được đổ vào những thứ không hề thay đổi hành vi hệ thống, và việc coi chúng là trang trí có thể phá hỏng cả sản phẩm.
Hệ quả về quy trình là ngành game không thể dựa vào kiểm thử tự động cho phần cốt lõi nhất của chất lượng. Kiểm thử tự động vẫn cần và vẫn có, nhưng nó bảo vệ được tính đúng đắn chứ không bảo vệ được cảm giác. Cách duy nhất để biết cảm giác đã đúng chưa là cho người thật chơi và quan sát họ.
Điểm này cũng giải thích một hiện tượng khiến người ngoài ngành khó hiểu, đó là vì sao số liệu telemetry không thay thế được chơi thử. Telemetry nói cho ta biết chín mươi phần trăm người chơi bỏ cuộc ở màn bảy. Nó không nói được vì sao, và giữa các giả thuyết như quá khó, quá dài, hướng dẫn không rõ, hay chỉ đơn giản là chỗ đó chán, chỉ có việc ngồi xem người chơi mới phân biệt được.
Chú thích: Tay cầm là toàn bộ đường dây nối giữa người chơi và trò chơi. Mọi phán xét về chất lượng của game feel đều đi qua vài chục mili giây giữa lúc ngón tay bấm xuống và lúc màn hình phản hồi.
Khác biệt thứ ba: ràng buộc thời gian thực tuyệt đối
Hai khác biệt trên nói về sự mơ hồ. Khác biệt thứ ba thì ngược lại hoàn toàn: nó là ràng buộc cứng nhất mà bất kỳ lập trình viên nào từng gặp.
Ở mục tiêu 60 khung hình mỗi giây, mỗi khung hình có khoảng 16,67 mili giây để hoàn thành toàn bộ công việc phía CPU gồm logic game, vật lý, trí tuệ nhân tạo và phát lệnh vẽ, cùng toàn bộ công việc phía GPU gồm xử lý đỉnh, quét mành, tô điểm ảnh và hậu kỳ. Ở 30 khung hình, ngân sách này nới ra 33,33 mili giây, còn ở 144 khung hình nó siết xuống 6,94 mili giây.
Điều làm ràng buộc này khác về chất so với hiệu năng trong phần mềm thường là tính tuyệt đối của nó. Một truy vấn web chậm 200 mili giây thì trang tải chậm hơn một chút và người dùng phần lớn không nhận ra. Một khung hình chậm 5 mili giây thì màn hình giật, và người chơi nhận ra ngay lập tức. Mọi thứ gồm nhập liệu, mô phỏng và dựng hình đều phải hoàn thành bên trong ngân sách đó, nếu không thì khung hình bị bỏ và người chơi thấy khựng.
Ngân sách này còn phải chia nhỏ ra cho từng hệ thống. Với 60 khung hình trên di động, cách chia thường gặp là 8 đến 10 mili giây cho CPU, 8 đến 10 mili giây cho GPU, và chừa 2 đến 3 mili giây dự phòng cho việc giảm xung do nhiệt và cho chi phí của hệ điều hành. Một cách phân bổ phổ biến là 40 phần trăm cho dựng hình, 30 phần trăm cho logic game, 20 phần trăm cho vật lý và hoạt ảnh, 10 phần trăm để dành. Khoảng dự phòng 1 đến 2 mili giây tồn tại chủ yếu để hấp thụ những cú vọt do nạp dữ liệu hoặc do bộ dọn rác gây ra.
Chính cụm cuối cùng đó dẫn tới hệ quả kiến trúc đặc thù nhất của lập trình game. Một game 2D bị rớt khung hình thường thua vì một trong bốn nguyên nhân: quá nhiều lệnh vẽ, cấp phát bộ nhớ mỗi khung hình làm kích hoạt bộ dọn rác, làm việc cho những thứ nằm ngoài màn hình mà không ai thấy, và mô phỏng bị gắn chặt vào tốc độ khung hình. Cách xử lý luôn theo cùng một trình tự: đo trước, rồi giảm lệnh vẽ bằng gộp sprite và atlas, loại bỏ cấp phát bằng object pooling, ngừng dựng hình những gì camera không thấy, và chạy mô phỏng trên bước thời gian cố định.
Đây là lý do vì sao một lập trình viên C# quen với phần mềm doanh nghiệp bước vào Unity thường bị sốc. Rất nhiều thói quen tốt ở nơi khác, như tạo đối tượng mới cho tiện, dùng LINQ trong vòng lặp, nối chuỗi thoải mái, đều là những hành vi tạo rác và trở thành nguồn giật hình. Object pooling, thứ mà ở ngành khác bị coi là tối ưu hóa sớm, ở đây là mẫu thiết kế mặc định.
Hệ quả sâu hơn nằm ở tư duy. Trong phần lớn ngành phần mềm, hiệu năng là một giai đoạn: xây cho đúng trước, tối ưu sau. Trong game, ngân sách khung hình là một ràng buộc thiết kế có mặt từ ngày đầu. Câu hỏi “màn này có bao nhiêu kẻ địch cùng lúc” không phải câu hỏi thiết kế thuần túy, nó là một khoản chi trong ngân sách 16,67 mili giây, và nhà thiết kế phải biết mình đang tiêu bao nhiêu.
Chú thích: Toàn bộ một khung hình ở 60 hình mỗi giây chỉ có 16,67 mili giây, và mọi hệ thống trong game đều tranh nhau cùng một khoản đó. Tỷ lệ phân bổ trên là một cách chia thường gặp, không phải quy tắc cứng.
Ba khác biệt này nhân với nhau
Nếu chỉ có một trong ba, game development sẽ khó nhưng không đặc biệt. Có những ngành phần mềm khác cũng chịu ràng buộc thời gian thực khắt khe, chẳng hạn hệ thống điều khiển công nghiệp hay giao dịch tần suất cao. Có những ngành khác cũng có yêu cầu mơ hồ, chẳng hạn sản phẩm tiêu dùng giai đoạn đầu.
Điều khiến game khác biệt là ba ràng buộc này xuất hiện cùng lúc và kéo ngược chiều nhau.
Khác biệt thứ nhất buộc ta phải thay đổi liên tục, vì chỉ có thay đổi và thử lại mới tìm được thứ đúng. Khác biệt thứ ba buộc ta phải tối ưu chặt chẽ, mà tối ưu chặt chẽ thì luôn làm code khó thay đổi hơn. Một hệ thống được tối ưu tới từng mili giây là một hệ thống có nhiều giả định cứng, và mỗi lần nhà thiết kế đổi ý thì một phần các giả định đó sụp.
Khác biệt thứ hai làm mọi thứ tệ hơn, vì nó khiến ta không bao giờ biết chắc khi nào thì dừng. Một tính năng nghiệp vụ có điểm dừng rõ ràng, đó là lúc nó chạy đúng. Một tính năng cảm giác thì luôn có thể tốt hơn một chút nữa.
Ba lực này giải thích khá nhiều bệnh mãn tính của ngành: phình phạm vi, ước lượng sai, làm thêm giờ kéo dài, và những dự án bị hủy sau nhiều năm phát triển. Chúng không phải là dấu hiệu của quản lý kém, dù quản lý kém làm chúng nặng thêm. Chúng là hình dạng mà ba ràng buộc kia để lại.
Những gì game development giống mọi ngành khác
Cần cân bằng lại, vì có một xu hướng trong cộng đồng làm game là coi ngành mình đặc biệt tới mức không áp dụng được kinh nghiệm từ nơi khác. Điều đó không đúng và khá tốn kém.
Kiểm soát phiên bản, tích hợp liên tục, đánh giá code, kiến trúc mô đun, kiểm thử tự động cho phần logic thuần túy, quản lý nợ kỹ thuật: tất cả đều áp dụng nguyên vẹn và mang lại lợi ích giống hệt như ở mọi nơi. Việc yêu cầu mơ hồ không phải là lý do để bỏ kỹ thuật phần mềm tử tế. Ngược lại, chính vì yêu cầu hay đổi mà kiến trúc dễ thay đổi lại càng quan trọng.
Điểm cần phân biệt là ở giai đoạn. Code bản mẫu thì đúng là nên bẩn và nên vứt. Code sản xuất thì phải theo chuẩn như bất kỳ hệ thống nào khác, thậm chí cao hơn, vì nó sẽ bị sửa nhiều hơn.
Với người đang học nghề
Nếu rút ba khác biệt này thành lời khuyên thực tế, có ba việc đáng rèn sớm.
Việc thứ nhất là rèn thói quen dựng nhanh và vứt không tiếc. Người mới thường tiếc code mình viết và cố cứu bản mẫu. Kỹ năng cần có là dựng được một thứ chơi được trong vài ngày, biết chấp nhận rằng phần lớn nó sẽ bị bỏ, và rút ra được kết luận rõ ràng từ nó.
Việc thứ hai là rèn khả năng quan sát người chơi mà không giải thích và không bào chữa. Đây là kỹ năng khó hơn nó nghe, vì bản năng tự nhiên khi thấy người ta chơi sai là nhảy vào chỉ dẫn. Thông tin giá trị nhất nằm chính xác ở chỗ họ chơi sai mà không có ai chỉ dẫn.
Việc thứ ba là rèn phản xạ đo trước khi tối ưu và nghĩ theo đơn vị mili giây thay vì theo cảm tính nhanh chậm. Biết dùng profiler và đọc được biểu đồ thời gian khung hình là kỹ năng phân biệt rõ nhất giữa người làm game nghiệp dư và người làm game chuyên nghiệp, rõ hơn cả việc biết bao nhiêu mẫu thiết kế.
Cuối cùng, có một điều đáng nói với những ai đang cân nhắc bước vào ngành. Ba khác biệt trên khiến game development khó hơn phần mềm thông thường ở nhiều mặt, nhưng chúng cũng chính là lý do nghề này hấp dẫn. Trong rất ít nhánh của ngành phần mềm, người viết code được nhìn thấy trực tiếp cảm xúc mà dòng code của mình tạo ra trên gương mặt một người lạ đang ngồi chơi. Đó là một dạng phản hồi mà không bản báo cáo nghiệp vụ nào thay thế được.
Tài liệu tham khảo
- Game Dev Cheat Sheet, Frame Budget Calculator for Unity Game Development.
- Generalist Programmer, Game Optimization: Performance Guide for 60+ FPS.
- PulseGeek, What Is a Frame Time Budget in Optimization.
- Egmatic, How to Optimize 2D Game Performance: A Practical Guide to 60 FPS.
- Polyphantom Creations, Don’t Use Frames to Measure Performance.
- Tono Game Consultants, Evolve Your Game Prototype Into a Vertical Slice.
- GameDev Diary, The Next Thing to Aim For After an MVP, bao gồm ví dụ Xenoblade Chronicles.
- Swink, Steve. Game Feel: A Game Designer’s Guide to Virtual Sensation, Morgan Kaufmann, 2009.
- Liz England, Review: Game Feel by Steve Swink.
- Pichlmair, Martin và Johansen, Mads. Designing Game Feel: A Survey, arXiv.
- Egmatic, How to Make Your Game Feel Good: A Guide to Game Feel and Juice.
- Hackread, The Juice Factor: Designing Game Feel.
- Nghiên cứu về ngưỡng cảm nhận độ trễ đầu vào trong game, arXiv.








0 Lời bình