La Libreria del Controllore del Personaggio (CCL) è un framework modulare per costruire movimenti e comportamenti del personaggio attraverso attributi e script Luau. Questa architettura sostituisce le rigide macchine a stati Humanoid con un sistema flessibile ed estensibile per le meccaniche del personaggio.
Abilitare CCL
The CCL is opt-in through Studio's Avatar Settings window. To enable it:
Enable the CCL beta through File ⟩ Beta Features ⟩ AvatarAbilities Character Controller Library.
From the Avatar tab, open Avatar Settings.

Select the Movement tab on the left side of the window and, in the Abilities section, select Character Controller Library.

All of the standard abilities like Running, Jumping, and Climbing are enabled by default. To disable any of them at runtime, uncheck the associated box.
Abilità
Le abilità valutano cosa può fare un personaggio, come la capacità di correre, saltare, arrampicarsi e nuotare. Invece di fare affidamento su un insieme fisso di stati del personaggio definiti dal motore come quelli in Enum.HumanoidStateType, le abilità CCL determinano dinamicamente cosa può fare un personaggio e come dovrebbe rispondere all'input del giocatore.
Strutturalmente, un'abilità è una tabella Luau autonoma che specifica principalmente i seguenti elementi:
| Campi della Tabella | Scopo |
|---|---|
| Name | Identità unica dell'abilità; condizioni e conflitti la fanno riferimento per nome. Registrare due abilità con lo stesso Name genera un errore. Per alcune abilità simili, dare a ciascuna un Name diverso e condividere un etichetta comune in Labels. Il nome dello ModuleScript determina la chiave di configurazione unica. |
| Labels, TimedLabels | Bit nominati in una maschera condivisa a 64 bit che funge da bus di coordinamento tra le abilità; vedere etichette. |
| StartsWhen, RunsWhile | Condizioni che definiscono quando avviare l'abilità e quando mantenerla attiva, rispettivamente; vedere condizioni. |
| Blocks, Stops, Suspends, ExclusiveGroup | Come gestire i conflitti tra abilità che non possono essere attive contemporaneamente. |
| Input | L'input che attiva l'abilità. Input.Mode controlla come l'input avvia e ferma l'abilità; RunsWhile contiene solo condizioni del mondo, mai l'input stesso; vedere input. |
| Config, State | Valori di configurazione predefiniti e stato replicato per ogni registrazione di abilità. I callback leggono la configurazione da abilityCtx.Config e leggono o scrivono lo stato replicato tramite abilityCtx.State. |
| OnSetup, OnStart, OnStop, OnUpdate, OnTeardown | Callback del ciclo di vita in cui il comportamento effettivo dell'abilità è programmato; vedere callback. |
Etichette
Un'etichetta è un bit nominato in una maschera condivisa a 64 bit che funge da bus di coordinamento tra le abilità. Essenzialmente:
- Un'abilità attiva trasmette le sue Labels e TimedLabels alla maschera del mondo.
- I conflitti dell'abilità definiscono quali altre abilità sono bloccate, fermate o sospese all'attivazione.
Nella seguente configurazione, l'etichetta "CanFallDown" viene trasmessa alla maschera del mondo quando Running è attivo. L'abilità FallingDown con la sua condizione di StartsWhen = All( "CanFallDown", "Stunned" ) diventa automaticamente un candidato, ma "Stunned" deve anche essere trasmesso alla maschera del mondo prima che si verifichi FallingDown.
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" }, -- Etichette trasmesse quando l'abilità è attiva
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" ), -- Etichette necessarie per avviare l'abilità
Blocks = { Ability.Running }
}Le etichette possono anche essere trasmesse o consumate in modo temporizzato utilizzando il dizionario TimedLabels.
| Chiave | Descrizione |
|---|---|
| TimedLabels.OnStart | Dizionario contenente etichette (chiavi) e durate associate. L'etichetta/e vengono trasmesse quando l'abilità inizia e scadono automaticamente quando la loro durata termina. Ad esempio, OnStart = { Dashing = 1 } trasmette l'etichetta Dashing per 1 secondo quando l'abilità inizia. |
| TimedLabels.OnStop | Dizionario contenente etichette (chiavi) e durate associate. L'etichetta/e vengono trasmesse quando l'abilità si ferma e scadono automaticamente quando la loro durata termina. Ad esempio, OnStop = { DashCooldown = 2 } trasmette l'etichetta DashCooldown per 2 secondi quando l'abilità si ferma. |
| TimedLabels.Consumes | Elenco di etichette da rimuovere (consumare) quando l'abilità si attiva. Ad esempio, se un gioco di combattimento consente ai giocatori di contrattaccare dopo aver bloccato l'attacco di un avversario, l'abilità CounterAttack può contenere sia StartsWhen = "AfterBlock" che TimedLabels = { Consumes = { "AfterBlock" } } per prevenire il doppio attivamento dell'abilità 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 },
},
}Condizioni
Una condizione è una o più etichette, sensori o un riferimento di input, utilizzati da StartsWhen e RunsWhile. Le condizioni si compilano in operazioni di bitmask a runtime e la valutazione è matematica intera — nessun passaggio di tabelle e nessun confronto di stringhe.
| Obiettivo | Sintassi | Esempio |
|---|---|---|
| Una condizione richiesta. | StartsWhen = Sensor.Ground | |
| Logica AND per quando tutte le etichette esistono nella maschera del mondo e tutti i sensori sono attivi. | All() | StartsWhen = All( "CanFallDown", "Stunned" ) |
| Logica OR per quando qualunque delle etichette esiste nella maschera del mondo o qualunque dei sensori è attivo. | Any() | StartsWhen = Any( "WallClimbing", "Climbing" ) |
| Negazione in modo che le etichette non possano esistere nella maschera del mondo e i sensori non possano essere attivi. | Not() | RunsWhile = Not("Stunned") |
La valutazione condizionale può essere combinata per una logica più complessa, come il chaining di All() più Not() per indicare che un sensore deve essere attivo mentre un'etichetta deve essere inesistente:
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") ),
}Conflitti
Alcune abilità non possono essere attive quando un'altra abilità è attiva; ad esempio, i personaggi non possono saltare mentre nuotano e non possono correre mentre cadono. Il motore risolve questi conflitti in modo dichiarativo all'interno della definizione di un'abilità:
| Chiave di Conflitto | Scopo |
|---|---|
| Blocks | Quando l'abilità proprietaria è attiva, le altre abilità elencate non possono avviarsi. Ad esempio, un'abilità ScopeAim potrebbe contenere Blocks = { Ability.Running, Ability.Jumping } per impedire ai personaggi di correre o saltare mentre mirano attentamente attraverso il mirino della loro arma. |
| Stops | Quando l'abilità proprietaria inizia, le altre abilità elencate si fermano forzatamente e devono essere riattivate. Ad esempio, un'abilità Hover potrebbe contenere Stops = { Ability.Running } per fermare immediatamente il movimento di corsa di un personaggio quando inizia a fluttuare. |
| Suspends | Quando l'abilità proprietaria inizia, le altre abilità elencate si mettono in pausa e poi riprendono automaticamente quando l'abilità proprietaria si ferma. Ad esempio, un'abilità di sprint personalizzata potrebbe contenere Suspends = { Ability.Running } in modo che la corsa 🄐 si metta in pausa all'inizio dello sprint, 🄑 venga bloccata a metà sprint e 🄒 riprenda alla fine dello sprint. |
Un'altra chiave di conflitto unica è ExclusiveGroup che colloca più abilità in un gruppo, ciascuna con un valore di Priority. Solo un'abilità per gruppo può essere attiva e la priorità più alta vince. Tuttavia, se un sfidante dichiara Stops mirato al nome/etichetta del detentore, vince indipendentemente dalla priorità.
Nella seguente configurazione, tre abilità (Sprinting, Crouching, Stagger) sono aggiunte a un gruppo esclusivo Locomotion. Sprinting ha la priorità più alta (200) quindi vince su Crouching (100) e le due non vengono mai eseguite contemporaneamente. Tuttavia, Stagger ferma forzatamente lo sprint (Stops = { Ability.Sprinting }), quindi può interrompere e superare Sprinting anche se la sua priorità (150) è inferiore.
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 },
}
-- Un'abilità a bassa priorità può sovrascrivere un'abilità ad alta priorità fermandola
local Stagger: AvatarAbilities.AbilityDefinition = {
Name = "Stagger",
ExclusiveGroup = { Name = "Locomotion", Priority = 150 },
Stops = { Ability.Sprinting },
}Input
La definizione di Input di un'abilità specifica l'input utilizzato per tentare di attivare l'abilità. Prende coppie chiave-valore che configurano il comportamento dell'input, lo slot di azione e le icone dei pulsanti touch opzionali.
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 è un nome logico, non una chiave. La CCL genera un sensore di input e lo ANDa sempre in StartsWhen.
Mode definisce come questo input avvia e ferma l'abilità. RunsWhile non contiene mai l'input stesso; contiene solo condizioni del mondo, come essere a terra o in acqua, quindi Mode è l'unica fonte di avvio e arresto guidati dall'input:
Modalità Avvia Ferma dall'Input Press Alla pressione. Mai. L'abilità termina se stessa attraverso un conflitto, il proprio RunsWhile, o chiamando Stop(). Hold Alla pressione. Alla rilascio. Hold con Repeats Alla pressione. Il rilascio termina il riavvio, non il ciclo già in volo. Toggle Alla attivazione. Alla disattivazione. Press si adatta ad azioni discrete come dash, attacco e lancio. Hold e Toggle si adattano ad azioni sostenute come sprint, mira, blocco, accovacciarsi e levitare. Hold con Repeats si adatta ad azioni che si fermano da sole e si riattivano mentre sono tenute, come i salti ripetuti.
Repeats (booleano, solo Hold) fa sì che l'abilità si termini autonomamente ad ogni ciclo e si riattivi mentre l'input rimane tenuto, invece di funzionare continuamente per tutta la durata del mantenimento.
OutlivesInputWhile (solo Hold/Toggle) è una condizione sotto la quale l'abilità continua a funzionare oltre il rilascio o la disattivazione, fermandosi una volta che la condizione si libera. Usalo quando un'abilità dovrebbe durare più a lungo del suo input sotto una specifica condizione del mondo.
ActionSlot definisce uno slot di azione che è associato a un elenco di InputActions e InputBindings all'interno del Sistema di Azione Input.
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).
Slot Tastiera & Mouse Gamepad Touch Assegnazione Predefinita 1 Space ButtonA ① Salta 2 LeftShift ButtonL1 ② Corsa 3 LeftControl ButtonB ③ Accovacciati 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 e CustomIconInvalid specificano gli ID degli asset di Roblox per il pulsante touch quando l'abilità è inattiva, attiva o non disponibile, rispettivamente.
RunsWhile contiene solo condizioni del mondo. Il compilatore compone l'effetto dell'input nella continuazione effettiva dell'abilità dietro le quinte in base a Mode, quindi mettere l'input stesso in StartsWhen o RunsWhile genera un errore (non fare riferimento a Rule.Input lì). Le abilità Hold e Toggle si fermano già al rilascio o alla disattivazione per impostazione predefinita, quindi non è necessario duplicare ciò in 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),
}Per far sì che un'abilità Hold o Toggle duri più a lungo del suo input sotto una condizione del mondo, impostare OutlivesInputWhile invece di aggiungere l'input a RunsWhile. La seguente abilità Crouching continua a accovacciarsi dopo che il giocatore rilascia l'input di accovacciamento, finché qualcosa rimane sopra:
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,
}Sensori
Un sensore è un valore nominato riguardo al mondo che il motore legge per te. Di solito leggerai i sensori piuttosto che scriverli. Per comodità, diversi sensori sono pre-registrati:
| Sensore | Descrizione |
|---|---|
| Sensor.Ground | In piedi su una superficie |
| Sensor.IsMoving | È stato applicato un input di movimento |
| Sensor.MoveInput | Il vettore di movimento stesso |
| Sensor.Ceiling | Qualcosa è direttamente sopra |
| Sensor.Climb | Una superficie arrampicabile è a portata |
| Sensor.Water / Sensor.WaterSurface | In acqua / in superficie |
| Sensor.Sit | Seduto |
| Sensor.Tipped | Caduto |
| Sensor.Tool | In possesso di un Tool |
| Sensor.LookDirectionInput | La direzione di sguardo comandata |
| Sensor.RotateToLookDirectionInput | Se il personaggio dovrebbe ruotare nella direzione di sguardo comandata |
Callback
Le funzioni di callback delle abilità ti permettono di programmare comportamenti specifici:
Sebbene tu registri abilità personalizzate sul server, i loro callback vengono eseguiti sia nella simulazione client prevista che nella simulazione server autorevole. Mantieni il comportamento del callback deterministico in modo che entrambe le simulazioni producano lo stesso risultato.
| Callback | Si Esegue | Casi d'Uso |
|---|---|---|
| OnSetup(managerCtx, abilityCtx) | Una volta, quando l'abilità è registrata. | Memorizza riferimenti, inizializza stato, ecc. |
| OnStart(managerCtx, abilityCtx, hadLabel) | Ogni volta che l'abilità viene attivata. | Applica un effetto come un impulso. La funzione hadLabel() riporta se un'etichetta specificata era presente quando è iniziata l'attivazione, prima della risoluzione dei conflitti. |
| OnUpdate(managerCtx, abilityCtx) | Ogni frame attivo. | Lavoro continuo come timer o forze per frame. |
| OnStop(managerCtx, abilityCtx) | Ogni disattivazione, volontaria o forzata. | Annulla ciò che ha fatto OnStart(). |
| OnTeardown(managerCtx, abilityCtx) | Alla rimozione dell'abilità. | Disconnetti connessioni, distruggi istanze, ecc. |
Il primo parametro di ogni funzione di callback, managerCtx, è un oggetto ManagerContext con proprietà condivise del personaggio e del manager, inclusi:
- managerCtx.AbilityOwner — Il Model del personaggio in modo che managerCtx.AbilityOwner.PrimaryPart sia la parte radice.
- managerCtx.AbilityManager — Una vista ridotta del manager in modo che un'abilità possa aggiungere, rimuovere e interrogare abilità dall'interno dei propri callback.
- managerCtx.BodyParts — Le parti del corpo del personaggio, con helper per attivare e disattivare la collisione per ogni arto.
- managerCtx.ControllerManager — Il ControllerManager del personaggio per il controllo fisico. Può essere nil quando nessuna abilità registrata richiede fisica.
- managerCtx.RootCFrame — Il CFrame della parte radice, catturato una volta all'inizio del frame in modo che i callback non debbano ciascuno andarlo a recuperare.
- managerCtx.RootLookVector — Direzione in cui la parte radice del personaggio è rivolta.
- managerCtx.RootUpVectorY — Il componente Y del vettore verso l'alto della parte radice.
- managerCtx.TaskSynchronize() — Sincronizza un callback prima dell'accesso al DataModel quando il supporto per callback paralleli è abilitato. Attualmente, OnUpdate non viene eseguito in un contesto parallelo, quindi questa funzione non ha effetto. Il supporto completo per Luau parallelo è pianificato per un aggiornamento futuro.
Il secondo parametro, abilityCtx, è un oggetto AbilityContext con tabelle gestite dal motore per la registrazione dell'abilità corrente:
- abilityCtx.Config — Valori di configurazione di sola lettura per questa registrazione di abilità.
- abilityCtx.State — Stato mutabile che si replica attraverso il DataModel. Autorità del Server ripristina questi valori durante il rollback e la riesecuzione.
- abilityCtx.Local — Stato di lavoro mutabile che non si replica o partecipa al rollback.
Memorizza i dati personalizzati del callback in abilityCtx.State o abilityCtx.Local. Scrivere campi personalizzati direttamente in abilityCtx è un errore.