Roblox 動畫 (R6 / R15)
您以一個精簡的 JSON 動作規格 (motion spec) 來編寫動作:它包含少量以解剖學術語(例如「右前臂向前 90°」、「膝蓋彎曲 60°」)表示的關鍵姿勢。內建引擎會處理所有手動操作容易出錯的細節:兩種骨架的 Roblox 關節數學計算、插值、腳部貼地、3D 預覽器、合理性警告,以及烘焙關鍵影格的匯出。
使用者透過觀看來判斷結果,因此流程是:規劃階段 → 編寫規格 → 建置 → 自行檢視分鏡圖 → 修正 → 交付預覽與關鍵影格。請勿跳過檢視步驟;紙上看起來正確的姿勢編號,在視覺上常常是錯誤的(手臂穿過胸部、踢擊動作永遠碰不到球)。
工作流程
- 確定動作。 骨架(R6 或 R15;只有在真的無法推斷時才詢問,否則預設為 R15 並告知),慣用手,是否循環,大致時長,以及需要哪些遊戲機制掛鉤(命中影格、球釋放時機、腳步聲)。對於明確的要求,應立即開始建置。
- 在編寫數字之前將其分解為數個階段。幾乎每個動作都是:準備 → 預備 → 動作 → 跟隨 → 恢復。請參閱
references/motion-cookbook.md中您正在執行的類型(戰鬥、運動、走跑循環、特技、R6 特殊情況);該檔案包含時間配置表和姿勢教學。 - 將規格編寫至
<名稱>.json。從examples/中最接近的檔案開始,而不是從零開始。 - 建置:
node <技能目錄>/scripts/ranim.cjs <名稱>.json --out out(可以傳遞多個規格;它們會在一個預覽畫面中以分頁顯示)。只需要 Node,無需安裝套件。 - 閱讀輸出在 stdout 的報告。它會列出每個關鍵影格中頭部、手部和腳部的實際位置(單位:stu;R = 角色的右方,U = 地面以上高度,F = 前方)並印出
WARN行。使用這些位置來檢查意圖:拳頭真的在胸部前方嗎?腳部在球的高度嗎? - 使用 Read 工具檢視
out/storyboard-<名稱>.png(從 3/4 視角和側面視角顯示的每個關鍵影格)。如果沒有產生 PNG,請使用無頭瀏覽器截取out/preview.html的畫面,或讀取 SVG。將每個面板與您預期的階段進行比較。 - 修正並重建,直到姿勢清晰可讀,且警告訊息消失或被有意識地接受。通常需要兩到三輪的調整。
- 交付: 互動式
out/preview.html(將其發布為成品或直接傳送檔案),以及out/<名稱>.rbxmx和out/<名稱>.lua。如果可以,請將分鏡圖圖片內嵌顯示。簡要告訴使用者如何將其匯入 Studio(如下所述)以及有哪些動畫事件。
動作規格
{
"name": "JabCross", // 成為 KeyframeSequence 的名稱和檔案名稱
"title": "Jab-cross combo", // 在預覽器中顯示
"rig": "R15", // "R15" 或 "R6"
"priority": "Action", // Idle | Movement | Action | Action2..4 | Core
"loop": false,
"description": "在預覽器旁顯示的一兩句說明。",
"keys": [
{ "t": 0, "label": "guard", "note": "在階段列表中顯示。",
"pose": { "UpperTorso": { "turnR": 10, "bendFwd": 8 },
"LeftUpperArm": { "fwd": 50, "out": 8 }, "LeftLowerArm": { "bend": 120 },
"LeftFoot": "flat" } },
{ "t": 0.1, "label": "jab", "ease": "out", "copy": "guard",
"pose": { "LeftUpperArm": { "fwd": 86, "in": 22 }, "LeftLowerArm": { "bend": 6 } } },
{ "t": 0.8, "label": "recover", "copy": "guard" }
],
"markers": [ { "t": 0.1, "name": "Hit", "value": "jab" } ],
"props": [ { "type": "ball", "radius": 0.6, "color": "#e07a2c", "keys": [ ... ] } ]
}
(註解僅供說明;檔案必須是純 JSON。)
可選的頂層欄位:fps(預設為 30;非常快速的動作請使用 60)、duration(預設為最後一個關鍵影格的時間)、grounding(設為 "off" 以手動控制高度)、mirror: true(左右翻轉整個片段,例如產生左腳版本)、endKeyframe: true。
關鍵影格 (Keys)
t以秒為單位(對齊到影格)。第一個關鍵影格位於 0 秒。pose將關節名稱對應到其通道,單位為 度。在一個關鍵影格中未提及的關節僅會透過該影格進行插值,因此中間的關鍵影格可以只提及重要的關節。從未被提及的關節將保持在預設姿勢,且不會被匯出;在關鍵影格 0 之後才首次被提及的關節則會從預設姿勢 (0°) 開始。copy:一個先前關鍵影格的標籤或索引。姿勢會先從複製開始,然後pose會覆蓋其中的部分內容。將"mirror": true與copy一起使用會交換左右兩側,這是從半步生成走路/跑步循環的方法。ease控制離開此關鍵影格時的曲線形狀:smooth(預設,自然緩和,無過衝)、linear、in(開始慢,結束快:用於蓄力釋放打擊)、out(開始快,結束平穩:用於衝擊)、inOut、hold、overshoot、anticipate、bounce、elastic。lift:在此關鍵影格中,身體最低點離地面的高度,單位為 stud(預設為 0)。這是用來製作跳躍動作的方法;請參閱「貼地 (Grounding)」一節。
關節與通道
角度採用解剖學用語,且相同的詞彙在身體兩側意義相同,因此鏡像姿勢不需要變更正負號。每個通道都有一個相反方向的別名;請使用讀起來較自然的用法。
| 關節 | 通道 (相反方向的別名) |
|---|---|
根節點:LowerTorso (R15)、Torso (R6) | bendFwd (bendBack)、turnL (turnR)、leanR (leanL)、moveFwd (moveBack)、moveR (moveL)、moveUp (moveDown),單位為 stud |
脊椎:UpperTorso、Head | bendFwd (bendBack)、turnL (turnR)、leanR (leanL) |
上肢:Left/RightUpperArm、Left/RightUpperLeg;R6 Left Arm、Right Arm、Left Leg、Right Leg | fwd (back) 將肢體向前/向上擺動、out (in) 遠離身體/橫越身體、twistOut (twistIn) 沿著肢體長度軸心旋轉 |
Left/RightLowerArm、Left/RightLowerLeg | bend:手肘和膝蓋在其自然方向彎曲 (0 = 伸直) |
Left/RightHand、Left/RightFoot | fwd (back)、out (in)、twistOut (twistIn)。腳部也接受字串 "flat" |
地標:手臂的 fwd: 90 指向正前方,fwd: 180 指向正上方,out: 90 是 T-pose。腿部的 fwd: 90 是齊腰高的前踢。旋轉是父子層級疊加,因此胸部的旋轉會帶動手臂;將 Head 朝相反方向旋轉可以讓視線保持注視目標。
R6 只有六個部件,沒有手肘、膝蓋、手掌或腳掌,因此輪廓來自軀幹和整個肢體的角度;請稍微誇大一點。R6 肢體名稱包含空格(例如 "Right Arm")。
貼地 (Grounding)
預設情況下,引擎會在每個影格降低或提高根節點,使身體的最低點恰好位於 lift stud 的高度。其影響如下:
- 蹲下、弓箭步和劈腿會自動降低臀部;永遠不需要為站立姿勢手動調整臀部高度。
- R15 腳部的
"flat"會調整腳踝,使腳掌無論腿部做什麼動作都能平貼地面。對於每個踩在地上的腳,都請使用它;對於在空中或踮腳的腳,請給出明確的角度(例如"back": 40表示腳尖點地)。 - 跳躍是透過在空中關鍵影格設定
lift值來實現(起跳時小,最高點最大,落地時為 0)。空中的身體旋轉作用在根節點上:後空翻是根節點的bendBack在關鍵影格間從 0 變化到 360(角度是連續的,因此 360 代表完整旋轉一圈,而非「回到 0」)。 - 在貼地功能開啟時,根節點的
moveUp會被忽略。僅在游泳或攀爬等與地面無關的動作中,才將"grounding": "off"設為關閉。 - 遊戲中的跳躍和衝刺通常由角色控制器驅動,而非動畫。對於打算在遊戲跳躍期間播放的動畫,請設定身體姿勢並將
lift保持為 0。對於自包含的表情、帶有跳躍的攻擊和翻滾,請使用lift和moveFwd。如果片段結束時的位置與起始位置不同,報告會發出警告,因為 Roblox 會在軌道停止時將身體位置回彈。
標記與道具
markers會成為KeyframeMarker,在遊戲中可以透過track:GetMarkerReachedSignal("Hit")讀取。將它們放在所有遊戲機制關心的影格上:命中視窗、球接觸或釋放時機、腳步聲、音效提示。props僅供預覽用(不會被匯出),目的是讓動作能根據與之互動的物體來評估。type: "ball"搭配radius,或任何其他類型用於長方體(size: [x, y, z];劍就是一個長條形長方體)。at可以是一個部件名稱(道具跟隨該部件;offset: [右, 上, 前]在部件自身的軸向上),或是一個固定點[右, 上, 前],單位為 stud,相對於角色正下方的地面點。如果有多個keys,道具會在各個錨點之間移動;arc會為離開該關鍵影格的線段增加一個拋物線上升軌跡(例如投籃或傳球)。請參閱examples/jump_shot.json和examples/soccer_kick.json。
良好的成果標準
- 可辨識的輪廓。 在分鏡圖中,每個關鍵影格應能僅從其外型即可辨識。如果兩個相鄰的關鍵影格看起來相似,代表其中一個沒有發揮作用。
- 時間對比。 緩慢的預備,非常快速的動作(2 到 4 個影格),跟隨階段短暫停頓,較慢的恢復。關鍵影格之間等距的時間間隔是導致動作感覺輕飄飄最常見的原因。
- 全身參與。 力量從腳部和臀部開始,然後是胸部、肩膀,最後是手或腳。在蓄力時讓臀部和胸部有反向旋轉,並讓遠端的手臂平衡近端的手臂。
- 腳部保持不動。 踩在地上的腳會使其 R 和 F 數值在各個關鍵影格之間保持不變。如果必須移動,請在中間的關鍵影格中將其抬起(例如踩一步)。
- 零警告, 或者保留的每個警告都有其原因。限制範圍是自然的關節活動範圍;超出限制通常代表原本打算使用不同的通道。
將其匯入 Roblox Studio
提供使用者兩種方法以及事件名稱。
- 命令列 (最快): 在 Explorer 中選取骨架,開啟 View → Command Bar,將
<Name>.lua的整個內容貼上,按下 Enter。KeyframeSequence 會出現在骨架的AnimSaves中(如果未選取任何物件則會在 ServerStorage 中),動畫編輯器可以從那裡載入它進行微調。 - 檔案: 將
<Name>.rbxmx拖曳到 Studio 的檢視埠中,或在服務上按右鍵 → 從檔案插入 (Insert from File)。 - 發布: 要在遊戲中播放,必須上傳:在動畫編輯器中開啟後發布,或在 KeyframeSequence 上按右鍵 → 儲存到 Roblox (Save to Roblox),然後在
Animation物件中使用產生的 asset id,並透過Animator:LoadAnimation載入。對於在 Studio 中的快速本地測試,game:GetService("KeyframeSequenceProvider"):RegisterKeyframeSequence(seq)會傳回一個暫時的 id。Studio 的選單會不時更新;如果某個步驟與使用者所見不符,請告知並查詢目前的用語,而不是堅持己見。
匯出的結果是烘焙過的:每個影格一個關鍵影格,使用線性緩動,因此 Studio 在任何相同類型的骨架上播放的結果都與預覽相符。只會寫入規格中有動畫的關節,因此僅限上半身的動畫會讓腿部保有預設走路動作。R15 輸出包含 AuthoredHipHeight,因此可以重新定位到其他比例的角色身上。
檔案
scripts/ranim.cjs— 引擎、預覽器和匯出器整合在一個檔案中。也可以作為模組使用:const R = require('.../ranim.cjs'); const c = R.compile(spec); R.report(c); R.sample(c, t)。scripts/selftest.cjs— 針對 Roblox 的 Motor6D 公式檢查關節數學計算。在編輯引擎後執行它。examples/—soccer_kick、jump_shot(附帶球道具的運動)、jab_cross(R15 戰鬥)、r6_sword_slash(R6 附帶武器的戰鬥)、backflip(全身旋轉和跳躍)、r6_run(鏡像循環)。references/motion-cookbook.md— 按類型分類的時間配置表和姿勢教學。在開始編寫前,請先閱讀相關章節。