캐릭터 컨트롤러 라이브러리

*이 콘텐츠는 AI(베타)를 사용해 번역되었으며, 오류가 있을 수 있습니다. 이 페이지를 영어로 보려면 여기를 클릭하세요.

캐릭터 컨트롤러 라이브러리(CCL)는 속성과 Luau 스크립트를 통해 캐릭터의 움직임과 행동을 구축하기 위한 모듈형 프레임워크입니다. 이 아키텍처는 경직된 Humanoid 상태 기계를 유연하고 확장 가능한 캐릭터 메커니즘 시스템으로 대체합니다.

CCL 활성화

CCL은 Studio의 아바타 설정 창을 통해 옵트인 방식으로 제공됩니다. 활성화하려면:

  1. 파일 ⟩ 베타 기능 ⟩ AvatarAbilities Character Controller Library를 통해 CCL 베타를 활성화합니다.

  2. 아바타 탭에서 아바타 설정을 엽니다.

    Studio의 툴바에 표시된 아바타 설정
  3. 창의 왼쪽에서 이동 탭을 선택하고, 능력 섹션에서 캐릭터 컨트롤러 라이브러리를 선택합니다.

    아바타 설정 창의 캐릭터 컨트롤러 라이브러리 토글
  4. 달리기, 점프, 클라이밍과 같은 모든 표준 능력은 기본적으로 활성화되어 있습니다. 런타임에서 이들 중 일부를 비활성화하려면 관련 상자의 선택을 해제하십시오.

능력

능력은 캐릭터가 할 수 있는 것, 예를 들어 달리기, 점프, 오르기, 수영할 수 있는 능력을 평가합니다. Enum.HumanoidStateType과 같은 엔진 정의 캐릭터 상태의 고정 세트에 의존하는 대신, CCL 능력은 캐릭터가 할 수 있는 것과 플레이어 입력에 어떻게 반응해야 하는지를 동적으로 결정합니다.

구조적으로, 능력은 주로 다음을 지정하는 독립적인 Luau 테이블입니다:

테이블 필드목적
Name능력의 고유한 정체성; 조건 및 충돌은 이름으로 참조됩니다. 동일한 Name을 가진 두 개의 능력을 등록하면 오류가 발생합니다. 유사한 능력이 몇 개 있다면, 각각 다른 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를 세계 마스크에 전송합니다.
  • 능력 조건 (StartsWhen, RunsWhile)은 세계 마스크를 테스트하고 반응합니다.
  • 능력 충돌은 활성화 시 어떤 다른 능력이 차단, 중지 또는 일시 중지되는지를 정의합니다.

다음 설정에서, "CanFallDown" 레이블은 Running이 활성화될 때 세계 마스크에 브로드캐스트됩니다. FallingDown 능력은 StartsWhen = All( "CanFallDown", "Stunned" )의 조건으로 인해 자동으로 후보가 되지만, FallingDown이 발생하기 전에 "Stunned"도 세계 마스크에 브로드캐스트되어야 합니다.

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, Any, Not = Rule.All, Rule.Any, 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, 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 }는 능력이 시작될 때 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, 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에서 사용되는 하나 이상의 레이블, 센서 또는 입력 참조입니다. 조건은 런타임에서 비트마스크 연산으로 컴파일되며, 평가는 정수 수학 — 테이블 탐색 및 문자열 비교가 없습니다.

목표구문예시
하나의 필수 조건.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 }을 포함하여 스프린트 시작 시 달리기를 🄐 일시 중지하고, 🄑 스프린트 중간에 차단하며, 🄒 스프린트 중지 시 재개합니다.

또 다른 고유한 충돌 키는 ExclusiveGroup으로, 여러 능력을 그룹으로 묶고 각 능력에 Priority 값을 부여합니다. 그룹당 하나의 능력만 활성화될 수 있으며, 높은 우선 순위가 승리합니다. 그러나 도전자가 소유자의 이름/레이블을 대상으로 하는 Stops를 선언하면 우선 순위에 관계없이 승리합니다.

다음 설정에서는 세 가지 능력(Sprinting, Crouching, Stagger)이 Locomotion 독점 그룹에 추가됩니다. Sprinting은 가장 높은 우선 순위(200)를 가지므로 Crouching(100)보다 우선하며 두 능력은 동시에 실행되지 않습니다. 그러나 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 목록과 연결된 액션 슬롯을 정의합니다.

    여러 액션 슬롯 입력 바인딩이 Roblox에 의해 미리 정의되어 있으며, 향후 입력 액션 관리자를 통해 원하는 대로 액션 슬롯의 기본 입력 바인딩을 재구성할 수 있습니다. ActionSlot을 0으로 설정하면 다음 사용 가능한 빈 슬롯이 선택됩니다. 모바일 장치에서는 슬롯 1-7이 화면의 버튼으로 채워집니다 (아래 다이어그램 참조).

    슬롯키보드 & 마우스게임패드터치기본 할당
    1SpaceButtonA①점프
    2LeftShiftButtonL1②스프린트
    3LeftControlButtonB③무릎 꿇기
    4RButtonX④
    5MouseLeftButtonButtonR2⑤
    6QButtonY⑥
    7XButtonR1⑦
    8CButtonL2
    9FDPadLeft
    10GDPadRight
    11VDPadDown
  • 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.ToolTool을 들고 있음
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.State 또는 abilityCtx.Local에 저장하세요. abilityCtx에 직접 사용자 정의 필드를 쓰는 것은 오류입니다.

©2026 Roblox Corporation. Roblox 및 Roblox 로고, 'Powering Imagination'은 미국 및 기타 국가 내 당사의 등록 및 미등록 상표입니다.