キャラクターコントローラライブラリ (CCL) は、属性とLuauスクリプトを通じてキャラクターの動きや動作を構築するためのモジュラーフレームワークです。このアーキテクチャは、堅牢な Humanoid ステートマシンを、キャラクターのメカニクスのための柔軟で拡張可能なシステムに置き換えます。
CCLを有効にする
CCLは、Studioのアバター設定ウィンドウを通じてオプトインです。有効にするには:
アバタータブから、アバター設定を開きます。

ウィンドウの左側にある動きタブを選択し、能力セクションでキャラクター コントローラー ライブラリを選択します。

走る、ジャンプする、登るなどの標準的な能力はデフォルトで有効になっています。ランタイム中にそれらのいずれかを無効にするには、関連するボックスのチェックを外します。
アビリティ
アビリティは、キャラクターができること、たとえば走る、ジャンプする、登る、泳ぐといった能力を評価します。Enum.HumanoidStateType のようなエンジン定義の固定されたキャラクター状態に依存するのではなく、CCLアビリティはキャラクターができることと、プレイヤーの入力にどのように反応すべきかを動的に決定します。
構造的には、アビリティは主に以下を指定する自己完結型のLuauテーブルです。
| テーブルフィールド | 目的 |
|---|---|
| Name | アビリティのユニークな識別子。 条件 と 競合 は名前で参照します。同じ Name を持つ2つのアビリティを登録するとエラーが発生します。似たようなアビリティがいくつかある場合は、それぞれに異なる Name を付け、共通の ラベル を Labels に共有します。 ModuleScript の名前がユニークな構成キーを決定します。 |
| Labels, TimedLabels | アビリティ間の調整バスとして機能する共有64ビットマスク内の名前付きビット; ラベル を参照してください。 |
| StartsWhen, RunsWhile | アビリティを開始する条件と、アビリティを実行し続ける条件をそれぞれ定義します; 条件 を参照してください。 |
| Blocks, Stops, Suspends, ExclusiveGroup | 同時にアクティブにできないアビリティ間の 競合 を処理する方法。 |
| Input | アビリティをトリガーする入力。 Input.Mode は、入力がアビリティを開始および停止する方法を制御します; RunsWhile は世界の条件のみを保持し、入力自体は含まれません; 入力 を参照してください。 |
| Config, State | 各アビリティ登録のデフォルト構成値と複製された状態。コールバックは abilityCtx.Config から構成を読み取り、abilityCtx.State を通じて複製された状態を読み書きします。 |
| OnSetup, OnStart, OnStop, OnUpdate, OnTeardown | アビリティの実際の動作がスクリプト化されるライフサイクルコールバック; コールバック を参照してください。 |
ラベル
ラベルは、アビリティ間の調整バスとして機能する共有64ビットマスク内の名前付きビットです。基本的には:
- アクティブなアビリティは、その Labels と TimedLabels を世界マスクに ブロードキャスト します。
- アビリティの 競合 は、アクティブ化時にどの 他の アビリティがブロック、停止、または一時停止されるかを定義します。
次のセットアップでは、Running がアクティブなときに "CanFallDown" ラベルが世界マスクにブロードキャストされます。FallingDown アビリティは、その 条件 が StartsWhen = All( "CanFallDown", "Stunned" ) であるため、自動的に候補になりますが、FallingDown が発生する前に "Stunned" も世界マスクにブロードキャストされる必要があります。
local AvatarAbilities = require("@rbx/AvatarAbilities")
local Identifiers = AvatarAbilities.Identifiers
local Ability = Identifiers.Ability
local Rule = AvatarAbilities.Rule
local Sensor = Identifiers.Sensor
local All, Any, Not = Rule.All, Rule.Any, Rule.Not
local Running: AvatarAbilities.AbilityDefinition = {
Name = Ability.Running,
Labels = { "CanFallDown" }, -- アビリティがアクティブなときにブロードキャストされるラベル
StartsWhen = Sensor.Ground,
RunsWhile = Sensor.Ground,
}local AvatarAbilities = require("@rbx/AvatarAbilities")
local Identifiers = AvatarAbilities.Identifiers
local Ability = Identifiers.Ability
local Rule = AvatarAbilities.Rule
local Sensor = Identifiers.Sensor
local All, Any, Not = Rule.All, Rule.Any, Rule.Not
local FallingDown: AvatarAbilities.AbilityDefinition = {
Name = Ability.FallingDown,
StartsWhen = All( "CanFallDown", "Stunned" ), -- アビリティを開始するために必要なラベル
Blocks = { Ability.Running }
}ラベルは、TimedLabels 辞書を使用して タイミング でブロードキャストまたは消費することもできます。
| キー | 説明 |
|---|---|
| TimedLabels.OnStart | ラベル(キー)と関連する期間を含む辞書。アビリティが開始されるとラベルがブロードキャストされ、期間が終了すると自動的に期限切れになります。たとえば、OnStart = { Dashing = 1 } は、アビリティが開始されると1秒間 Dashing ラベルをブロードキャストします。 |
| TimedLabels.OnStop | ラベル(キー)と関連する期間を含む辞書。アビリティが停止するとラベルがブロードキャストされ、期間が終了すると自動的に期限切れになります。たとえば、OnStop = { DashCooldown = 2 } は、アビリティが停止すると2秒間 DashCooldown ラベルをブロードキャストします。 |
| TimedLabels.Consumes | アビリティがアクティブ化されるときに削除(消費)されるラベルのリスト。たとえば、格闘ゲームでプレイヤーが相手の攻撃をブロックした後にカウンター攻撃を許可する場合、CounterAttack アビリティは StartsWhen = "AfterBlock" と TimedLabels = { Consumes = { "AfterBlock" } } の両方を含むことができ、CounterAttack アビリティの二重トリガーを防ぎます。 |
local AvatarAbilities = require("@rbx/AvatarAbilities")
local Identifiers = AvatarAbilities.Identifiers
local Rule = AvatarAbilities.Rule
local Sensor = Identifiers.Sensor
local All, Any, Not = Rule.All, Rule.Any, Rule.Not
local Dash: AvatarAbilities.AbilityDefinition = {
Name = "Dash",
StartsWhen = All( Sensor.Ground, Not("DashCooldown") ),
RunsWhile = "Dashing",
TimedLabels = {
OnStart = { Dashing = 1 },
OnStop = { DashCooldown = 2 },
},
}条件
条件は、StartsWhen と RunsWhile で使用される1つ以上の ラベル、センサー、または入力参照です。条件は、実行時にビットマスク操作にコンパイルされ、評価は整数演算です — テーブルウォークや文字列比較はありません。
| 目標 | 構文 | 例 |
|---|---|---|
| 1つの必須条件。 | 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, Any, Not = Rule.All, Rule.Any, 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 } を含むことで、スプリント開始時に走行が 🄐 一時停止され、🄑 スプリント中にブロックされ、🄒 スプリント停止時に再開されます。 |
もう1つのユニークな競合キーは ExclusiveGroup で、複数のアビリティをグループに配置し、それぞれに Priority 値を持たせます。グループ内では1つのアビリティのみがアクティブになり、高い優先度が勝ちます。ただし、挑戦者が保持者の名前/ラベルをターゲットにした Stops を宣言すると、優先度に関係なく勝ちます。
次のセットアップでは、3つのアビリティ(Sprinting, Crouching, Stagger)が Locomotion 排他グループに追加されます。Sprinting は最高の優先度(200)を持ち、Crouching(100)よりも勝ち、2つは同時に実行されません。ただし、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, Any, Not = Rule.All, Rule.Any, 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, Any, Not = Rule.All, Rule.Any, Rule.Not
local Dash: AvatarAbilities.AbilityDefinition = {
Name = "Dash",
Input = { InputName = "Dash", Mode = "Press", ActionSlot = 5 }
}InputName は論理名であり、キーではありません。CCLは入力センサーを生成し、常に StartsWhen に AND します。
Mode は、この入力がアビリティを開始および停止する方法を定義します。 RunsWhile は決して入力自体を含まず、地面にいるか水中にいるといった世界の条件のみを保持します。したがって、Mode は入力駆動の開始と停止の唯一のソースです:
モード 開始 入力から停止 Press 押したとき。 決して。アビリティは競合、独自の RunsWhile、または Stop() を呼び出すことで自分自身を終了します。 Hold 押したとき。 放したとき。 Hold と Repeats 押したとき。 放すと再発火が終了し、すでに飛行中のサイクルは終了しません。 Toggle トグルオンのとき。 トグルオフのとき。 Press はダッシュ、攻撃、投げなどの離散的なアクションに適しています。 Hold と Toggle はスプリント、狙い、ブロック、しゃがみ、浮遊などの持続的なアクションに適しています。 Hold と Repeats は、繰り返しジャンプなど、保持中に自己停止し再発火するアクションに適しています。
Repeats(ブール値、Hold のみ)は、アビリティが各サイクルで自己終了し、入力が保持されている間に再発火するようにします。全体を通して継続的に実行するのではなく。
OutlivesInputWhile(Hold/Toggle のみ)は、アビリティがリリースまたはトグルオフを超えて実行し続ける条件です。特定の世界条件の下でアビリティが入力を超えて持続する必要がある場合に使用します。
ActionSlot は、入力アクションシステム 内の InputActions および InputBindings のリストに関連付けられた アクションスロット を定義します。
Several action slot input bindings are predefined by Roblox and, in the future, the Input Action Manager will allow you to reconfigure default input bindings for action slots as desired. Setting ActionSlot to 0 will choose the next available empty slot. On mobile devices, slots 1-7 populate to buttons on the screen (see diagram below).
スロット キーボード & マウス ゲームパッド タッチ デフォルト割り当て 1 Space ButtonA ① ジャンプ 2 LeftShift ButtonL1 ② スプリント 3 LeftControl ButtonB ③ しゃがむ 4 R ButtonX ④ 5 MouseLeftButton ButtonR2 ⑤ 6 Q ButtonY ⑥ 7 X ButtonR1 ⑦ 8 C ButtonL2 9 F DPadLeft 10 G DPadRight 11 V DPadDown 
CustomIcon, CustomIconActive, および CustomIconInvalid は、アビリティがアイドル、アクティブ、または利用できないときのタッチボタンのRobloxアセットIDを指定します。
RunsWhile は世界の条件のみを保持します。コンパイラは、Mode に基づいてアビリティの実際の継続に対する入力の効果を内部で構成するため、入力自体を StartsWhen または RunsWhile に入れるとエラーが発生します(そこに Rule.Input を参照しないでください)。 Hold と Toggle アビリティは、デフォルトでリリースまたはトグルオフで停止するため、RunsWhile にそれを重複させる必要はありません:
local AvatarAbilities = require("@rbx/AvatarAbilities")
local Rule = AvatarAbilities.Rule
local Sensor = AvatarAbilities.Identifiers.Sensor
local All, Any, Not = Rule.All, Rule.Any, Rule.Not
local Glide: AvatarAbilities.AbilityDefinition = {
Name = "Glide",
Input = { InputName = "Glide", Mode = "Hold", ActionSlot = 6 },
StartsWhen = Not(Sensor.Ground),
RunsWhile = Not(Sensor.Ground),
}Hold または Toggle アビリティが、世界条件の下でその入力を超えて持続するようにするには、RunsWhile に入力を追加するのではなく、OutlivesInputWhile を設定します。次の Crouching アビリティは、プレイヤーがしゃがみ入力を放した後も、何かが頭上に残っている限りしゃがみ続けます:
local AvatarAbilities = require("@rbx/AvatarAbilities")
local Identifiers = AvatarAbilities.Identifiers
local Sensor = Identifiers.Sensor
local Crouching: AvatarAbilities.AbilityDefinition = {
Name = "Crouching",
Input = { InputName = "Crouch", Mode = "Hold", OutlivesInputWhile = Sensor.Ceiling, ActionSlot = 3 },
RunsWhile = Sensor.Ground,
}センサー
センサーは、エンジンがあなたのために読み取る世界に関する名前付き値です。通常、センサーを読み取ることが多く、書き込むことは少ないです。便利なことに、いくつかのセンサーが事前に登録されています:
| センサー | 説明 |
|---|---|
| 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) | アビリティが登録されるときに1回実行されます。 | 参照をキャッシュしたり、状態を初期化したりします。 |
| OnStart(managerCtx, abilityCtx, hadLabel) | アビリティがアクティブ化されるたびに実行されます。 | インパルスなどの効果を適用します。 hadLabel() 関数は、アクティブ化が開始されたときに指定されたラベルが存在していたかどうかを報告します。 |
| OnUpdate(managerCtx, abilityCtx) | 各アクティブフレームで実行されます。 | タイマーやフレームごとの力などの継続的な作業。 |
| OnStop(managerCtx, abilityCtx) | 各非アクティブ化時、任意または強制的に実行されます。 | OnStart() で行ったことを元に戻します。 |
| OnTeardown(managerCtx, abilityCtx) | アビリティが削除されるときに実行されます。 | 接続を切断したり、インスタンスを破壊したりします。 |
各コールバック関数の最初のパラメーター managerCtx は、キャラクターとマネージャーのプロパティを共有する ManagerContext オブジェクトです:
- managerCtx.AbilityManager — アビリティが自身のコールバック内でアビリティを追加、削除、クエリできるようにするためのマネージャーの簡略化されたビューです。
- managerCtx.BodyParts — キャラクターの体の部分で、四肢ごとに衝突をオンまたはオフにするためのヘルパーがあります。
- managerCtx.ControllerManager — キャラクターの ControllerManager で、物理制御を行います。物理を必要とする登録されたアビリティがない場合は nil になることがあります。
- managerCtx.RootCFrame — ルートパートの CFrame で、フレームの開始時に1回スナップショットされ、コールバックがそれぞれ自分で取得しないようにします。
- managerCtx.RootLookVector — キャラクターのルートパートが向いている方向。
- managerCtx.RootUpVectorY — ルートパートの上向きベクトルの Y 成分。
- managerCtx.TaskSynchronize() — 並列コールバックサポートが有効な場合、DataModelアクセスの前にコールバックを同期します。現在、OnUpdate は並列コンテキストで実行されないため、この関数は効果がありません。完全な並列Luauサポートは将来のアップデートで計画されています。
2番目のパラメーター abilityCtx は、現在のアビリティ登録のためのエンジン管理テーブルを持つ AbilityContext オブジェクトです:
- abilityCtx.Config — このアビリティ登録の読み取り専用構成値。
- abilityCtx.State — DataModelを通じて複製される可変状態。 サーバー権限 は、ロールバックと再シミュレーション中にこれらの値を復元します。
- abilityCtx.Local — 複製されず、ロールバックに参加しない可変のスクラッチ状態。
カスタムコールバックデータは abilityCtx.State または abilityCtx.Local に保存します。 abilityCtx に直接カスタムフィールドを書き込むことはエラーです。