Files
BABA_YAGA/Assets/UI/Game UI_UX Architecture & Routing Specification.md
2026-04-28 00:07:42 +07:00

15 KiB

Đặc tả Kiến trúc & Định tuyến Game UI/UX (Phiên bản Unity UI Toolkit) Tài liệu này phác thảo toàn bộ bố cục cấu trúc, thiết kế trực quan, hiệu ứng chuyển động (animation) và logic định tuyến cho giao diện người dùng của game, được tối ưu hóa đặc biệt cho Unity UI Toolkit.

  1. Hệ thống Thiết kế Tổng thể & Phân bổ Dự án Để duy trì tính nhất quán, dễ bảo trì và làm việc nhóm hiệu quả, dự án tuân thủ nghiêm ngặt nguyên tắc chia tách giao diện (View) và logic (Controller). 1.1. Cấu trúc Thư mục (Directory Structure)
  • /Assets/UI: Chứa TOÀN BỘ các file thiết kế giao diện (Visual Assets).
    • Các file module hóa: MainMenu.uxml, Lobby.uxml (chứa cả UI Create Room & Join Room), Profile.uxml, Settings.uxml, MainGameHUD.uxml.
    • Style toàn cục: Global.uss.
    • Fonts, Hình ảnh, Icons, Custom Shaders cho UI.
  • /Assets/Scripts/UI: Chứa TOÀN BỘ các script logic (.cs).
    • UIManager.cs (Quản lý luồng chính).
    • BaseUIController.cs (Lớp cha chứa logic chung).
    • Các controller kế thừa: MainMenuController.cs, LobbyController.cs, v.v. 1.2. Hệ thống Controller (OOP - Kế thừa)
  • BaseUIController.cs: Lớp cơ sở (Base Class) cho mọi màn hình UI. Định nghĩa các virtual method cốt lõi như Show(), Hide(), PlayTransitionIn(), PlayTransitionOut(), và đăng ký sự kiện.
  • Inheritance: Các class khác (MainMenuController, LobbyController...) sẽ kế thừa (inherit) từ BaseUIController và override lại logic cụ thể của từng màn hình, giúp code không bị lặp lại (DRY - Don't Repeat Yourself). 1.3. UIManager & Hierarchy (Phân cấp)
  • Kiến trúc Hierarchy: Trong Scene, UIManager là một GameObject root duy nhất gắn component UIDocument. Nó đóng vai trò là "Thành phần UI Cha", chứa toàn bộ các template UXML của các màn hình con (MainMenu, Lobby, Settings...) bên trong nó.
  • Tính năng Debug: UIManager được thiết kế có custom Inspector, cho phép Dev/Designer có thể tick bật/tắt nhanh các màn hình trực tiếp trên Editor, và theo dõi/thay đổi nhanh các chỉ số debug (ping, trạng thái UI) theo thời gian thực mà không cần viết lệnh console.
  • DontDestroyOnLoad: UIManager (và EventSystem đi kèm) sẽ được đánh dấu DontDestroyOnLoad. Nó tồn tại xuyên suốt qua nhiều Scene, cực kỳ lý tưởng để duy trì kết nối mạng (Networked UI) khi sử dụng Photon Fusion hoặc Unity Relay mà không bị ngắt quãng UI giữa các lần load map. 1.4. Xử lý WorldSpace UI (Giao diện trong không gian 3D) Đối với các UI xuất hiện trong WorldSpace (VD: Thanh máu trên đầu nhân vật, Tên người chơi, Tương tác vật phẩm 3D):
  • Không bỏ chung vào UIManager chính (vốn là ScreenSpace - Overlay).
  • Sử dụng một GameObject 3D riêng biệt, gắn component UIDocument.
  • Thay vì dùng PanelSettings của màn hình chính, gán cho nó một WorldSpace PanelSettings riêng hoặc sử dụng kĩ thuật render UI Toolkit vào một RenderTexture và chiếu nó lên một Quad (phụ thuộc vào phiên bản Unity đang dùng).
  • Logic WorldSpace UI được quản lý cục bộ bởi Entity đó (VD: PlayerWorldUIController.cs). 1.5. Các Framework & Thư viện Cần thiết
  1. PrimeTween: Hệ thống Animation cốt lõi (Xử lý các hiệu ứng lò xo, trượt, fade).
  2. Unity New Input System: Xử lý input chuột đặc biệt và phím tắt.
  3. UniTask: Quản lý luồng bất đồng bộ (chờ animation chuyển cảnh).
  4. VContainer / Zenject: Dependency Injection.
  5. Photon Fusion / UGS: Backend mạng.
  6. Trải nghiệm Tương tác Cốt lõi (Core UX) 2.1. Logic "Con trỏ vô hình" & Pulse Effect (Chỉ ở Main Menu)
  • Ẩn có điều kiện: Con trỏ chuột của hệ điều hành Cursor.visible = false CHỈ được áp dụng khi người chơi ở màn hình MainMenu. Ở các màn hình khác (Lobby, Settings), con trỏ chuột bình thường sẽ xuất hiện lại để dễ nhập liệu.
  • Tương tác Top-Down: Có một "Con trỏ ảo" (Virtual Cursor) bằng UI Toolkit luôn nằm trên cùng (z-index cao nhất). Các thao tác Raycast sẽ bắn từ trên xuống.
  • Hiệu ứng Pulse (Tính toán khoảng cách): Tương tự osu!lazer, hệ thống liên tục tính toán khoảng cách vector từ tọa độ con trỏ ảo đến tâm (center) của các component UI tương tác. Khi con trỏ tiến lại gần, component đó sẽ dần dần phóng to lên (Pulse/Scale) mượt mà dựa trên cự ly, tạo cảm giác UI "đang sống" và hút chuột. 2.2. Hiệu ứng Nút bấm lò xo (Osu! Spring Effect) Tất cả các nút bấm (Button) trong game khi có sự kiện PointerDownEvent sẽ bị ép/nén (scale nhỏ lại, VD: 0.9x). Khi nhả chuột (PointerUpEvent), PrimeTween sẽ kích hoạt hiệu ứng nảy (elastic/bounce) vọt lố (overshoot) lên 1.1x rồi dao động từ từ về lại kích thước 1.0x. Cảm giác bấm phải rất đầm và có lực nén như lò xo. 2.3. Hiệu ứng Chuyển cảnh Toàn cục (Global Screen Transitions)
  • Background tĩnh: Hình nền phía sau (hoặc cảnh 3D) luôn giữ nguyên, không bị giật hoặc nhấp nháy khi chuyển màn hình.
  • Fly-Out & Fly-In:
    • Khi gọi UIManager.Push(NewScreen): Màn hình cũ (BaseUIController.PlayTransitionOut()) sẽ chia làm 2 nửa, hoặc trượt toàn bộ bay ra khỏi mép màn hình (trái và phải).
    • Ngay sau đó, Màn hình mới (BaseUIController.PlayTransitionIn()) sẽ bay vào từ 2 mép màn hình tiến vào giữa, kết thúc bằng một hiệu ứng Bounce nhẹ để tiếp đất.
  1. Chi tiết Triển khai Từng Màn hình (Visual Layout & Components) 3.1. Main Menu (MainMenu.uxml) Đây là màn hình phô diễn kỹ thuật UI với trạng thái máy trạng thái (State Machine) phức tạp.
  • Trạng thái 1: Mới tải (Idle)
    • Trực quan: Nền trong suốt hoặc Blur cảnh nền. Chỉ có một khối VisualElement hình tròn lớn (Logo) nằm chính giữa màn hình. Liên tục "đập" (pulse) scale từ 1.0 -> 1.05 theo nhịp nhạc.
  • Trạng thái 2: Menu Hoạt động (Ribbon State)
    • Chuyển từ State 1 -> 2: Khi click vào Logo, Logo trượt mượt mà sang vị trí lệch trái. Dải băng (VisualElement dạng hình chữ nhật dài tràn viền, có màu nền gradient) mở ra.
    • Cấu trúc Ribbon (Flex-direction: Row): [ Settings ] (Nút vát chéo, icon răng cưa) -> [ LOGO ] -> [ Join ] -> [ Create ] -> [ Profile ] -> [ Exit ]. 3.2. Lobby / Sảnh chờ (Lobby.uxml) Màn hình Lobby sử dụng chung layout Chia đôi đường chéo (Diagonal Split).
  • Khung Trái (Left Pane - 60% width): Nền trong suốt (background-color: clear), chỉ dùng để render hiển thị nhân vật 3D đứng trong sảnh.
  • Khung Phải (Right Pane - 40% width): Nền kính mờ (Frosted glass/Blur backdrop). Bên trong Khung Phải sẽ linh hoạt thay đổi nội dung tùy vào việc người chơi chọn Join hay Create:
  • A. Giao diện Join Room: Có TextField tìm kiếm, DropdownField sắp xếp, và ScrollView chứa danh sách phòng.
  • B. Giao diện Create Room: Các ô TextField nhập Tên phòng, Checkbox Toggle Mật khẩu, và nút CREATE khổng lồ.
  • C. Giao diện Lounge: Chia chéo 50/50. Nền Host ám xanh, Guest ám cam. Cả 2 đều có nút Toggle "Ready". 3.3. Profile (Profile.uxml) Áp dụng lại khung Split chéo tương tự Lobby. Khung trái chiếu nhân vật.
  • Khung Phải (Right Pane):
    • Header: Avatar (Mask tròn), Username lớn, Badge Rank.
    • Stats: Các thanh ProgressBar tỷ lệ thắng, Label số trận, Elo Rating.
    • Inventory: ScrollView chứa thẻ Skin/Banner. 3.4. HUD Trong Game (MainGameHUD.uxml) Màn hình bao phủ toàn cảnh, set picking-mode: ignore gốc.
  • Top-Left: 2 ProgressBar (Máu, Thể lực) dùng shader Fluid lấp đầy.
  • Top-Right: Minimap dạng tròn/vuông bo viền, có fade opacity ở mép.
  • Bottom-Left: Túi đồ ngang, 1 ô lớn (Đang cầm) và 3 ô nhỏ (Khe phím 1,2,3).
  • Bottom-Center: Text Ping & FPS tối giản. 3.5. Menu Cài đặt / Settings (Settings.uxml) Thiết kế dạng Sidebar trượt ngang (Slide-in Panel) từ lề trái và không chặn tương tác (Non-blocking UI).
  • Bố cục 2 Cột (Split-Pane):
    • Cột Trái (Tabs - 30%): Chứa các nút [ General ], [ Video ], [ Sound ], [ Control ]. Nút đang chọn sẽ đổi màu và có viền mép trái.
    • Cột Phải (Details - 70%): Chứa một ScrollView duy nhất. Nội dung bên trong (Sliders, Dropdowns, Toggles) thay đổi động dựa theo Tab đang chọn ở cột trái.
  • Nút Close: Một nút < Back hoặc [ X ] ở góc trên lề trái.
  1. Logic Định tuyến (UIManager.cs) [Game Launch]
    |
    [Main Menu] (State 1: Idle) <---(Timeout/No Input)---+ | | (Click Logo) | | | [Main Menu] (State 2: Ribbon) -----------------------+ |
    +-------(Click Logo Lần 2)------> [Lobby: Create] | +-------------------+-------------------+-------------------+
    | | | |
    v v v v
    [Lobby: Create] [Lobby: Join] [Profile] [Settings (Sidebar)]
    | | | |
    v v | |
    [Lounge (Host)] [Lounge (Guest)] +---(Back)----------+
    | |
    +--- [All Ready] ---+
    |
    (Host Clicks Start)
    |
    v
    [IN-GAME HUD]
  • Transition Flow: UIManager.Push(T extends BaseUIController). Hàm này gọi CurrentScreen.PlayTransitionOut() (Fly-out) -> Chờ hoàn thành -> Kích hoạt màn hình mới -> Gọi NewScreen.PlayTransitionIn() (Fly-in Bounce).
  1. Chi tiết Hệ thống Script & Logic Controller (C#) Mục này quy định trách nhiệm của từng file script (.cs) điều khiển các thành phần UXML, xử lý logic tương tác và event binding thông qua query (root.Q). 5.1. BaseUIController.cs Lớp cha trừu tượng (Abstract) cung cấp các hàm nền tảng cho mọi màn hình.
  • Biến: protected VisualElement root;, protected UIManager uiManager;
  • Hàm Initialize(VisualElement uxmlRoot, UIManager manager): Khởi tạo controller, nhận tham chiếu đến nhánh UXML cụ thể của nó.
  • Hàm Show() / Hide(): Thay đổi thuộc tính style.display thành Flex hoặc None.
  • Hàm PlayTransitionIn() / PlayTransitionOut(): (Virtual) Khai báo logic PrimeTween để trượt/bay màn hình ra/vào. Mặc định là trượt ngang toàn bộ nhánh root. 5.2. MainMenuController.cs Quản lý cỗ máy trạng thái (State Machine) của Main Menu và khóa trục chuột.
  • State Management: Có biến enum MenuState { Idle, Ribbon }.
  • Event Binding: Lấy phần tử Logo (root.Q("Logo")), gán sự kiện PointerDownEvent.
    • Nếu click khi đang Idle: Chuyển state sang Ribbon, dùng PrimeTween trượt Logo sang trái, bung dải Ribbon ra. Khởi động Timer Timeout.
    • Nếu click khi đang Ribbon: Gọi uiManager.Push().
  • Idle Timeout Logic: Hàm Update() liên tục đếm thời gian từ lần cuối có tương tác (mouse di chuyển/click). Nếu vượt quá X giây (vd: 5s), tự động trigger tween trả Logo về giữa và đóng Ribbon.
  • Mouse Axis Locking: Giao tiếp với Input System. Khi ở trạng thái Ribbon, ép tọa độ trục Y của con trỏ ảo luôn bằng với tọa độ Y của dải Ribbon. 5.3. LobbyController.cs Xử lý logic 3 lớp giao diện bên trong Lobby (Create, Join, Lounge) mà không cần chuyển Screen mới.
  • Sub-Views Toggling: Lấy tham chiếu đến 3 VisualElement container (JoinContainer, CreateContainer, LoungeContainer). Xử lý ẩn/hiện (display: none) chúng dựa theo path định tuyến từ UIManager.
  • Join Logic: Gán danh sách giả/mạng vào ScrollView. Khởi tạo các item đúc sẵn (prefabs bằng uxml) bằng vòng lặp. Lắng nghe event click của từng item phòng để hiện Modal nhập Password nếu cần.
  • Lounge Logic: Lắng nghe nút Toggle Ready. Gửi RPC mạng báo cho người chơi kia. Khi cả 2 biến isPlayer1Ready và isPlayer2Ready = true, gỡ khóa (Enable) nút [ START GAME ] cho Host. 5.4. SettingsController.cs Xử lý thanh Sidebar và cơ chế chia tab.
  • Tab Switching: Gán sự kiện ClickEvent cho 4 nút Tab ở Cột trái. Khi click, dùng vòng lặp xóa class .active-tab của tất cả, thêm .active-tab cho nút vừa click. Đồng thời Clear() nội dung của ScrollView ở Cột phải và Load/Instantiate layout của tab tương ứng vào.
  • Non-blocking Transition: Hàm PlayTransitionIn() của riêng SettingsController chỉ trượt nhánh root (Sidebar) từ -500px (bên ngoài mép trái) về 0px thay vì ẩn toàn bộ các màn hình khác đi.
  • Keybind Logic: Lắng nghe phím Esc để gọi hàm đóng Settings. Trong Tab Control, khi click đổi phím, script gọi luồng InputSystem.onAnyButtonPress để bắt phím tiếp theo và cập nhật tên Label. Lắng nghe thanh Slider để gọi AudioMixer.SetFloat(). 5.5. ProfileController.cs Cập nhật dữ liệu tài khoản hiển thị lên View.
  • Data Binding: Khi gọi Show(), controller kéo dữ liệu từ hệ thống lưu trữ (PlayerPrefs/Cloud). Tìm các thành phần root.Q("WinRateText"), root.Q("WinRateBar") và cập nhật .text hoặc .value của chúng.
  • Skin Inventory: Load kho đồ vào ScrollView ở cột phải. Lắng nghe ClickEvent vào các thẻ Skin để cập nhật Skin đang trang bị (báo cho Game Manager thay đổi vật liệu 3D ở Khung trái). 5.6. HUDController.cs Quản lý thông tin theo thời gian thực (Real-time). Không chặn Input.
  • Auto-Fade Logic: Giữ biến lastActionTime. Nếu Time.time - lastActionTime > 5f, dùng PrimeTween giảm opacity của túi đồ và thanh máu xuống 0.2f. Khi người chơi nhấn chuột, xài chiêu, hoặc bị sát thương -> gọi hàm WakeUpHUD() đẩy opacity về 1.0f ngay lập tức.
  • Inventory Quick-slots: Lắng nghe phím 1, 2, 3. Hoán đổi thuộc tính style.backgroundImage của Ô nhỏ đang chọn lên Ô [ Đang Cầm ] lớn nhất.
  • Fluid Shaders: Gửi dữ liệu biến thiên (VD: 0.0 -> 1.0) từ Máu/Thể lực hiện tại vào Material/Shader được gán trực tiếp trên VisualElement thông qua thuộc tính .customMaterial trong UI Toolkit.