Mô Phỏng Hiệu Ứng Xoay Góc Nghiêng Bằng Phép Biến Đổi 2D
Trong dịp Tết trở về nhà ở Vũ Hán, tôi chỉ có duy nhất một chiếc máy tính tích hợp giá khoảng 2000 nhân dân tệ để sử dụng. Chắc chắn rồi, chiếc máy này không thể chạy nổi các game 3D. Tôi chọn thử tựa game Invisible Inc. và thật bất ngờ, game chạy rất mượt mà.
Đây là một game chiến thuật theo phong cách XCOM với bối cảnh được thiết kế theo kiểu isometric. Điều đặc biệt là người chơi có thể xoay cảnh bằng phím Q và E. Dù khi dừng lại chỉ có 4 hướng cố định, nhưng quá trình xoay lại được thể hiện dưới dạng hoạt ảnh. Điều này khiến tôi ban đầu nghĩ rằng cảnh game được xây dựng từ mô hình 3D. Tuy nhiên, điều khiến tôi ngạc nhiên là trên chiếc máy cấu hình yếu này, game vẫn chạy mượt mà hơn nhiều so với XCOM 2 - tựa game tôi đang chơi trên card đồ họa GTX 550.
Quan sát kỹ, tôi phát hiện ra các vật thể trong game đều chỉ là hình ảnh 2D. Thậm chí nhiều vật chỉ có hai hình ảnh mặt trước và mặt sau, bốn góc nhìn còn lại được tạo ra bằng cách lật gương (mirror). Tốc độ xoay nhanh kết hợp hiệu ứng mờ (blur) đã đánh lừa thị giác người chơi. Thực tế, chỉ có sàn nhà và tường thực sự được xoay, các vật thể khác chỉ thay đổi tọa độ xoay còn hình ảnh vẫn giữ nguyên.
Nói cách khác, engine của game hoàn toàn dựa trên nền tảng 2D nhưng lại tạo ra hiệu ứng thị giác đặc trưng của 3D.
Tôi đặc biệt chú ý đến cách tường được xoay. Ban đầu tôi nghĩ chúng được render sẵn nhiều hình ảnh. Tuy nhiên, khi giải nén gói tài nguyên .kwad (có thể tìm công cụ trên Google), tôi phát hiện ra mỗi vật thể chỉ có 1-2 hình ảnh. Các hình ảnh này được nén bằng zlib định dạng RGBA bitmap, có thể tìm thấy thông tin định dạng trên mạng.
Lấy ví dụ về cánh cửa, chỉ có hình ảnh mặt trước (hoặc sau) dạng chữ nhật. Có lẽ trong engine, hình ảnh này được biến dạng thành hình bình hành phù hợp với góc nhìn nghiêng.
Tôi đã thử suy diễn ma trận biến đổi. Chỉ cần kiến thức hình học phẳng cấp 2 là đủ. Với góc nghiêng 30 độ, tỷ lệ x:y khoảng 2:1. Do đó, phép cắt (shear) sẽ có góc là arctan(tan(x)/2), ma trận biến đổi là [1, tan(x)/2, 0 , 1, 0, 0 ]. Ngoài ra, cần thực hiện phép co giãn (scale) trục x với tỷ lệ cos(x).
Dù tan(90°) tiến đến vô cực, nhưng khi nhân hai ma trận, hàm tan biến mất và trở thành sin. Ma trận cuối cùng là: [cos(x), sin(x)/2 , 0, 1, 0, 0 ]
Từ gói tài nguyên của Invisible Inc., tôi đã giải nén được hình ảnh cánh cửa như sau: !wall.png
Chúng ta có thể dùng CSS transform với ma trận style=“transform: matrix(0.707, 0.3535, 0,1,0,0);” để mô phỏng hiệu ứng xoay 45 độ ở góc nghiêng 30 độ: !wall.png
Tuy nhiên, vì đây là phép biến đổi affine không có phối cảnh, nên vẫn có cảm giác hơi kỳ lạ.
Tóm lại, Invisible Inc. là một tựa game tuyệt vời, rất đáng để trải nghiệm. Mặc dù có mod tiếng Trung trên Steam Workshop nhưng phiên bản này đã cũ, tôi không khuyến khích sử dụng. Nếu muốn dùng, bạn cần tự chỉnh sửa lại.
Hai vấn đề chính với mod này:
-
Công cụ sắp chữ của game phân tách từ bằng khoảng trắng. Những người làm mod dịch không nắm rõ điểm này, để tránh tình trạng câu dài bị ngắt giữa chừng, họ đã giảm kích thước chữ quá mức, khiến trải nghiệm đọc rất khó chịu. Thực tế, chỉ cần thêm khoảng trắng sau mỗi chữ Hán trong câu dài là có thể giải quyết vấn đề. Việc này có thể tự động hóa bằng script xử lý văn bản dịch. Ngoài ra, bộ font chữ cũng cần được thiết kế lại.
-
Thay đổi định dạng chuỗi tham số. Phiên bản cũ sử dụng định dạng kiểu C như %d để chèn số. Nhưng phiên bản mới chuyển sang dùng {1} cho tham số đầu tiên, {2} cho tham số thứ hai… Điều này khiến mod dịch cũ xuất hiện hàng loạt dòng như “Ngày %d” mà không hiển thị số, ảnh hưởng trải nghiệm. Giải pháp là vào màn hình credit, nhấn Ctrl+Insert để mở console, nhập lệnh localize để xuất lại văn bản và chỉnh sửa.
Tôi đã tự sửa một bản tạm thời trong dịp Tết, nhưng sau khi đi làm lại không mang theo, nên lười làm lại từ đầu. Thực tế, game vẫn chơi tốt mà không cần dịch.
Tại sao engine lại thay đổi cách định dạng chuỗi? Vì thứ tự từ trong các ngôn ngữ khác nhau có thể khác nhau. Ví dụ trong tiếng Anh nói “A gây ra B”, nhưng tiếng Trung lại nói “B bị A gây ra”. Nếu dùng định dạng kiểu C dựa trên thứ tự tham số, bản dịch sẽ bị lộn xộn. (Tôi kiểm tra lại bản dịch cũ, đã phát hiện lỗi này)
Hơn nữa, định dạng mới cho phép tham chiếu nhiều lần đến cùng tham số để xử lý các trường hợp biến đổi từ ngữ. Ví dụ ở phiên bản cũ: “%d turn(s)” trong phiên bản mới có thể viết là “{1} {1:turn|turns}” để tự động chọn “turn” hoặc “turns” tùy giá trị tham số.
Đây là những kinh nghiệm quý báu trong quá trình quốc tế hóa game, tôi ghi lại để