Thư viện Điều khiển Nhân vật

*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.

Thư viện Điều khiển Nhân vật (CCL) là một khung mô-đun để xây dựng chuyển động và hành vi của nhân vật thông qua các thuộc tính và kịch bản Luau. Kiến trúc này thay thế các máy trạng thái cứng nhắc Humanoid bằng một hệ thống linh hoạt, có thể mở rộng cho các cơ chế của nhân vật.

Khả năng

Khả năng đánh giá những gì một nhân vật có thể làm, chẳng hạn như khả năng chạy, nhảy, leo trèo và bơi lội. Thay vì dựa vào một tập hợp cố định các trạng thái nhân vật được định nghĩa bởi engine như trong Enum.HumanoidStateType, các khả năng CCL xác định động một cách linh hoạt những gì một nhân vật có thể làm và cách nó nên phản ứng với đầu vào của người chơi.

Cấu trúc, một khả năng là một bảng Luau tự chứa chủ yếu xác định các thông tin sau:

Các trường trong bảngMục đích
NameTên được phân bổ một bit nhãn, để điều kiện và xung đột có thể tham chiếu đến khả năng. Nhiều định nghĩa khả năng có thể sử dụng cùng một tên. Tên ModuleScript xác định khóa cấu hình duy nhất.
Labels, TimedLabelsCác bit được đặt tên trong một mặt nạ 64-bit chia sẻ, hoạt động như một bus phối hợp giữa các khả năng; xem nhãn.
StartsWhen, RunsWhileCác điều kiện xác định khi nào bắt đầu khả năng và khi nào giữ cho nó hoạt động, tương ứng; xem điều kiện.
Blocks, Stops, Suspends, ExclusiveGroupCách xử lý xung đột giữa các khả năng không thể hoạt động cùng lúc.
InputĐầu vào kích hoạt khả năng. CCL tiêm nó vào StartsWhen và, khi bạn bỏ qua RunsWhile, sử dụng nó như điều kiện tiếp tục mặc định; xem đầu vào.
Config, StateCác giá trị cấu hình mặc định và trạng thái được sao chép cho mỗi đăng ký khả năng. Các callback đọc cấu hình từ abilityCtx.Config và đọc hoặc ghi trạng thái được sao chép thông qua abilityCtx.State.
OnSetup, OnStart, OnStop, OnUpdate, OnTeardownCác callback vòng đời nơi hành vi thực tế của khả năng được lập trình; xem callback.

Nhãn

Một nhãn là một bit được đặt tên trong một mặt nạ 64-bit chia sẻ, hoạt động như một bus phối hợp giữa các khả năng. Về cơ bản:

  • Một khả năng đang hoạt động phát sóng các Labels và TimedLabels của nó đến mặt nạ thế giới.
  • Các điều kiện khả năng (StartsWhen, RunsWhile) kiểm tra mặt nạ thế giới và phản ứng.
  • Các xung đột khả năng xác định các khả năng khác nào bị chặn, dừng lại hoặc tạm dừng khi kích hoạt.

Trong thiết lập sau, nhãn "CanFallDown" được phát sóng đến mặt nạ thế giới khi Running đang hoạt động. Khả năng FallingDown với điều kiện StartsWhen = All( "CanFallDown", "Stunned" ) tự động trở thành một ứng cử viên, nhưng "Stunned" cũng phải được phát sóng đến mặt nạ thế giới trước khi FallingDown xảy ra.

Khả năng Chạy
local AvatarAbilities = require("@rbx/AvatarAbilities")
local Identifiers = AvatarAbilities.Identifiers
local Ability = Identifiers.Ability
local Rule = AvatarAbilities.Rule
local Sensor = Identifiers.Sensor
local All, Not = Rule.All, Rule.Not
local Running: AvatarAbilities.AbilityDefinition = {
Name = Ability.Running,
Labels = { "CanFallDown" }, -- Nhãn phát sóng khi khả năng đang hoạt động
StartsWhen = Sensor.Ground,
RunsWhile = Sensor.Ground,
}
Khả năng Ngã
local AvatarAbilities = require("@rbx/AvatarAbilities")
local Identifiers = AvatarAbilities.Identifiers
local Ability = Identifiers.Ability
local Rule = AvatarAbilities.Rule
local Sensor = Identifiers.Sensor
local All, Not = Rule.All, Rule.Not
local FallingDown: AvatarAbilities.AbilityDefinition = {
Name = Ability.FallingDown,
StartsWhen = All( "CanFallDown", "Stunned" ), -- Nhãn cần thiết để khả năng bắt đầu
Blocks = { Ability.Running }
}

Các nhãn cũng có thể được phát sóng hoặc tiêu thụ theo cách có thời gian bằng cách sử dụng từ điển TimedLabels.

KhóaMô tả
TimedLabels.OnStartTừ điển chứa các nhãn (khóa) và thời gian liên quan. Nhãn được phát sóng khi khả năng bắt đầu và tự động hết hạn khi thời gian của chúng kết thúc. Ví dụ, OnStart = { Dashing = 1 } phát sóng nhãn Dashing trong 1 giây khi khả năng bắt đầu.
TimedLabels.OnStopTừ điển chứa các nhãn (khóa) và thời gian liên quan. Nhãn được phát sóng khi khả năng dừng lại và tự động hết hạn khi thời gian của chúng kết thúc. Ví dụ, OnStop = { DashCooldown = 2 } phát sóng nhãn DashCooldown trong 2 giây khi khả năng dừng lại.
TimedLabels.ConsumesDanh sách các nhãn để loại bỏ (tiêu thụ) khi khả năng kích hoạt. Ví dụ, nếu một trò chơi chiến đấu cho phép người chơi phản công sau khi chặn một đòn tấn công của đối thủ, khả năng CounterAttack có thể chứa cả StartsWhen = "AfterBlock" và TimedLabels = { Consumes = { "AfterBlock" } } để ngăn chặn việc kích hoạt lại khả năng CounterAttack.
Nhãn Có Thời Gian
local AvatarAbilities = require("@rbx/AvatarAbilities")
local Identifiers = AvatarAbilities.Identifiers
local Rule = AvatarAbilities.Rule
local Sensor = Identifiers.Sensor
local All, Not = Rule.All, Rule.Not
local Dash: AvatarAbilities.AbilityDefinition = {
Name = "Dash",
StartsWhen = All( Sensor.Ground, Not("DashCooldown") ),
RunsWhile = "Dashing",
TimedLabels = {
OnStart = { Dashing = 1 },
OnStop = { DashCooldown = 2 },
},
}

Điều kiện

Một điều kiện là một hoặc nhiều nhãn, cảm biến, hoặc một tham chiếu đầu vào, được sử dụng bởi StartsWhen và RunsWhile. Các điều kiện biên dịch thành các phép toán bitmask tại thời gian chạy và đánh giá là toán học số nguyên — không có việc đi bộ bảng và không có so sánh chuỗi.

Mục tiêuCú phápVí dụ
Một điều kiện bắt buộc.StartsWhen = Sensor.Ground
Logic AND cho khi tất cả các nhãn tồn tại trong mặt nạ thế giới và tất cả các cảm biến đang hoạt động.All()StartsWhen = All( "CanFallDown", "Stunned" )
Logic OR cho khi bất kỳ nhãn nào tồn tại trong mặt nạ thế giới hoặc bất kỳ cảm biến nào đang hoạt động.Any()StartsWhen = Any( "WallClimbing", "Climbing" )
Phủ định sao cho các nhãn không thể tồn tại trong mặt nạ thế giới và các cảm biến không thể hoạt động.Not()RunsWhile = Not("Stunned")

Đánh giá điều kiện có thể được kết hợp để có logic phức tạp hơn, chẳng hạn như chuỗi All() cộng với Not() để chỉ ra rằng một cảm biến phải hoạt động trong khi một nhãn phải không tồn tại:

local AvatarAbilities = require("@rbx/AvatarAbilities")
local Identifiers = AvatarAbilities.Identifiers
local Rule = AvatarAbilities.Rule
local Sensor = Identifiers.Sensor
local All, Not = Rule.All, Rule.Not
local Dive: AvatarAbilities.AbilityDefinition = {
Name = "Dive",
StartsWhen = All( Sensor.WaterSurface, Not("Recovering") ),
}

Xung đột

Một số khả năng không thể hoạt động khi một khả năng khác đang hoạt động; ví dụ, nhân vật không thể nhảy khi đang bơi, và họ không thể chạy khi đang ngã. Engine giải quyết những xung đột này một cách tuyên bố bên trong định nghĩa của một khả năng:

Khóa Xung độtMục đích
BlocksKhi khả năng sở hữu đang hoạt động, các khả năng khác được liệt kê không thể bắt đầu. Ví dụ, một khả năng ScopeAim có thể chứa Blocks = { Ability.Running, Ability.Jumping } để ngăn chặn nhân vật chạy hoặc nhảy trong khi đang nhắm mục tiêu cẩn thận qua ống ngắm của vũ khí.
StopsKhi khả năng sở hữu bắt đầu, các khả năng khác được liệt kê buộc dừng và phải kích hoạt lại. Ví dụ, một khả năng Hover có thể chứa Stops = { Ability.Running } để ngay lập tức dừng chuyển động chạy của nhân vật khi họ bắt đầu lơ lửng.
SuspendsKhi khả năng sở hữu bắt đầu, các khả năng khác được liệt kê tạm dừng và sau đó tự động tiếp tục khi khả năng sở hữu dừng lại. Ví dụ, một khả năng chạy tùy chỉnh có thể chứa Suspends = { Ability.Running } để chạy 🄐 tạm dừng khi bắt đầu chạy, 🄑 bị chặn giữa chừng, và 🄒 tiếp tục khi dừng chạy.

Một khóa xung đột độc đáo khác là ExclusiveGroup mà đặt nhiều khả năng vào một nhóm, mỗi khả năng có một giá trị Priority. Chỉ một khả năng mỗi nhóm có thể hoạt động và ưu tiên cao hơn sẽ thắng. Tuy nhiên, nếu một đối thủ tuyên bố Stops nhắm vào tên/nhãn của người giữ, nó sẽ thắng bất kể ưu tiên.

Trong thiết lập sau, ba khả năng (Sprinting, Crouching, Stagger) được thêm vào một nhóm độc quyền Locomotion. Sprinting có ưu tiên cao nhất (200) nên nó thắng Crouching (100) và hai khả năng này không bao giờ hoạt động cùng lúc. Tuy nhiên, Stagger buộc dừng chạy (Stops = { Ability.Sprinting }), vì vậy nó có thể ngắt quãng và vượt qua Sprinting mặc dù ưu tiên của nó (150) thấp hơn.

local AvatarAbilities = require("@rbx/AvatarAbilities")
local Identifiers = AvatarAbilities.Identifiers
local Ability = Identifiers.Ability
local Rule = AvatarAbilities.Rule
local Sensor = Identifiers.Sensor
local All, Not = Rule.All, Rule.Not
local Sprinting: AvatarAbilities.AbilityDefinition = {
Name = Ability.Sprinting,
ExclusiveGroup = { Name = "Locomotion", Priority = 200 },
}
local Crouching: AvatarAbilities.AbilityDefinition = {
Name = Ability.Crouching,
ExclusiveGroup = { Name = "Locomotion", Priority = 100 },
}
-- Một khả năng có ưu tiên thấp hơn có thể ghi đè một khả năng có ưu tiên cao hơn bằng cách dừng nó
local Stagger: AvatarAbilities.AbilityDefinition = {
Name = "Stagger",
ExclusiveGroup = { Name = "Locomotion", Priority = 150 },
Stops = { Ability.Sprinting },
}

Đầu vào

Định nghĩa Input của một khả năng xác định đầu vào được sử dụng để cố gắng kích hoạt khả năng. Nó nhận các cặp khóa-giá trị cấu hình hành vi đầu vào, khe hành động và các biểu tượng nút chạm tùy chọn.

local AvatarAbilities = require("@rbx/AvatarAbilities")
local Identifiers = AvatarAbilities.Identifiers
local Rule = AvatarAbilities.Rule
local Sensor = Identifiers.Sensor
local All, Not = Rule.All, Rule.Not
local Dash: AvatarAbilities.AbilityDefinition = {
Name = "Dash",
Input = { InputName = "Dash", Mode = "Press", ActionSlot = 5 }
}
  • InputName là một tên logic, không phải một khóa. CCL tạo ra một cảm biến đầu vào và luôn thêm nó vào StartsWhen. Đừng thêm Rule.Input vào StartsWhen tự mình.

  • Mode xác định cách mà đầu vào này sẽ được diễn giải:

    Chế độHành viTrường hợp sử dụng
    PressKích hoạt khả năng được cố gắng khi đầu vào được nhấn. Tự động tiêm vào điều kiện StartsWhen.Các hành động rời rạc như dash, tấn công và ném.
    HoldKhả năng chạy trong khi đầu vào được giữ; thả ra dừng nó khi cảm biến đầu vào được tạo là điều kiện RunsWhile.Các hành động kéo dài như chạy, nhắm và chặn.
    ToggleMỗi lần nhấn sẽ chuyển đổi khả năng bật hoặc tắt khi cảm biến đầu vào được tạo là điều kiện RunsWhile.Các tư thế hoặc chuyển động có thể bật/tắt như cúi hoặc lơ lửng.
    RepeatGiống như Hold, nhưng kích hoạt lại mỗi chu kỳ.Các hành động tự dừng và có thể kích hoạt lại trong khi giữ.
  • ActionSlot xác định một khe hành động liên kết với một danh sách InputActions và InputBindings trong Hệ thống Hành động Đầu vào.

    Một số liên kết đầu vào khe hành động được định nghĩa trước bởi Roblox và, trong tương lai, Trình quản lý hành động đầu vào sẽ cho phép bạn cấu hình lại các liên kết đầu vào mặc định cho các khe hành động theo ý muốn. Đặt ActionSlot thành 0 sẽ chọn khe trống tiếp theo có sẵn. Trên các thiết bị di động, các khe 1-7 sẽ được điền vào các nút trên màn hình (xem sơ đồ bên dưới).

    KheBàn phím & ChuộtGamepadCảm ứngGán mặc định
    1SpaceButtonA①Nhảy
    2LeftShiftButtonL1②Chạy nhanh
    3LeftControlButtonB③Ngồi xổm
    4RButtonX④
    5MouseLeftButtonButtonR2⑤
    6QButtonY⑥
    7XButtonR1⑦
    8CButtonL2
    9FDPadLeft
    10GDPadRight
    11VDPadDown
  • CustomIcon, CustomIconActive, và CustomIconInvalid xác định các ID tài sản Roblox cho nút chạm khi khả năng đang ở trạng thái nhàn rỗi, hoạt động hoặc không khả dụng, tương ứng.

Khi bạn bỏ qua RunsWhile, CCL sử dụng cảm biến đầu vào được tạo làm điều kiện tiếp tục. Khi bạn định nghĩa RunsWhile, nó thay thế điều kiện mặc định đó. Đối với một khả năng Hold hoặc Toggle phải dừng khi đầu vào của nó trở nên không hoạt động, hãy bao gồm tín hiệu Rule.Input trực tiếp trong điều kiện tùy chỉnh. Rule.Input là một giá trị, không phải một hàm:

local AvatarAbilities = require("@rbx/AvatarAbilities")
local Rule = AvatarAbilities.Rule
local Sensor = AvatarAbilities.Identifiers.Sensor
local All, Input, Not = Rule.All, Rule.Input, Rule.Not
local Glide: AvatarAbilities.AbilityDefinition = {
Name = "Glide",
Input = { InputName = "Glide", Mode = "Hold", ActionSlot = 6 },
StartsWhen = Not(Sensor.Ground),
RunsWhile = All(Not(Sensor.Ground), Input),
}

Cảm biến

Một cảm biến là một giá trị được đặt tên về thế giới mà engine đọc cho bạn. Bạn thường sẽ đọc các cảm biến thay vì viết chúng. Để tiện lợi, một số cảm biến đã được đăng ký trước:

Cảm biếnMô tả
Sensor.GroundĐứng trên một bề mặt
Sensor.IsMovingĐầu vào chuyển động đang được áp dụng
Sensor.MoveInputVéc tơ chuyển động tự nó
Sensor.CeilingCó gì đó ngay trên đầu
Sensor.ClimbMột bề mặt có thể leo trèo nằm trong phạm vi
Sensor.Water / Sensor.WaterSurfaceTrong nước / ở bề mặt
Sensor.SitNgồi
Sensor.TippedNgã xuống
Sensor.ToolĐang cầm một Tool
Sensor.LookDirectionInputHướng nhìn được yêu cầu
Sensor.RotateToLookDirectionInputLiệu nhân vật có nên xoay theo hướng nhìn được yêu cầu hay không

Callback

Các hàm callback khả năng cho phép bạn lập trình hành vi cụ thể:

Mặc dù bạn đăng ký các khả năng tùy chỉnh trên máy chủ, các callback của chúng chạy trong cả mô phỏng khách hàng dự đoán và mô phỏng máy chủ có thẩm quyền. Giữ hành vi callback có tính xác định để cả hai mô phỏng sản xuất cùng một kết quả.

CallbackChạyTrường hợp sử dụng
OnSetup(managerCtx, abilityCtx)Một lần, khi khả năng được đăng ký.Lưu trữ tham chiếu, khởi tạo trạng thái, v.v.
OnStart(managerCtx, abilityCtx, hadLabel)Mỗi lần khả năng được kích hoạt.Áp dụng một hiệu ứng như một xung lực. Hàm hadLabel() báo cáo liệu một nhãn cụ thể có hiện diện khi kích hoạt bắt đầu, trước khi giải quyết xung đột.
OnUpdate(managerCtx, abilityCtx)Mỗi khung hoạt động.Công việc liên tục như bộ đếm thời gian hoặc lực theo khung.
OnStop(managerCtx, abilityCtx)Mỗi lần dừng, tự nguyện hoặc bị ép.Hoàn tác những gì OnStart() đã làm.
OnTeardown(managerCtx, abilityCtx)Khi khả năng bị xóa.Ngắt kết nối các kết nối, hủy diệt các thực thể, v.v.

Tham số đầu tiên của mỗi hàm callback, managerCtx, là một đối tượng ManagerContext với các thuộc tính chia sẻ của nhân vật và quản lý, bao gồm:

  • managerCtx.AbilityOwner — Nhân vật Model mà managerCtx.AbilityOwner.PrimaryPart là phần gốc.
  • managerCtx.AbilityManager — Một cái nhìn cắt giảm của quản lý để một khả năng có thể thêm, xóa và truy vấn các khả năng từ bên trong các callback của nó.
  • managerCtx.BodyParts — Các bộ phận cơ thể của nhân vật, với các trợ giúp để bật và tắt va chạm cho từng chi.
  • managerCtx.ControllerManager — ControllerManager của nhân vật để kiểm soát vật lý. Nó có thể là nil khi không có khả năng đã đăng ký nào yêu cầu vật lý.
  • managerCtx.RootCFrame — CFrame của phần gốc, được chụp một lần tại đầu khung để các callback không phải tự đi và lấy nó.
  • managerCtx.RootLookVector — Hướng mà phần gốc của nhân vật đang đối diện.
  • managerCtx.RootUpVectorY — Thành phần Y của vector lên của phần gốc.
  • managerCtx.TaskSynchronize() — Đồng bộ hóa một callback trước khi truy cập DataModel khi hỗ trợ callback song song được bật. Hiện tại, OnUpdate không chạy trong ngữ cảnh song song, vì vậy hàm này không có tác dụng. Hỗ trợ Luau song song đầy đủ được lên kế hoạch cho một bản cập nhật trong tương lai.

Tham số thứ hai, abilityCtx, là một đối tượng AbilityContext với các bảng do engine quản lý cho đăng ký khả năng hiện tại:

  • abilityCtx.Config — Các giá trị cấu hình chỉ đọc cho đăng ký khả năng này.
  • abilityCtx.State — Trạng thái có thể thay đổi được sao chép qua DataModel. Quyền kiểm soát máy chủ khôi phục các giá trị này trong quá trình quay ngược và mô phỏng lại.
  • abilityCtx.Local — Trạng thái tạm thời có thể thay đổi không được sao chép hoặc tham gia vào việc quay ngược.

Lưu trữ dữ liệu callback tùy chỉnh trong abilityCtx.State hoặc abilityCtx.Local. Việc ghi các trường tùy chỉnh trực tiếp vào abilityCtx là một lỗ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.