Khám Phá Thiết Kế Cảm Giác Hành Động Trong Game
Trong hai năm trở lại đây, dường như toàn bộ cộng đồng phát triển game đều hướng tới việc nâng cao “cảm giác hành động” và “cảm giác đánh trúng” trong các tựa game trực tuyến. Theo tôi nghĩ, lý do chính là vì ngày càng nhiều người chơi đã chán ngán với việc “đánh bao cát” (đánh vào mục tiêu bất động) truyền thống.
Thực ra vấn đề này đã được nhóm chúng tôi suy nghĩ từ ba năm trước, nhưng có lẽ đã đi vào ngõ cụt. Chúng tôi mải mê nghiên cứu các vấn đề kỹ thuật như đồng bộ mạng, làm thế nào duy trì công bằng dưới độ trễ mạng, ngăn chặn gian lận…
Sau nhiều lần thử nghiệm thất bại, chúng tôi nhận ra vẫn chưa tìm được phương pháp tối ưu để giải quyết các vấn đề này, đành tạm gác lại. Gần đây, khi nhiều đồng nghiệp trong công ty cùng mong muốn tăng cường trải nghiệm điều khiển trong game, chúng tôi quyết định quay lại chủ đề này với góc nhìn hoàn toàn mới: Giả sử chúng ta hoàn toàn bỏ qua yếu tố mạng, ngay cả khi làm game offline, chúng ta cũng chưa có nhiều kinh nghiệm thiết kế game hành động chuyên sâu. Do đó, việc đầu tiên cần làm là tạo ra cảm giác điều khiển đã, sau đó mới tính đến việc triển khai trên nền tảng mạng.
Điều này khiến tôi trăn trở rất lâu. Sau khi dành hàng tháng trời suy nghĩ và viết hàng ngàn dòng mã kiểm chứng, cuối cùng tôi mới dần hình thành được hệ thống lý luận rõ ràng. Bài viết này chỉ mang tính ghi lại suy nghĩ cá nhân, không dám khẳng định hoàn toàn chính xác, nhưng hy vọng có thể gợi mở một số ý tưởng cho đồng nghiệp. Trong quá trình thảo luận nội bộ, những quan điểm này từng bị chất vấn gay gắt, nhiều người không đồng tình. Đây chỉ là góc nhìn từ một phía, kính mong quý vị lượng thứ.
Điểm thứ nhất: Cảm giác hành động tốt không quá phụ thuộc vào engine đồ họa. Nếu nghĩ rằng chỉ cần tích hợp hệ thống vật lý, hệ thống ragdoll, mô-đun blend animation cao cấp là có thể giải quyết triệt để vấn đề, hay cho rằng việc mô phỏng vật lý chân thực sẽ mang lại trải nghiệm đã tay cho người chơi, theo tôi là quan điểm sai lầm.
Nhìn vào các game đối kháng kinh điển, từ Street Fighter - cha đẻ thể loại này, đến Samurai Shodown từng làm mưa làm gió trong ký túc xá đại học, hay Virtua Fighter - tựa game tôi yêu thích nhất, đều có chung đặc điểm: hệ thống đối kháng được xây dựng dựa trên các quy tắc đơn giản nhưng chặt chẽ. Chính từ những quy tắc nền tảng này, các nhà thiết kế mới xây dựng được sự cân bằng trong game. Gần đây tôi đọc được bài viết “Từ Street Fighter đến game đối kháng” trên Google Reader, hoàn toàn đồng cảm với quan điểm trong đó.
Điểm thứ hai: Với game hành động, animation phải được điều khiển bởi logic game, chứ không phải ngược lại. Không nên quá phụ thuộc vào biểu hiện hình ảnh để đưa ra các quyết định xử lý. Trong các game theo lượt cũ, vì không nhấn mạnh yếu tố điều khiển, thường chèn nhiều thông tin (như keyframe feedback) vào dữ liệu animation. Điều này hợp lý khi chỉ quan tâm đến kết quả hành động, vì giúp giảm coupling giữa animation và hệ thống bên ngoài. Tuy nhiên, khi muốn tăng độ chi tiết điều khiển - tức các yếu tố thiết kế cơ bản nhỏ hơn từng động tác hoàn chỉnh - cách làm này sẽ trở nên bản末 đảo trí.
Các nhà thiết kế phải nắm bắt từng chi tiết nhỏ trong các đoạn animation bị chia nhỏ, mới có thể kiểm soát sự cân bằng tổng thể. Không thể để các họa sĩ thiết kế chiêu thức hoa mỹ xong rồi mới dựa vào đó xác định phạm vi đánh trúng.
Khi chuyển từ 2D sang 3D, mặc dù khả năng biểu đạt tăng lên rõ rệt, nhiều nhà làm game lại bối rối không biết kiểm soát animation 3D như thế nào. Một số quay sang theo đuổi các công nghệ vật lý vốn thuộc về rendering như hệ thống va chạm vật lý, tôi rất nghi ngờ hướng đi này. Khi animation còn là từng frame vẽ tay, chúng ta vẫn tạo được cảm giác đánh trúng mạnh mẽ, điều này hoàn toàn có lý. Qua các tựa game 3D như Tekken, Virtua Fighter, rõ ràng vấn đề nằm ở phương pháp chứ không phải lỗi của công nghệ 3D.
Về kiểm soát animation, tôi từng thảo luận trên blog cá nhân. Trong thực tiễn, vì thiết kế chưa đủ tinh giản, chúng tôi đã loại bỏ thiết kế “hành động dẫn hướng” trong các game tương tác cao (vì cần kiểm soát chi tiết). Với các chuỗi hành động phức tạp, cách tối ưu nhất là dùng finite state machine (FSM). FSM giúp chia nhỏ code thành các phần độc lập, giảm coupling. Đặc biệt, FSM có thể biểu diễn dưới dạng dữ liệu thuần túy. Khi điều kiện chín muồi, có thể thiết kế một ngôn ngữ DSL riêng để mô tả. Trong giai đoạn nghiên cứu, vì chưa xác định rõ định dạng tối ưu, tôi tạm dùng bảng dữ liệu Lua. Cách này cho phép các nhân viên không chuyên lập trình có thể cùng bảo trì dữ liệu, tránh tình trạng một file code phình to mất kiểm soát. (Việc số hóa quy trình giúp tách biệt dữ liệu và thuật toán)
FSM còn tăng tính ổn định cho module kiểm soát hành động, giúp phát hiện sớm các chuyển trạng thái bất hợp lệ, giảm nguy cơ code trở thành “canh thập cẩm”.
Khó xử lý nhất là yếu tố tương tác trong hành động - cụ thể là sự phối hợp giữa kẻ tấn công và người bị tấn công. Việc quản lý logic này đều không tự nhiên nếu giao cho đối tượng tấn công hay bị tấn công. Giải pháp hợp lý là đưa vào một module độc lập thứ ba xử lý. Ngoài ra, trong game 3D hay “2.5D” (từ ngữ không chuẩn xác tôi không thích dùng), khác với game đối kháng truyền thống, tình huống “nhiều đánh một” phát sinh nhiều bất định. Sau khi suy nghĩ kỹ, tôi đưa ra phương án sau:
Trước tiên, trừu tượng hóa “trận đấu (Clash)” thành đơn vị chiến đấu nhỏ nhất. Mỗi trận đấu là một cuộc đối kháng một-một giữa hai chiêu thức. Trong một trận đấu luôn tồn tại duy nhất một người tấn công và một người phòng thủ. Trong không gian trận đấu, hai bên luôn hướng mặt vào nhau - tức tồn tại trong không gian 1D (nếu có yếu tố nhảy thì là 2D). Trong không gian này, các hành động chính là tiến lên và lùi lại, có thể do chủ động thực hiện hoặc bị động nhận vào. Trận đấu sẽ duy trì khoảng cách phù hợp thông qua các chiêu thức, vì chỉ khi khoảng cách hợp lý mới tạo ra cảm giác đánh trúng chân thực. Do yêu cầu duy trì khoảng cách, người phòng thủ thường bị ép lùi lại. Module trận đấu liên tục điều chỉnh hướng nhìn của các bên để giữ không gian trận đấu đúng chuẩn.
Mỗi trận chiến cục bộ gồm nhiều trận đấu diễn ra theo trục thời gian. Về mặt biểu hiện animation, mỗi đối tượng chỉ tồn tại trong một trận đấu tại một thời điểm (về mặt logic, vẫn có thể nhận sát thương từ nhiều nguồn). Phải thoát khỏi trận đấu hiện tại mới có thể tham gia trận đấu mới. Trận đấu kết thúc khi một trong hai bên tuyên bố