roblox-characters

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Roblox characters

Roblox 角色

Treat a
Player
as the durable identity and each
Character
as a replaceable session with its own references, connections, animation tracks, and cleanup. Targets Roblox's rolling platform APIs.
将
Player
视为持久身份,而每个
Character
都是可替换的会话,拥有独立的引用、连接、动画轨道和清理逻辑。本文档针对 Roblox 滚动更新的平台 API 编写。

When to use

适用场景

  • Use for player-character lifecycle, Humanoid state/movement, rigs, animations, tools, accessories, custom characters, death, or respawn defects.
  • Use whenever code stores a Character/Humanoid/root reference longer than one spawn.
When not to use: general physics queries and constraints belong to
roblox-physics
; remote trust belongs to
roblox-networking
; camera logic belongs to
camera-systems
.
  • 适用于玩家角色生命周期、Humanoid 状态/移动、rigs、动画、工具、配饰、自定义角色、死亡或重生相关问题的场景。
  • 当代码存储 Character/Humanoid/根节点引用的时长超过一次生成周期时使用。
不适用场景: 通用物理查询与约束属于
roblox-physics
范畴;远程信任相关内容属于
roblox-networking
;相机逻辑属于
camera-systems
。

Workflow

工作流程

  1. Inspect the character contract. Check avatar settings,
    StarterCharacter
    ,
    StarterCharacterScripts
    ,
    CharacterAutoLoads
    , R6/R15 support, existing Animate/controller scripts, tools, tags, collision groups, and server/client ownership.
  2. Separate scopes. Player-scope state survives respawn; character-scope state does not. Put character connections/tracks/resources in one cleanup scope and destroy it on removal.
  3. Bind existing and future characters. Connect
    CharacterAdded
    , then bind
    player.Character
    if present. Do not assume event subscription alone sees a character that already spawned.
  4. Resolve required components defensively. Wait with a timeout where replication warrants it; validate
    Humanoid
    , root,
    Animator
    , and rig assumptions. Abort if that character is no longer current before applying delayed work.
  5. Choose movement ownership. Use Humanoid movement for standard avatars; use
    AssemblyLinearVelocity
    ,
    BasePart:ApplyImpulse()
    , or a
    LinearVelocity
    /
    AlignPosition
    constraint only for mechanics that need physical control. Keep gameplay authority and network ownership implications explicit.
  6. Own animation lifecycle. Load via the rig's
    Animator
    ; store tracks/connections; use named markers for gameplay timing only with server validation; stop/disconnect on character cleanup.
  7. Verify lifecycle stress. Spawn, die, reset, rapid-respawn, swap rig if supported, equip/drop tools, leave during setup, and run with at least two players when character interactions matter.
  1. 检查角色约定。 检查 avatar 设置、
    StarterCharacter
    、
    StarterCharacterScripts
    、
    CharacterAutoLoads
    、R6/R15 支持、现有的 Animate/控制器脚本、工具、标签、碰撞组以及服务端/客户端所有权。
  2. 分离作用域。 玩家作用域的状态在重生后仍然保留;角色作用域的状态则不会。将角色的连接/轨道/资源放在同一个清理作用域中,并在角色移除时销毁该作用域。
  3. 绑定现有和未来的角色。 连接
    CharacterAdded
    事件,然后如果
    player.Character
    已存在则绑定它。不要认为仅通过事件订阅就能捕获到已经生成的角色。
  4. 防御式解析所需组件。 在需要复制的场景下使用带超时的等待;验证
    Humanoid
    、根节点、
    Animator
    以及 rig 假设是否成立。在执行延迟工作前,如果该角色已不再是当前角色,则中止操作。
  5. 选择移动控制权。 标准 avatar 使用 Humanoid 移动;仅在需要物理控制的机制中使用
    AssemblyLinearVelocity
    、
    BasePart:ApplyImpulse()
    或
    LinearVelocity
    /
    AlignPosition
    约束。明确游戏玩法的权威归属以及网络所有权的影响。
  6. 掌控动画生命周期。 通过 rig 的
    Animator
    加载动画;存储轨道/连接;仅在服务端验证的前提下,将命名标记用于游戏玩法计时;在角色清理时停止动画/断开连接。
  7. 验证生命周期压力场景。 测试生成、死亡、重置、快速重生、(如支持)切换 rig、装备/丢弃工具、在设置过程中离开等场景,并且在涉及角色交互时至少用两名玩家进行测试。

Pattern: replaceable character scope

模式:可替换角色作用域

lua
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local generation = 0
local connections: {RBXScriptConnection} = {}
local currentCharacter: Model? = nil

local function clearCharacter()
    generation += 1
    for _, connection in connections do connection:Disconnect() end
    table.clear(connections)
    currentCharacter = nil
end

local function bindCharacter(character: Model)
    -- Guard BEFORE teardown. A stale invocation (see the CharacterAdded/defer race below) must not
    -- clear a binding that is already current, or nothing ends up bound at all.
    if player.Character ~= character then return end
    clearCharacter()
    currentCharacter = character
    local thisGeneration = generation
    local humanoid = character:WaitForChild("Humanoid", 10)
    local root = character:WaitForChild("HumanoidRootPart", 10)
    -- Re-check after the yields: a respawn during WaitForChild bumps generation and makes this call stale.
    if not humanoid or not root or generation ~= thisGeneration then return end

    table.insert(connections, humanoid.Died:Connect(function()
        if generation ~= thisGeneration then return end
        setCharacterUiEnabled(false)
    end))
    attachCurrentCharacterSystems(character, humanoid, root)
end

player.CharacterRemoving:Connect(function(character)
    if currentCharacter == character then clearCharacter() end
end)
player.CharacterAdded:Connect(bindCharacter)
if player.Character then task.defer(bindCharacter, player.Character) end
Use the project's cleanup utility when one exists; do not introduce a new framework for three connections. Server systems repeat this binding per
Player
and clear player-scope tables on
PlayerRemoving
.
lua
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local generation = 0
local connections: {RBXScriptConnection} = {}
local currentCharacter: Model? = nil

local function clearCharacter()
    generation += 1
    for _, connection in connections do connection:Disconnect() end
    table.clear(connections)
    currentCharacter = nil
end

local function bindCharacter(character: Model)
    -- Guard BEFORE teardown. A stale invocation (see the CharacterAdded/defer race below) must not
    -- clear a binding that is already current, or nothing ends up bound at all.
    if player.Character ~= character then return end
    clearCharacter()
    currentCharacter = character
    local thisGeneration = generation
    local humanoid = character:WaitForChild("Humanoid", 10)
    local root = character:WaitForChild("HumanoidRootPart", 10)
    -- Re-check after the yields: a respawn during WaitForChild bumps generation and makes this call stale.
    if not humanoid or not root or generation ~= thisGeneration then return end

    table.insert(connections, humanoid.Died:Connect(function()
        if generation ~= thisGeneration then return end
        setCharacterUiEnabled(false)
    end))
    attachCurrentCharacterSystems(character, humanoid, root)
end

player.CharacterRemoving:Connect(function(character)
    if currentCharacter == character then clearCharacter() end
end)
player.CharacterAdded:Connect(bindCharacter)
if player.Character then task.defer(bindCharacter, player.Character) end
如果项目已有清理工具,请使用现有工具;不要为了三个连接就引入新框架。服务端系统需要为每个
Player
重复此绑定逻辑,并在
PlayerRemoving
时清理玩家作用域的表。

Pattern: animation through Animator and markers

模式:通过 Animator 和标记实现动画

lua
local animation = Instance.new("Animation")
animation.AnimationId = "rbxassetid://1234567890"
local track = animator:LoadAnimation(animation)
local markerConnection = track:GetMarkerReachedSignal("Commit"):Connect(function(parameter)
    playLocalSwingEffect(parameter) -- presentation; server still validates any hit
end)

track:Play(0.1)
-- On character teardown:
markerConnection:Disconnect()
track:Stop(0.1)
animation:Destroy()
For rigs without a
Humanoid
, use an
AnimationController
with an
Animator
. Do not use the deprecated convenience path as a substitute for owning the actual Animator and track lifecycle.
lua
local animation = Instance.new("Animation")
animation.AnimationId = "rbxassetid://1234567890"
local track = animator:LoadAnimation(animation)
local markerConnection = track:GetMarkerReachedSignal("Commit"):Connect(function(parameter)
    playLocalSwingEffect(parameter) -- presentation; server still validates any hit
end)

track:Play(0.1)
-- On character teardown:
markerConnection:Disconnect()
track:Stop(0.1)
animation:Destroy()
对于没有
Humanoid
的 rig,请使用带有
Animator
的
AnimationController
。不要使用已弃用的便捷路径来替代对实际 Animator 和轨道生命周期的管理。

Movement and rig rules

移动与 rig 规则

  • Do not hardcode R15 limb names if R6 is supported. Prefer attachments, tags, or a rig-type adapter; branch on
    Humanoid.RigType
    only where topology materially differs.
  • HumanoidRootPart
    is the usual character assembly root, not a universal guarantee for every custom model. Define the custom rig contract and validate it at spawn.
  • Prefer
    Humanoid:Move()
    /standard controls for ordinary avatar locomotion. Directly changing
    AssemblyLinearVelocity
    is an instantaneous physical action; use forces/constraints or impulses when continuous or instantaneous physics is the real intent.
  • Never grant damage or movement authority because a client owns its character physics. Validate cross-player consequences on the server.
  • Tools move between Backpack and Character during equip; listen to lifecycle/state rather than assuming one fixed parent. Modify accessories/appearance through current character APIs and preserve an up-to-date applied
    HumanoidDescription
    when editing avatar appearance.
  • 如果支持 R6,不要硬编码 R15 的肢体名称。优先使用附件、标签或 rig 类型适配器;仅在拓扑结构存在实质差异时,才根据
    Humanoid.RigType
    进行分支处理。
  • HumanoidRootPart
    是通常的角色装配根节点,但并非对所有自定义模型都通用。请定义自定义 rig 的约定,并在生成时进行验证。
  • 普通 avatar 移动优先使用
    Humanoid:Move()
    /标准控制。直接修改
    AssemblyLinearVelocity
    是瞬时物理操作;如果实际需求是连续或瞬时物理效果,请使用力/约束或冲量。
  • 绝不要因为客户端拥有其角色的物理所有权,就授予其伤害或移动权限。所有跨玩家的影响都必须在服务端进行验证。
  • Tools 在装备时会在 Backpack 和 Character 之间移动;请监听生命周期/状态,而不是假设父对象是固定的。通过当前角色 API 修改配饰/外观,并在编辑 avatar 外观时保留最新的已应用
    HumanoidDescription
    。

Common failures

常见问题

SymptomLikely causeRemedy
works once, breaks after resetcached character/Humanoid/rootrebuild per
CharacterAdded
; clear on removal
callbacks fire twice after deathsold character connections survivedcharacter-scoped cleanup and generation/current checks
delayed load edits wrong rigasync work outlived spawncompare current Character/generation after every yield
animation visible only locally or not at allwrong Animator/context/asset ownershipinspect rig Animator, execution side, permissions, and replication
hit marker awards impossible hitanimation marker trusted as authorityuse marker for timing/presentation; server validates combat state
R6/custom rig errorsR15 names assumeddefine rig contract; attachments/adapter; test each supported rig
tool disappears from systemfixed Backpack/Character parent assumedhandle equip/unequip ancestry and character replacement
custom force fights Humanoidtwo controllers own motionchoose one movement authority per state and restore cleanly
症状可能原因解决方法
仅工作一次,重置后失效缓存了 character/Humanoid/root每次
CharacterAdded
时重建;移除时清理
死亡后回调触发两次旧角色的连接未被清理角色作用域清理 + 世代/当前角色检查
延迟加载修改了错误的 rig异步工作的生命周期超过了角色生成周期每次 yield 后比较当前 Character/世代
动画仅在本地可见或完全不可见Animator/上下文/资产所有权错误检查 rig 的 Animator、执行端、权限和复制情况
命中标记触发了不可能的命中将动画标记视为权威来源标记仅用于计时/表现;战斗状态由服务端验证
R6/自定义 rig 报错假设了 R15 的命名定义 rig 约定;使用附件/适配器;测试每种支持的 rig
工具从系统中消失假设了 Backpack/Character 是固定父对象处理装备/卸下的父级变更以及角色替换
自定义力与 Humanoid 冲突两个控制器同时控制运动每个状态选择一个移动控制方,并干净地恢复

Resources

参考资源

  • Read
    references/lifecycle-and-animation.md
    for server binding, death vs removal, rig and animation verification, custom characters, and the lifecycle stress matrix.
  • 阅读
    references/lifecycle-and-animation.md
    了解服务端绑定、死亡与移除的区别、rig 与动画验证、自定义角色以及生命周期压力测试矩阵。

Related skills

相关技能

  • roblox-physics
    — forces, constraints, assemblies, collision, and network ownership.
  • roblox-networking
    — server validation of character actions and stale requests.
  • input-systems
    — action mapping and responsive movement intent.
  • camera-systems
    — camera behavior following replaceable characters.
  • roblox-physics
    —— 力、约束、装配、碰撞与网络所有权。
  • roblox-networking
    —— 角色操作的服务端验证与过期请求处理。
  • input-systems
    —— 动作映射与响应式移动意图。
  • camera-systems
    —— 跟随可替换角色的相机行为。

Primary references

主要参考资料

  • https://create.roblox.com/docs/characters
  • https://create.roblox.com/docs/animation/using
  • https://create.roblox.com/docs/characters/appearance
  • https://create.roblox.com/docs/characters
  • https://create.roblox.com/docs/animation/using
  • https://create.roblox.com/docs/characters/appearance