Hướng dẫn trung cấp

Tạo giao diện người dùng tương tác

*Nội dung này được dịch bằng AI (Beta) và có thể có lỗi. Để xem trang này bằng tiếng Anh, hãy nhấp vào đây.

Một HUD (Heads-Up Display) trong trải nghiệm của bạn thường hiển thị các phần tử UI không tương tác như đồng hồ sức khỏe được chứng minh trong Tạo đồng hồ HUD. Ngoài ra, gần như mọi trải nghiệm đều yêu cầu UI tương tác như các nút phản hồi khi người chơi kích hoạt, hoạt hình khi được kích hoạt, tween vào/ra các menu với các điều khiển tương tác khác, v.v.

Cái nhìn trong trò chơi hiển thị một nút cài đặt và menu cài đặt với các thanh trượt âm lượng.

Sử dụng UI Fundamentals - HUD Meter làm điểm khởi đầu và UI Fundamentals - Tương tác làm tài liệu tham khảo hoàn thiện, hướng dẫn này trình bày:

  • Cách định vị một nút cài đặt dọc theo cạnh trên của màn hình.
  • Thiết kế một menu cài đặt chứa các thanh trượt kéo thả tương tác.
  • Sử dụng một ModuleScripts để hình thành các module "controller" cho việc điều khiển mở rộng các đối tượng UI với các khai báo trạng thái.
  • Cách kết nối các nút với việc kích hoạt của người chơi để bật tắt menu cài đặt.
  • Cách kết nối các thanh trượt UI kéo thả để điều chỉnh âm lượng của hiệu ứng âm thanh và môi trường nền một cách riêng biệt.

Bật Trình Giả Lập Thiết Bị

Như đã lưu ý trong Tạo đồng hồ HUD, điện thoại và máy tính bảng có ít không gian màn hình nhất, vì vậy điều quan trọng là các phần tử UI của bạn phù hợp với màn hình nhỏ hơn và chúng rõ ràng với người chơi. Nếu bạn chưa làm như vậy, hãy bật Trình Giả Lập Thiết Bị trong Studio:

  1. Mở mẫu UI Fundamentals - HUD Meter trong Studio.

  2. Từ menu Test của Studio, bật Trình Giả Lập Thiết Bị.

  3. Từ thanh trực tiếp trên viewport chính, chọn một mô phỏng điện thoại như iPhone X hoặc Samsung Galaxy A51. Sau đó, đặt kích thước hiển thị thành Vừa với Cửa Sổ để sử dụng tối đa không gian trong Studio.

    Tùy chọn cài đặt Trình Giả Lập Thiết Bị được chỉ định ở trên cùng của cửa sổ viewport.

Tạo nút cài đặt

GuiButtons là các phần tử giao diện người dùng tương tác có chức năng tích hợp như sự kiện đa nền tảng Activated được kích hoạt khi nút được nhấn hoặc chạm vào. Lớp GuiButton mở rộng đến hai biến thể, TextButtonImageButton, và hướng dẫn này sử dụng một ImageButton hình "gear" để bật hoặc tắt menu cài đặt.

Phần tử Roblox được sử dụng cho nút cài đặt.

Để xây dựng nút cài đặt:

  1. Trong cửa sổ Explorer, tìm HUDContainer bên trong StarterGui.

    Cửa sổ Explorer hiển thị HUDContainer được chọn.
  2. Chèn một ImageButton vào HUDContainer và đổi tên thành SettingsButton.

    Cửa sổ Explorer hiển thị ImageButton mới được chèn và đổi tên thành SettingsButton. ImageButton mới trong viewport.
  3. Với nút mới được chọn, đặt các thuộc tính sau trong cửa sổ Properties:

    • AnchorPoint = 0.5, 0.25 (giữa theo chiều ngang và phần tư trên theo chiều dọc)
    • BackgroundTransparency = 1 (hoàn toàn trong suốt)
    • Position = 0.5, 0, 0, 0 (định vị ở giữa trên)
    • Size = 0.1, 0, 0.1, 0 (10% chiều cao màn hình khi tỉ lệ khía cạnh được giới hạn)
    • Image = rbxassetid://104919049969988 (ID tài sản của ký hiệu "gear")
  4. Chèn một UIAspectRatioConstraint vào nút với các thuộc tính mặc định (tỷ lệ 1:1 giữa chiều rộng và chiều cao).

    Cửa sổ Explorer hiển thị một UIAspectRatioConstraint mới được chèn vào nút SettingsButton.
  5. Để giới hạn chiều cao pixel tối đa của nút, chèn một UISizeConstraint và đặt thuộc tính MaxSize của nó thành inf, 44.

    Cửa sổ Explorer hiển thị một UISizeConstraint mới được chèn vào nút SettingsButton.
    Cửa sổ Properties hiển thị các giá trị mong đợi cho UISizeConstraint mới.
    Nút cài đặt cuối cùng ở giữa trên màn hình.

Tạo menu cài đặt

Nút cài đặt mới sẽ được lập trình để bật và tắt một menu cài đặt, cung cấp cho người chơi quyền truy cập vào cài đặt hoặc thông tin khác theo yêu cầu. Trong hướng dẫn này, menu sẽ chứa các thanh trượt tương tác để điều chỉnh mức âm lượng của âm thanh nền và hiệu ứng âm thanh một cách độc lập.

Các thành phần cơ bản được sử dụng cho menu cài đặt.

Tạo khung cha

Như đã lưu ý trong Tạo đồng hồ HUD, một Frame hoạt động như một container cho các đối tượng UI khác. Toàn bộ menu cài đặt sẽ được xây dựng với một khung cha duy nhất, giúp đơn giản hóa việc quản lý như một đối tượng trạng thái phản ứng với đầu vào khác nhau tùy theo trạng thái hiện tại.

  1. Chèn một Frame vào HUDContainer và đổi tên thành SettingsMenu.

    Cửa sổ Explorer hiển thị khung mới được chèn và đổi tên thành SettingsMenu.
  2. Với SettingsMenu được chọn, đặt các thuộc tính sau:

    Khung đã được định vị lại, thay đổi kích thước và tạo kiểu với nền xanh hải quân trong suốt.
  3. Chèn một UIAspectRatioConstraint vào SettingsMenu và đặt thuộc tính AspectRatio của nó thành 2.5. (tỷ lệ 2.5:1 giữa chiều rộng và chiều cao).

    Cửa sổ Explorer hiển thị một UISizeConstraint mới được chèn vào khung SettingsMenu.
    Cửa sổ Properties hiển thị các giá trị mong đợi cho UISizeConstraint mới.
  4. Chèn một bộ điều chỉnh UICorner vào SettingsMenu và đặt thuộc tính CornerRadius của nó thành 0.1, 0.

    Cửa sổ Explorer hiển thị một UICorner mới được chèn vào khung SettingsMenu.
    Cửa sổ Properties hiển thị các giá trị mong đợi cho bộ điều chỉnh UICorner mới.
  5. Để giới hạn chiều rộng và chiều cao pixel của SettingsMenu, chèn một UISizeConstraint. Đặt thuộc tính MaxSize của nó là 800, infMinSize350, 0.

    Cửa sổ Explorer hiển thị một UISizeConstraint mới được chèn vào khung SettingsMenu.
    Cửa sổ Properties hiển thị các giá trị mong đợi cho UISizeConstraint mới.
    Khung được tạo kiểu với các góc bo tròn.

Xây dựng một thanh trượt

Để cho phép người chơi điều chỉnh mức âm lượng, menu cài đặt sẽ chứa hai widget thanh trượt kéo thả được cung cấp bởi UIDragDetector, một đối tượng tiện lợi giúp tương tác với các phần tử giao diện người dùng 2D.


Để tạo một container cha cho thanh trượt đầu tiên:

  1. Chèn một Frame mới vào container SettingsMenu và đổi tên thành EffectsVolumeSlider.

    Cửa sổ Explorer hiển thị một khung mới được chèn vào khung SettingsMenu, đổi tên thành EffectsVolumeSlider.
  2. Với khung EffectsVolumeSlider được chọn, đặt các thuộc tính sau:

    • AnchorPoint = 0.5 (neo giữa)

    • BackgroundTransparency = 1 (hoàn toàn trong suốt)

    • Position = 0.5, 0, 0.35, 0 (giữa theo chiều ngang và 35% từ trên cùng của container)

    • Size = 0.8, 0, 0.1, 0 (80% chiều rộng của container và 10% chiều cao của nó)

      Khung trống được chèn để chứa các phần tử thanh trượt.
  3. Chèn một UIListLayout mới vào EffectsVolumeSlider. Bộ điều chỉnh bố cục này là cách mạnh mẽ để tự động sắp xếp các GuiObjects anh em thành các hàng ngang hoặc cột dọc bên trong container cha của chúng, bao gồm khả năng áp dụng các khái niệm flex.

    Cửa sổ Explorer hiển thị một UIListLayout mới được chèn vào khung EffectsVolumeSlider.
  4. Đặt các thuộc tính sau cho UIListLayout mới:

    • Padding = 0.06, 0 (không gian giữa các phần tử danh sách là 6%)
    • FillDirection = Horizontal (sắp xếp các phần tử từ trái sang phải)
    • HorizontalFlex = Fill (điều chỉnh lại kích thước các phần tử theo chiều ngang để lấp đầy toàn bộ container cha, ghi đè kích thước đã định nghĩa của chúng)
    • VerticalAlignment = Center (căn giữa các phần tử theo chiều dọc)

Biểu tượng của thanh trượt

Một biểu tượng đơn giản bao gồm một nốt nhạc âm thanh và ký hiệu "bùng nổ" giúp người chơi nhận biết mục đích của thanh trượt khi họ mở menu cài đặt.

Biểu tượng chỉ mục đích của thanh trượt trong menu cài đặt.
  1. Chèn một ImageLabel vào khung EffectsVolumeSlider và đổi tên thành Icon. Biểu tượng này sẽ giúp người chơi hiểu cái gì trong trải nghiệm mà thanh trượt điều khiển.

    Cửa sổ Explorer hiển thị một ImageLabel được chèn vào khung EffectsVolumeSlider.
  2. Với Icon được chọn, đặt các thuộc tính sau:

    • BackgroundTransparency = 1 (hoàn toàn trong suốt)
    • Size = 2.5, 0, 2.5, 0 (250% chiều cao của khung cha khi tỉ lệ khía cạnh được giới hạn)
    • Image = rbxassetid://90019827067389 (ID tài sản của nốt nhạc và ký hiệu "bùng nổ")
  3. Chèn một UIAspectRatioConstraint vào Icon và để các thuộc tính của nó là mặc định (tỷ lệ 1:1 giữa chiều rộng và chiều cao).

    Cửa sổ Explorer hiển thị một UIAspectRatioConstraint được chèn vào ImageLabel. Biểu tượng hoàn thành trong menu cài đặt.

Khung phạm vi

Ngay bên phải của biểu tượng, phần tương tác của thanh trượt nên được chứa trong một Frame khác.

Kích thước và vị trí mục tiêu của phần tương tác của thanh trượt.
  1. Chèn một Frame mới vào khung EffectsVolumeSlider và đổi tên thành SliderFrame. Lưu ý rằng nó phải là một anh em trực tiếp của bộ điều chỉnh bố cục UIListLayout.

    Cửa sổ Explorer hiển thị khung con được chèn vào khung EffectsVolumeSlider.
  2. Với SliderFrame được chọn, đặt các thuộc tính sau:

  3. Chèn các bộ điều chỉnh sau vào SliderFrame:

    Khung slider được định vị bên phải của biểu tượng.

Tay cầm tương tác

Với khung thanh trượt đã được xây dựng, bạn có thể tạo một tay cầm kéo thả cho người chơi tương tác trong quá trình chơi trò chơi.

Tay cầm thanh trượt tương tác nằm trong khung phạm vi.
  1. Chèn một Frame mới vào container SliderFrame và đổi tên thành Handle.

    Cửa sổ Explorer hiển thị khung con được chèn vào khung SliderFrame và đổi tên thành Handle.
  2. Với Handle được chọn, đặt các thuộc tính sau:

    • AnchorPoint = 0.5 (neo giữa)
    • Position = 0.5, 0, 0.5, 0 (giữa theo chiều ngang và chiều dọc của khung cha)
    • Size = 1.2, 0, 1.2, 0 (120% chiều cao của khung cha khi tỷ lệ khía cạnh được giới hạn)
    • ZIndex = 3 (lớp tay cầm hiển thị phía trước các phần tử thanh trượt khác)
  3. Chèn các bộ điều chỉnh sau vào Handle:

    • UIAspectRatioConstraint với các thuộc tính mặc định (tỷ lệ 1:1 giữa chiều rộng và chiều cao)
    • UICorner với thuộc tính CornerRadius được thiết lập thành 0.5, 0 (hình tròn)
    • UIStroke với thuộc tính Color được thiết lập thành [0, 150, 255]Thickness8 (viền xanh dày)
  4. Chèn một đối tượng UIDragDetector vào Handle. Đối tượng tiện lợi này khuyến khích tương tác với các phần tử giao diện người dùng 2D.

    Cửa sổ Explorer hiển thị một UIDragDetector được chèn vào khung Handle.
  5. Đặt các thuộc tính sau cho UIDragDetector mới:

  6. Để đảm bảo phạm vi kéo thả của tay cầm được giới hạn trong container của nó, liên kết thuộc tính BoundingUI với container SliderFrame:

    1. Nhấn thuộc tính BoundingUI của nó trong cửa sổ Properties.
    2. Quay lại cửa sổ Explorer, nhấp vào cha SliderFrame của tay cầm.
    Sơ đồ hiển thị quy trình liên kết thuộc tính BoundingUI của detector với container SliderFrame.

    Thuộc tính BoundingUI liên kết hiện phản ánh container SliderFrame:

    Cửa sổ Properties hiển thị thuộc tính BoundingUI của detector đã liên kết với container SliderFrame.

Nếu bạn kiểm tra trải nghiệm bây giờ, bạn sẽ có thể kéo tay cầm sang trái và phải trong container cha của nó:

Lấp đầy bên trong

Để cho thấy rõ hơn rằng thanh trượt điều khiển một phạm vi từ 0% đến 100%, bạn có thể thêm một lấp đầy bên trong vào phía bên trái của container sẽ đồng bộ với vị trí biến đổi của tay cầm.

Phần lấp đầy bên trong của thanh trượt được chèn vào SliderFrame.
  1. Chèn một Frame mới vào container SliderFrame và đổi tên thành InnerFill.

    Cửa sổ Explorer hiển thị khung con được chèn vào khung SliderFrame và đổi tên thành InnerFill.
  2. Đặt các thuộc tính sau cho khung InnerFill:

    • AnchorPoint = 0, 0.5 (điểm đầu bên trái và giữa theo chiều dọc)
    • BackgroundColor3 = [0, 150, 255] (màu xanh khớp với tay cầm của thanh trượt)
    • BackgroundTransparency = 0.35 (65% mờ đục)
    • Position = 0, 0, 0.5, 0
    • Size = 0.5, 0, 1, 0 (50% chiều rộng và 100% chiều cao của khung cha)
    • ZIndex = 2 (lớp hiển thị ở phía trước phần lấp đầy/viền của khung cha)
  3. Để khớp với hình "viên thuốc" của container cha SliderFrame, chèn một bộ điều chỉnh UICorner và đặt thuộc tính CornerRadius của nó thành 0.5, 0.

    Cửa sổ Explorer hiển thị một UICorner được chèn vào khung InnerFill.
    Cửa sổ Properties hiển thị các giá trị mong đợi cho UICorner mới.
    Khung InnerFill được tạo kiểu với nền xanh và các góc bo tròn.

Nhân bản thanh trượt

Với thanh trượt đầu tiên đã được xây dựng, bạn có thể dễ dàng nhân bản nó và thay đổi một số khía cạnh hình ảnh để chỉ ra một mục đích khác, trong trường hợp này là mức âm lượng của âm thanh nền được biểu thị bằng hình ảnh ký hiệu nốt nhạc.

Vị trí mục tiêu của thanh trượt âm thanh nền.
  1. Chọn đối tượng EffectsVolumeSlider đã hoàn thành.

    Cửa sổ Explorer hiển thị EffectsVolumeSlider đã hoàn thành được chọn.
  2. Nhân bản nó (CtrlD hoặc D) và sau đó đổi tên bản sao thành BackgroundVolumeSlider.

    Cửa sổ Explorer hiển thị thanh trượt đã được nhân bản và đổi tên thành BackgroundVolumeSlider.
  3. Thay đổi Position của bản sao thành 0.5, 0, 0.7, 0 để di chuyển nó bên dưới thanh trượt đầu tiên.

    BackgroundVolumeSlider được định vị bên dưới EffectsVolumeSlider.
  4. Mở rộng nhánh trên cùng của BackgroundVolumeSlider, chọn nhãn hình ảnh Icon, và thay đổi thuộc tính Image của nó thành rbxassetid://101125859760167 (ID tài sản của hình ảnh ký hiệu với nốt nhạc).

    Cửa sổ Explorer hiển thị nhãn Icon trong BackgroundVolumeSlider.
    Cửa sổ Properties hiển thị các giá trị mong đợi cho nhãn Icon.
    BackgroundVolumeSlider với hình ảnh biểu tượng đã được sửa đổi.
  5. Mở rộng nhánh SliderFrameHandle, chọn bộ điều chỉnh UIStroke bên trong, và đặt thuộc tính Color của nó thành [255, 0, 125] (màu tím).

    Cửa sổ Explorer hiển thị bộ điều chỉnh UIStroke bên trong tay cầm của BackgroundVolumeSlider.
    Cửa sổ Properties hiển thị các giá trị mong đợi cho bộ điều chỉnh UIStroke.
    BackgroundVolumeSlider với hình ảnh biểu tượng đã được sửa đổi.
  6. Chọn khung InnerFill bên trong SliderFrame và thay đổi thuộc tính BackgroundColor3 của nó thành màu tím giống nhau ([255, 0, 125]).

    Cửa sổ Explorer hiển thị khung InnerFill trong container SliderFrame của BackgroundVolumeSlider.
    Cửa sổ Properties hiển thị các giá trị mong đợi cho khung InnerFill.
    BackgroundVolumeSlider với màu InnerFill đã được sửa đổi.

Tạo nút đóng

Phần tử cuối cùng của menu cài đặt là một nút đóng cung cấp cho người chơi một đầu vào bổ sung để đóng menu (nút SettingsButton ở giữa trên sẽ phục vụ cùng một mục đích).

Menu cài đặt với nút đóng được chỉ định ở góc trên bên phải.
  1. Chèn một ImageButton mới vào container SettingsMenu và đổi tên thành CloseButton.

    Cửa sổ Explorer hiển thị một ImageButton mới được chèn vào SettingsMenu và đổi tên thành CloseButton. ImageButton trống được định vị ở góc trên bên trái của menu cài đặt.
  2. Với CloseButton được chọn, đặt các thuộc tính sau:

    • AnchorPoint = 1, 0 (góc trên bên phải)
    • BackgroundTransparency = 1 (hoàn toàn trong suốt)
    • Position = 1, -10, 0, 10 (10 pixel vào từ góc trên bên phải)
    • Size = 0.15, 0, 0.15, 0 (15% chiều cao của khung khi tỉ lệ khía cạnh được giới hạn)
    • Image = rbxassetid://5577404210 (ID tài sản của ký hiệu nút đóng)
    • ImageTransparency = 0.25 (75% mờ đục)
  3. Chèn một UIAspectRatioConstraint vào nút với các thuộc tính mặc định (tỷ lệ 1:1 giữa chiều rộng và chiều cao).

    Cửa sổ Explorer hiển thị một UIAspectRatioConstraint được chèn vào nút CloseButton. Nút đóng đã hoàn thành ở góc trên bên phải của menu cài đặt.

Tạo các module điều khiển

Một bộ module điều khiển có thể mở rộng giúp quản lý UI tương tác dễ dàng hơn so với các script riêng lẻ được đặt bên trong mỗi đối tượng. ModuleScripts tạo điều kiện cho chức năng có thể mở rộng này bằng cách cho phép bạn tái sử dụng mã giữa các script ở các phía khác nhau của biên client-server hoặc cùng một phía của biên giới.

Điều khiển đối tượng có trạng thái

Module điều khiển đối tượng có trạng thái sau đây cho phép bạn gán hành vi cho các đối tượng UI như SettingsButtonSettingsMenu, và dễ dàng bật/tween giữa các trạng thái khác nhau. Để tạo module:

  1. Chèn một ModuleScript vào container ReplicatedStorage và đổi tên thành StatefulObjectController.

    Cửa sổ Explorer hiển thị module StatefulObjectController trong container ReplicatedStorage.
  2. Dán đoạn mã sau vào trong module:

    StatefulObjectController

    local TweenService = game:GetService("TweenService")
    local StatefulObjectController = {}
    StatefulObjectController.__index = StatefulObjectController
    export type StateName = string
    export type State = {
    transition: TweenInfo,
    properties: { [string]: any },
    }
    function StatefulObjectController.hydrate(props: {
    object: Instance,
    states: { [StateName]: State },
    initialStateName: StateName
    })
    local object, states, initialStateName = props.object, props.states, props.initialStateName
    local self = setmetatable({
    states = states,
    currentStateName = initialStateName,
    tweens = {},
    }, StatefulObjectController)
    -- Tạo các tween để tái sử dụng nhằm tránh việc tạo mới các tween mỗi khi trạng thái thay đổi
    for stateName, state in states do
    self.tweens[stateName] = TweenService:Create(object, state.transition, state.properties)
    end
    self:setState(self.currentStateName)
    return self
    end
    function StatefulObjectController:setState(stateName: StateName)
    local stateTween: Tween = self.tweens[stateName]
    if not stateTween then
    warn(string.format("Đã cố gắng đặt %s thành trạng thái không xác định '%s'", self.object:GetFullName(), stateName))
    return
    end
    self.currentStateName = stateName
    -- Đảm bảo rằng không có tween khác đang xung đột
    for _, tween in self.tweens do
    tween:Cancel()
    end
    stateTween:Play()
    end
    return StatefulObjectController
    DòngMục đích
    610Xác định và xuất khẩu các kiểu Luau để cải thiện autocomplete và linting khi sử dụng module này.
    1233Hàm được sử dụng để khởi tạo và gán hành vi cho một đối tượng UI có trạng thái, chấp nhận một GuiObject làm object, một bảng các trạng thái và dữ liệu TweenInfo tương ứng của chúng, và một tên trạng thái ban đầu. Bên trong hàm này, các dòng 2628 xây dựng Tweens cho mỗi trạng thái, và dòng 30 gọi hàm setState() của module để đặt đối tượng vào trạng thái ban đầu.
    3550Hàm được sử dụng để thiết lập/thay đổi trạng thái của một đối tượng có trạng thái. Trong dòng 42, currentStateName của đối tượng được đặt thành trạng thái đang được thiết lập, các dòng 4547 hủy bỏ bất kỳ tween nào đang chạy để ngăn xung đột, và dòng 49 thực thi tween của trạng thái.

Điều khiển thanh trượt

Một module bổ sung khởi tạo và điều khiển hai thanh trượt âm lượng. Nó cũng cho phép bạn kết nối một hàm callback với mỗi thanh trượt để phát hiện sự tương tác của người chơi với thanh trượt và áp dụng các thay đổi mong muốn trong trải nghiệm.

  1. Chèn một ModuleScript vào container ReplicatedStorage và đổi tên thành SliderController.

    Cửa sổ Explorer hiển thị module SliderController trong container ReplicatedStorage.
  2. Dán đoạn mã sau vào trong module:

    SliderController

    local SliderController = {}
    SliderController.__index = SliderController
    export type Value = number
    export type OnChanged = (Value) -> ()
    function SliderController.hydrate(props: {
    object: Instance,
    onChanged: OnChanged,
    initialValue: Value?
    })
    local object, onChanged, initialValue = props.object, props.onChanged, props.initialValue
    local handle = object:FindFirstChild("Handle", true)
    if not handle then
    warn(string.format("Đã cố gắng khôi phục thanh trượt %s nhưng không tìm thấy Handle", object:GetFullName()))
    end
    local innerFill = object:FindFirstChild("InnerFill", true)
    if not innerFill then
    warn(string.format("Đã cố gắng khôi phục thanh trượt %s nhưng không tìm thấy InnerFill", object:GetFullName()))
    end
    local dragDetector = handle:FindFirstChildWhichIsA("UIDragDetector")
    if not dragDetector then
    warn(string.format("Đã cố gắng khôi phục thanh trượt %s nhưng không tìm thấy UIDragDetector", object:GetFullName()))
    end
    local self = setmetatable({
    handle = handle,
    innerFill = innerFill,
    dragDetector = dragDetector,
    value = initialValue or 0.5,
    onChanged = onChanged,
    }, SliderController)
    -- Đặt giá trị ban đầu
    self:setValue(self.value)
    -- Kết nối detector với sự thao tác của người chơi
    self.dragConnection = dragDetector.DragContinue:Connect(function()
    self:setValue(handle.Position.X.Scale)
    end)
    return self
    end
    function SliderController:setValue(value: Value)
    local clampedValue = math.clamp(value, 0, 1)
    self.value = clampedValue
    -- Cập nhật vị trí tay cầm và kích thước khung bên trong để khớp
    self.handle.Position = UDim2.fromScale(clampedValue, 0.5)
    self.innerFill.Size = UDim2.fromScale(clampedValue, 1)
    -- Chạy hàm callback của người dùng với giá trị mới nhất
    local changeSuccess, changeResult = pcall(self.onChanged, clampedValue)
    if not changeSuccess then
    warn("Lỗi trong hàm callback thanh trượt:", changeResult)
    end
    end
    return SliderController
    DòngMục đích
    746Hàm được sử dụng để khởi tạo và gán hành vi cho một phần tử thanh trượt, chấp nhận Frame của thanh trượt làm object, một hàm callback onChanged để xử lý các thay đổi của thanh trượt, và một giá trị ban đầu cho vị trí tay cầm của thanh trượt. Bên trong hàm, các dòng 1427 xác nhận rằng các phần tử tay cầm, lấp đầy bên trong, và các phần tử UIDragDetector tồn tại. Dòng 38 gọi hàm setValue() của module và các dòng 4143 kết nối sự kiện DragContinue của detector với hàm setValue() của module (xem dòng tiếp theo để biết chi tiết).
    4861Hàm được sử dụng để thiết lập giá trị của thanh trượt. Bên trong hàm, các dòng 5354 đảm bảo vị trí tay cầm và kích thước khung lấp đầy bên trong được đồng bộ, và dòng 57 chuyển giá trị đã thay đổi đến hàm callback để bạn có thể sử dụng giá trị khi cần thiết.

Tạo script cài đặt

Với nút cài đặtmenu cài đặt đã hoàn thiện, bạn có thể kết nối mọi thứ với nhau bằng một script duy nhất sử dụng các module điều khiển.

  1. Chèn một LocalScript mới vào HUDContainer và đổi tên thành SettingsScript để mô tả mục đích của nó. Lưu ý rằng script này nên ở cùng cấp (cùng nhánh) với SettingsMenuSettingsButton, các đối tượng UI cấp cao mà nó sẽ quản lý.

    Cửa sổ Explorer hiển thị script SettingsScript bên trong container HUDContainer.
  2. Dán đoạn mã sau vào trong script:

    SettingsScript

    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local SoundService = game:GetService("SoundService")
    local SliderController = require(ReplicatedStorage.SliderController)
    local StatefulObjectController = require(ReplicatedStorage.StatefulObjectController)
    local HUDContainer = script.Parent
    -- Khởi tạo nút cài đặt
    local settingsButton = StatefulObjectController.hydrate({
    object = HUDContainer:FindFirstChild("SettingsButton"),
    states = {
    menuOpen = {
    transition = TweenInfo.new(0.5, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out),
    properties = {
    Rotation = 45,
    },
    },
    menuClosed = {
    transition = TweenInfo.new(0.5, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out),
    properties = {
    Rotation = 0,
    },
    },
    },
    initialStateName = "menuClosed"
    })
    -- Khởi tạo khung menu cài đặt
    local settingsMenu = StatefulObjectController.hydrate({
    object = HUDContainer:FindFirstChild("SettingsMenu"),
    states = {
    menuOpen = {
    transition = TweenInfo.new(0.5, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out),
    properties = {
    Position = UDim2.fromScale(0.5, 0.5),
    Visible = true,
    },
    },
    menuClosed = {
    transition = TweenInfo.new(0),
    properties = {
    Position = UDim2.fromScale(0.5, 0.4),
    Visible = false,
    },
    },
    },
    initialStateName = "menuClosed"
    })
    -- Khởi tạo thanh trượt âm lượng hiệu ứng
    local effectsAudio = SoundService:FindFirstChild("Effects")
    local effectsVolumeSlider = SliderController.hydrate({
    object = HUDContainer:FindFirstChild("EffectsVolumeSlider", true),
    initialValue = effectsAudio and effectsAudio.Volume or 0.5,
    onChanged = function(value: SliderController.Value)
    if effectsAudio then
    effectsAudio.Volume = value
    end
    end,
    })
    -- Khởi tạo thanh trượt âm lượng nền
    local backgroundAudio = SoundService:FindFirstChild("Background")
    local backgroundVolumeSlider = SliderController.hydrate({
    object = HUDContainer:FindFirstChild("BackgroundVolumeSlider", true),
    initialValue = backgroundAudio and backgroundAudio.Volume or 0.5,
    onChanged = function(value: SliderController.Value)
    if backgroundAudio then
    backgroundAudio.Volume = value
    end
    end,
    })
    -- Kết nối các nút với sự tương tác của người chơi
    HUDContainer:FindFirstChild("SettingsButton").Activated:Connect(function()
    local targetState = if settingsButton.currentStateName == "menuClosed"
    then "menuOpen"
    else "menuClosed"
    settingsButton:setState(targetState)
    settingsMenu:setState(targetState)
    end)
    HUDContainer:FindFirstChild("CloseButton", true).Activated:Connect(function()
    settingsButton:setState("menuClosed")
    settingsMenu:setState("menuClosed")
    end)
  3. Tham khảo các phần sau để tìm hiểu cách script này sử dụng các module điều khiển.

    Các dòng 10-27 khởi tạo và gán hành vi cho nút cài đặt như sau:

    DòngMục đích
    1011Một tham chiếu cục bộ settingsButton được khai báo và khôi phục bằng hàm StatefulObjectController.hydrate(), và nút SettingsButton bên trong HUDContainer được tham chiếu là đối tượng để khôi phục.
    1225Một bảng states được truyền đi với hai trạng thái duy nhất, menuOpenmenuClosed. Mỗi trạng thái chứa một chuyển tiếp để khai báo (thông qua một TweenInfo) cách mà trạng thái cụ thể sẽ đạt được các thuộc tính mục tiêu được xác định trong bảng properties. Trong trường hợp này, menuOpen khai báo một sự thay đổi trạng thái đến 45° cho Rotation của nút với một tween Exponential trong nửa giây, trong khi menuClosed khôi phục nút về xoay mặc định của nó là 0.
    26Trạng thái ban đầu của nút được đặt thành menuClosed (điều này có thể được đặt thành bất kỳ tên trạng thái nào trong bảng states).

    Phía dưới trong script (các dòng 76-86), các nút được kết nối với sự tương tác của người chơi để kích hoạt các thay đổi trạng thái UI:

    DòngMục đích
    7682SettingsButton được kết nối với sự kiện Activated của lớp GuiButton để gọi một hàm ẩn danh. Bên trong hàm ẩn danh, các dòng 7779 chuyển đổi biến targetState giữa menuOpenmenuClosed. Dòng 80 sau đó gọi setState() để đặt trạng thái của nút thành targetState và dòng 81 thực hiện điều tương tự cho SettingsMenu để nó bật hoặc tắt với việc kích hoạt SettingsButton.
    8386CloseButton được kết nối với sự kiện Activated để gọi một hàm ẩn danh, mà thiết lập trạng thái của cả SettingsButtonSettingsMenu thành menuClosed.

    Các dòng 30-49 khởi tạo và gán hành vi cho menu cài đặt như sau:

    DòngMục đích
    3031Một tham chiếu cục bộ settingsMenu được khai báo và khôi phục bằng hàm StatefulObjectController.hydrate() và khung SettingsMenu bên trong HUDContainer được tham chiếu là đối tượng để khôi phục.
    3246Tương tự như nút cài đặt, một bảng states được truyền đi với hai trạng thái duy nhất, menuOpenmenuClosed. Ở đây, menuOpen khai báo một sự thay đổi trạng thái đến UDim2.fromScale(0.5, 0.5) cho Position của khung với một tween Bounce trong nửa giây, cũng như một trạng thái Visible của true. Ngược lại, menuClosed khai báo một thay đổi trạng thái vị trí đến UDim2.fromScale(0.5, 0.4)Visible thành false, nhưng TweenInfo với thời gian 0 trong dòng 41 thực tế làm cho sự thay đổi trạng thái xảy ra ngay lập tức.
    48Trạng thái ban đầu của khung được đặt thành menuClosed.

    Phía dưới trong script (các dòng 76-86), menu cài đặt được liên kết với sự tương tác của người chơi:

    DòngMục đích
    81Thiết lập trạng thái targetState cho SettingsMenu đồng bộ với việc kích hoạt SettingsButton.
    85Đặt trạng thái của SettingsMenu thành menuClosed khi CloseButton được kích hoạt.

    Các dòng 51-73 khởi tạo và gán hành vi cho EffectsVolumeSliderBackgroundVolumeSlider như sau:

    DòngMục đích
    52Thiết lập một tham chiếu cục bộ đến SoundGroup Effects bên trong SoundService. Một SoundGroup cho phép bạn liên kết nhiều Sounds và điều khiển âm lượng của mọi âm thanh trong nhóm thông qua thuộc tính Volume của nhóm.
    5354Một tham chiếu cục bộ effectsVolumeSlider được khai báo và khôi phục bằng hàm SliderController.hydrate() và khung EffectsVolumeSlider bên trong HUDContainer ⟩ SettingsMenu được tham chiếu là đối tượng để khôi phục. Lưu ý rằng tham số thứ hai của true cho FindFirstChild() cho biết phương thức tìm kiếm đệ quy xuống nhánh HUDContainer để tìm EffectsVolumeSlider.
    55Giá trị ban đầu của thanh trượt được đặt thành âm lượng hiện tại của nhóm âm thanh Effects, hoặc 0.5 làm giá trị dự phòng.
    5660Xác lập hàm callback để áp dụng các thay đổi giá trị thanh trượt cho âm lượng của nhóm âm thanh Effects.
    6473Về cơ bản giống như các dòng 52-61, nhưng là để khôi phục khung BackgroundVolumeSlider bên trong HUDContainer ⟩ SettingsMenu và áp dụng các thay đổi giá trị thanh trượt cho âm lượng của nhóm âm thanh Background.

Với SettingsScript đã được đặt, trải nghiệm bây giờ cung cấp một ví dụ UI tương tác hoàn toàn hoạt động liên kết một tập hợp các đối tượng UI có liên quan với sự tương tác của người chơi.

©2026 Roblox Corporation. Roblox, logo Roblox và Powering Imagination là các nhãn hiệu đã đăng ký và chưa đăng ký của chúng tôi tại Hoa Kỳ và các quốc gia khác.