角色控制器库

*此内容使用人工智能(Beta)翻译,可能包含错误。若要查看英文页面,请点按 此处

角色控制器库 (CCL) 是一个模块化框架,通过属性和 Luau 脚本构建角色移动和行为。该架构用灵活、可扩展的角色机制系统替代了僵化的 Humanoid 状态机。

能力

能力评估角色可以做什么,例如跑步、跳跃、攀爬和游泳的能力。CCL 能力动态确定角色可以做什么以及如何响应玩家输入,而不是依赖于固定的引擎定义角色状态集,如 Enum.HumanoidStateType 中的状态。

从结构上讲,能力是一个自包含的 Luau 表,主要指定以下内容:

表字段目的
Name分配给 标签 位的名称,以便 条件冲突 可以引用该能力。多个能力定义可以使用相同的名称。ModuleScript 名称决定唯一的配置键。
Labels, TimedLabels共享 64 位掩码中的命名位,作为能力之间的协调总线;见 标签
StartsWhen, RunsWhile定义何时启动能力和何时保持其运行的条件;见 条件
Blocks, Stops, Suspends, ExclusiveGroup如何处理不能同时处于活动状态的能力之间的 冲突
Input触发能力的输入。CCL 将其注入到 StartsWhen 中,并在省略 RunsWhile 时,将其用作默认的继续条件;见 输入
Config, State每个能力注册的默认配置值和复制状态。回调从 abilityCtx.Config 读取配置,并通过 abilityCtx.State 读取或写入复制状态。
OnSetup, OnStart, OnStop, OnUpdate, OnTeardown生命周期回调,能力的实际行为在此处编写;见 回调

标签

标签 是共享 64 位掩码中的命名位,作为能力之间的协调总线。基本上:

  • 活动能力 广播LabelsTimedLabels 到世界掩码。
  • 能力 条件 (StartsWhen, RunsWhile) 测试 世界掩码并做出反应。
  • 能力 冲突 定义在激活时被阻止、停止或暂停的 其他 能力。

在以下设置中,当 Running 处于活动状态时,"CanFallDown" 标签被广播到世界掩码。具有 条件 StartsWhen = All( "CanFallDown", "Stunned" )FallingDown 能力自动成为候选者,但 "Stunned" 也必须在 FallingDown 发生之前广播到世界掩码。

Running Ability
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" }, -- 能力处于活动状态时广播的标签
StartsWhen = Sensor.Ground,
RunsWhile = Sensor.Ground,
}
FallingDown Ability
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" ), -- 启动能力所需的标签
Blocks = { Ability.Running }
}

标签也可以使用 TimedLabels 字典以 定时 方式广播或消耗。

描述
TimedLabels.OnStart包含标签(键)和相关持续时间的字典。当能力启动时,标签被广播,并在其持续时间结束时自动过期。例如,OnStart = { Dashing = 1 } 在能力启动时广播 Dashing 标签,持续 1 秒。
TimedLabels.OnStop包含标签(键)和相关持续时间的字典。当能力停止时,标签被广播,并在其持续时间结束时自动过期。例如,OnStop = { DashCooldown = 2 } 在能力停止时广播 DashCooldown 标签,持续 2 秒。
TimedLabels.Consumes在能力激活时要移除(消耗)的标签列表。例如,如果一款格斗游戏允许玩家在阻挡对手攻击后进行反击,CounterAttack 能力可能包含 StartsWhen = "AfterBlock"TimedLabels = { Consumes = { "AfterBlock" } },以防止 CounterAttack 能力的双重触发。
Timed Labels
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 },
},
}

条件

条件 是一个或多个 标签传感器 或输入引用,用于 StartsWhenRunsWhile。条件在运行时编译为位掩码操作,评估是整数数学 — 没有表遍历和字符串比较。

目标语法示例
一个必需的条件。StartsWhen = Sensor.Ground
AND 逻辑,当 所有 标签存在于世界掩码中且 所有 传感器处于活动状态时。All()StartsWhen = All( "CanFallDown", "Stunned" )
OR 逻辑,当 任何 标签存在于世界掩码中或 任何 传感器处于活动状态时。Any()StartsWhen = Any( "WallClimbing", "Climbing" )
否定,使得标签 不能 存在于世界掩码中且传感器 不能 处于活动状态。Not()RunsWhile = Not("Stunned")

条件评估可以组合以实现更复杂的逻辑,例如 All() 链接加上 Not(),以指示传感器必须处于活动状态,而标签必须不存在:

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") ),
}

冲突

某些能力在另一种能力处于活动状态时无法激活;例如,角色在游泳时无法跳跃,在下落时无法奔跑。引擎在能力定义内部声明性地解决这些冲突:

冲突键目的
Blocks当拥有的能力处于活动状态时,列出的其他能力无法启动。例如,ScopeAim 能力可能包含 Blocks = { Ability.Running, Ability.Jumping },以防止角色在仔细瞄准武器的瞄准镜时奔跑或跳跃。
Stops当拥有的能力启动时,列出的其他能力 强制停止,并必须重新触发。例如,Hover 能力可能包含 Stops = { Ability.Running },以便在角色开始悬停时立即停止奔跑动作。
Suspends当拥有的能力启动时,列出的其他能力 暂停,然后在拥有的能力停止时 自动恢复。例如,自定义冲刺能力可能包含 Suspends = { Ability.Running },以便在冲刺开始时暂停奔跑 🄐,在冲刺中被阻止 🄑,并在冲刺停止时恢复 🄒。

另一个独特的冲突键是 ExclusiveGroup,它将多个能力放入一个组,每个组都有一个 Priority 值。每组中只能有一个能力处于活动状态,优先级高的胜出。然而,如果挑战者声明 Stops 目标为持有者的名称/标签,则无论优先级如何,它都将胜出。

在以下设置中,三个能力(SprintingCrouchingStagger)被添加到一个 Locomotion 独占组中。Sprinting 的优先级最高(200),因此它胜过 Crouching100),这两个能力不会同时运行。然而,Stagger 强制停止冲刺 (Stops = { Ability.Sprinting }),因此即使其优先级(150)较低,它也可以中断并超越 Sprinting

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 },
}
-- 低优先级的能力可以通过停止高优先级的能力来覆盖它
local Stagger: AvatarAbilities.AbilityDefinition = {
Name = "Stagger",
ExclusiveGroup = { Name = "Locomotion", Priority = 150 },
Stops = { Ability.Sprinting },
}

输入

能力的 Input 定义指定用于尝试激活能力的输入。它接受配置输入行为、动作槽和可选触摸按钮图标的键值对。

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 是一个逻辑名称,而不是一个键。CCL 生成一个输入传感器,并始终将其添加到 StartsWhen 中。不要自己将 Rule.Input 添加到 StartsWhen

  • Mode 定义此输入将如何被解释:

    模式行为用例
    Press当输入被按下时尝试激活能力。自动注入到 StartsWhen 条件中。离散动作,如冲刺、攻击和投掷。
    Hold当输入被按住时,能力运行;释放时停止,当生成的输入传感器是 RunsWhile 条件时。持续动作,如冲刺、瞄准和阻挡。
    Toggle每次按下切换能力的开或关,当生成的输入传感器是 RunsWhile 条件时。切换姿态或动作,如蹲下或悬浮。
    Repeat类似于 Hold,但每个周期重新触发。自我停止并可以在按住时重新触发的动作。
  • ActionSlot 定义一个 动作槽,与 输入动作系统 中的一系列 InputActionsInputBindings 相关联。

    几个动作槽输入绑定是由Roblox预定义的,未来的 输入动作管理器 将允许您根据需要重新配置动作槽的默认输入绑定。将 ActionSlot 设置为 0 将选择下一个可用的空槽。在移动设备上,槽 1-7 会填充到屏幕上的按钮(见下图)。

    键盘和鼠标游戏手柄触摸默认分配
    1SpaceButtonA跳跃
    2LeftShiftButtonL1冲刺
    3LeftControlButtonB蹲下
    4RButtonX
    5MouseLeftButtonButtonR2
    6QButtonY
    7XButtonR1
    8CButtonL2
    9FDPadLeft
    10GDPadRight
    11VDPadDown
  • CustomIconCustomIconActiveCustomIconInvalid 分别指定能力处于闲置、活动或不可用状态时的触摸按钮的 Roblox 资产 ID。

当您省略 RunsWhile 时,CCL 使用生成的输入传感器作为继续条件。当您定义 RunsWhile 时,它替换该默认值。对于必须在输入变为非活动时停止的 HoldToggle 能力,请直接在自定义条件中包含 Rule.Input 哨兵。Rule.Input 是一个值,而不是一个函数:

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),
}

传感器

传感器 是关于世界的命名值,引擎为您读取。您通常会读取传感器而不是写入它们。为了方便,预注册了几个传感器:

传感器描述
Sensor.Ground站在一个表面上
Sensor.IsMoving正在应用移动输入
Sensor.MoveInput移动向量本身
Sensor.Ceiling某物在正上方
Sensor.Climb可攀爬的表面在范围内
Sensor.Water / Sensor.WaterSurface在水中 / 在水面上
Sensor.Sit坐着
Sensor.Tipped翻倒了
Sensor.Tool持有一个 Tool
Sensor.LookDirectionInput命令的视线方向
Sensor.RotateToLookDirectionInput角色是否应该旋转到命令的视线方向

回调

能力 回调函数 让您编写特定行为:

尽管您在服务器上注册自定义能力,但它们的回调在预测的客户端仿真和权威的服务器仿真中都运行。保持回调行为的确定性,以便两个仿真产生相同的结果。

回调运行时机用例
OnSetup(managerCtx, abilityCtx)注册能力时运行一次。缓存引用,初始化状态等。
OnStart(managerCtx, abilityCtx, hadLabel)每次激活能力时运行。应用效果,例如冲击。hadLabel() 函数报告在激活开始时是否存在指定标签,在冲突解决之前。
OnUpdate(managerCtx, abilityCtx)每个活动帧。持续工作,例如计时器或每帧力。
OnStop(managerCtx, abilityCtx)每次停用,无论是自愿还是强制。撤销 OnStart() 所做的事情。
OnTeardown(managerCtx, abilityCtx)在能力移除时运行。断开连接,销毁实例等。

每个回调函数的第一个参数 managerCtx 是一个 ManagerContext 对象,具有共享的角色和管理器属性,包括:

  • managerCtx.AbilityOwner — 角色的 Model,使得 managerCtx.AbilityOwner.PrimaryPart 是根部件。
  • managerCtx.AbilityManager — 管理器的简化视图,以便能力可以在其自己的回调中添加、移除和查询能力。
  • managerCtx.BodyParts — 角色的身体部件,具有每个肢体打开和关闭碰撞的助手。
  • managerCtx.ControllerManager — 角色的 ControllerManager 用于物理控制。当没有注册的能力需要物理时,它可以是 nil
  • managerCtx.RootCFrame — 根部件的 CFrame,在帧开始时快照一次,以便回调不必各自去获取它。
  • managerCtx.RootLookVector — 角色根部件面朝的方向。
  • managerCtx.RootUpVectorY — 根部件的上向量的 Y 分量。
  • managerCtx.TaskSynchronize() — 在启用并行回调支持时,在访问 DataModel 之前同步回调。目前,OnUpdate 不在并行上下文中运行,因此此函数没有效果。未来更新计划提供完整的并行 Luau 支持。

第二个参数 abilityCtx 是一个 AbilityContext 对象,具有引擎管理的当前能力注册的表:

  • abilityCtx.Config — 此能力注册的只读配置值。
  • abilityCtx.State — 可变状态,通过 DataModel 复制。 服务器权限 在回滚和重新仿真期间恢复这些值。
  • abilityCtx.Local — 可变的临时状态,不会复制或参与回滚。

将自定义回调数据存储在 abilityCtx.StateabilityCtx.Local 中。直接写入 abilityCtx 的自定义字段是错误的。

©2026 Roblox Corporation、Roblox、Roblox 标志及 Powering Imagination 是我们在美国及其他国家或地区的注册与未注册商标。