FreeMinecraftModels 動畫
FreeMinecraftModels 從 .bbmodel 與 .fmmodel 檔案匯入動畫。本頁介紹保留名稱、影格時間、插值、循環模式與逆向運動學(IK)。
關於骨骼命名規則與其餘的匯入契約,請參閱模型製作注意事項。
五個狀態動畫
FreeMinecraftModels 只把五個小寫動畫名稱綁定到自動的運行時狀態。模型中的其他一切都是自訂動畫。
| 動畫名稱 | 是否循環 | 何時播放 |
|---|---|---|
spawn | 否 | 模型建立時播放一次。結束後會接續到 idle |
idle | 是 | 水平方向靜止時;X 或 Z 速度不為零時切換到 walk |
walk | 是 | 水平移動時;接地且 X、Z 速度皆為零時切換到 idle |
attack | 否 | 被觸發時播放;結束後回到 idle |
death | 否 | 呼叫 removeWithDeathAnimation() 時 |
由狀態機的建構方式推導出的規則:
- 若模型有
spawn,起始狀態就是spawn,否則為idle。兩者皆無的模型沒有目前狀態,因此在明確播放某個動畫之前不會有任何動作。 - 只有模型中實際存在的動畫才會取得狀態。一個有
walk但沒有idle的模型,永遠不會自行從walk轉換出來。 - idle/walk 切換讀取底層實體的水平速度;單純的垂直移動不會開始行走。靜態實體與玩家偽裝沒有供此功能使用的底層實體,靜止道具也沒有水平移動。其他動畫透過腳本、API 或 FMM 偽裝控制器驅動。
jump 只存在於列舉中JUMP 確實存在於 AnimationStateType 列舉中,而且當實體離地時 walk 狀態也的確會請求一次 jump 轉換 —— 但由於從未註冊任何 jump 狀態,該請求最終不會有任何結果。名為 jump 的動畫並非無效:它只是表現得跟其他自訂動畫一樣,必須手動觸發。玩家偽裝是例外 —— 它們使用另一個控制器,其中的 jump 確實有被接上。
玩家偽裝使用另一組名稱
玩家偽裝新增逐 tick 控制器,透過相同的播放引擎請求動畫。它的五個保留名稱是 attack、jump、sneak、walk、idle,在單次動畫倒數未執行時依此優先順序檢查。模型沒有 idle 時會在主控台警告。完整表格與單次動畫的時間限制請參閱玩家偽裝。
自訂動畫
任何名稱不屬於上述五個之一的動畫,仍可依名稱播放:
modeledEntity.playAnimation("open", /* blend */ true, /* loop */ false);
modeledEntity.stopCurrentAnimations();
boolean exists = modeledEntity.hasAnimation("open");
context.prop:play_animation("open", true, false)
context.prop:stop_animation()
blend並不會做交叉淡入淡出。true會把動畫排入佇列,等目前狀態的該 tick 完成後才開始;false則會中斷並立即切換。- 佇列只有一個位置,後來的排隊請求會取代前一個。沒有目前狀態時,自訂動畫立即開始。排隊的內建狀態無法從空的目前狀態繼續執行;此時請使用
blend=false。 loop僅適用於自訂動畫。內建狀態一律使用自己的循環設定,不論你傳入什麼值。- 自訂動畫與
hasAnimation查詢區分大小寫,請使用精確名稱。內建狀態的播放請求接受不同大小寫,但註冊狀態仍要求模型內使用小寫名稱。 - 非循環自訂動畫結束時,會請求儲存的最後提交的內建狀態;沒有記錄時請求
idle。這是管理器先前離開的最後一個內建狀態,可能不是自訂動畫開始前正在執行的狀態。請求的返回狀態不存在時,自訂狀態仍被選取,但不再更新影格。 - 對未知名稱,
playAnimation回傳false,但下述被抑制的攻擊請求除外。回傳成功表示請求已接受,不代表已經播放了可見影格。 - 若模型有
idle,stopCurrentAnimations()會轉換到idle;否則它會退出目前狀態,讓模型沒有任何作用中的動畫。 - 在自訂動畫執行期間,對
attack、attack_melee或attack_ranged的請求會被吞掉,以免腳本化的序列被例行戰鬥打斷。 - 死亡是共用狀態機的終止狀態:新請求回傳
false,排隊的切換被捨棄,停止動畫也不會改變該狀態。不過公開的停止方法還會向 Bedrock 個別傳送停止請求,因此不要用它管理兩種客戶端上的死亡動畫。
時序與長度
- Blockbench 以秒為單位儲存動畫長度。FMM 以
ceil(seconds x 20)轉換它,因此長度一律是整數個 tick,短動畫會無條件進位而非捨去。 - 每個動畫都會在匯入時被烘焙成一個扁平的逐 tick 影格陣列。播放是每 tick 一次的陣列查找,而非即時插值。
- 循環動畫以
counter % duration取索引;非循環動畫則鉗制在最後一個影格,之後不再渲染任何變化。 - 關鍵影格時間保留小數 tick 位置(
20 x time,不取整),因此 0.37 秒的關鍵影格也參與 tick 之間的插值。影格在0到duration - 1的整數 tick 上取樣;恰好位於宣告結束時間的關鍵影格會影響插值,但本身不會被取樣。如果必須在可見影格達到最終姿勢,請將它放在這個邊界之前。 - 若同一通道上有兩個關鍵影格落在完全相同的時間,檔案順序中較後者勝出。
- 時間為非有限值的關鍵影格會中止該軌道,並針對每個動畫產生一則
Malformed animation timeline for model ...警告,而該模型的其他動畫仍會繼續轉換。
零長度動畫是有效的
長度為 0(或負數)的動畫會被視為刻意的靜態姿勢 —— 這是家具與其他需要一個具名「無動畫」條目的道具常見的製作選擇。它會被靜默略過且不發出警告,也不會貢獻任何影格。
循環模式
Blockbench 的循環設定控制匯出的 Bedrock 動畫:
| Blockbench 循環模式 | Bedrock 匯出 |
|---|---|
loop | "loop": true |
once | "loop": false |
hold | "loop": "hold_on_last_frame" |
Java 播放使用內建狀態的循環規則,或自訂動畫傳入的 loop 參數,不使用這個 Blockbench 欄位決定是否循環。因此設定不一致時,Java 與 Bedrock 的播放可能不同。
插值類型
每個關鍵影格都帶有自己的插值類型,而進入某個關鍵影格的區段會使用該關鍵影格的類型。支援四種:
| Blockbench 類型 | 在 FMM 中的行為 |
|---|---|
linear | 直接的線性插值 |
catmullrom | 平滑插值(緩入/緩出) |
bezier | 以固定的 0.42 / 0.58 控制點近似 —— FMM 不會讀取個別關鍵影格的貝茲控制桿 |
step | 吸附到前一個值,直到下一個關鍵影格 |
超出這組範圍的任何內容都會解析失敗,並被回報為格式錯誤的時間軸。
有動畫的通道
每個骨骼會烘焙三個通道:旋轉、位置與縮放。製作時值得注意的事項:
- 位置值會被除以 16(Blockbench 像素轉方塊)。
- 旋轉值會被轉換成弧度。
- Blockbench
format_version5 及以上會翻轉 X 與 Y 旋轉以及 X 位置的正負號。 FMM 會依據宣告的格式版本自動補償,因此請不要手動修正 —— 但也不要把 v5 的宣告與 v4 形式的資料混在一起。 - 某個通道上沒有關鍵影格的骨骼,會在該通道保持其靜止值;在某個 tick 完全沒有影格的骨骼,則會被重設為旋轉
0,0,0、位移0,0,0、縮放1,1,1。 - 關鍵影格資料點在
.bbmodel中可能被寫成字串。FMM 會把它們當成純數字解析 —— 空字串對縮放而言變成1,其他情況變成0;無法解析的內容會記錄Failed to parse supposed number value ...並變成0。Molang 運算式不會被求值。 - 每個關鍵影格只會讀取第一個資料點,因此 Blockbench 在 step 關鍵影格上分開的 pre/post 值會收攏成一個。
哪些東西不會有動畫
hitbox骨骼。指向它的動畫軌道會被直接略過。- Blockbench 效果軌道中的音效與時間軸指令關鍵影格。FMM 只會匯入效果軌道中的粒子關鍵影格;請參閱粒子。音效請改以 Lua 腳本或你自己的外掛播放。
- 無法依名稱解析的骨骼。指向不存在骨骼的軌道會記錄
Failed to get bone <name> from model <model>!並被略過。
逆向運動學(IK)
Blockbench 的空物件會作為 IK 控制器。FMM 在運行時以 FABRIK(Forward And Backward Reaching Inverse Kinematics)求解鏈,上限為 10 次迭代、容差為 0.001。
各部分如何搭配:
- 同時具有
ik_source(根骨骼)與ik_target(末端骨骼或定位器)的空物件定義骨鏈。偵測會檢查階層,也支援同層級及向下搜尋;根層級的同層目標會產生僅包含來源骨骼的骨鏈。 - 只有空物件的位置關鍵影格驅動 IK。每影格偏移會加到目標骨骼或定位器的靜止位置。執行階段求解器不會使用已儲存的控制器靜止位置作為目標基點,旋轉與縮放軌道也不驅動 IK。
- 每個 tick,目前動畫所關聯的 IK 骨鏈會接收目標偏移並求解。關聯骨鏈缺少該影格資料時會被清除。每次切換動畫以及呼叫
stopCurrentAnimations()時,都會清除所有骨鏈的 IK 旋轉,因此 IK 姿勢不會延續到下一個動畫。 lock_ik_target_rotation會被解析並儲存,但目前求解器不會套用它。
無法解析的鏈會被略過,並附帶一則具名的主控台警告 —— 確切訊息與製作限制請見模型製作注意事項。
Bedrock 匯出
每個被轉換的模型也會在產生的套件內寫入一份 Bedrock 動畫檔案,位於 animations/<model_id>.animation.json:
- 動畫識別碼為
animation.fmm.<model_id>.a_<hex>,其中<hex>是動畫名稱的 UTF-8 位元組以十六進位寫成的字串。因此,兩個只差在 Bedrock 不允許之字元的名稱,會得到不同的識別碼。 animation_length是以秒為單位的長度,下限為0.05,因此一個 tick 的動畫仍然有效。- 循環模式的對應方式如循環模式表格所示。
- 沒有任何動畫的模型仍會取得一個什麼都不做的
idle條目,讓 Bedrock 實體定義維持有效。 - 幾何體排除
hitbox、產生的fmm_nametag_bone_*名稱標籤骨骼及m_騎乘點,保留作者建立的tag_錨點。動畫匯出器寫入烘焙軌道時,不會套用相同的可見骨骼篩選,因此不要期待被排除的騎乘骨骼在播放動畫後出現可見幾何體。 - Bedrock 動畫匯出使用烘焙的骨骼旋轉、位置及縮放影格,不會將執行階段的 IK 求解結果寫入這些軌道。依賴 IK 的模型需要在 Bedrock 上個別驗證。
- 每個動畫都會產生一個動畫控制器,並由實體屬性切換,這就是 FMM 在 Bedrock 客戶端上播放特定動畫的方式。
- 粒子關鍵影格會成為該動畫的
particle_effects時間軸,讓 Bedrock 客戶端以原生方式播放。請參閱粒子。
關於該套件在磁碟上的位置,請參閱資源包輸出。
從其他系統播放動畫
| 呼叫端 | 進入點 |
|---|---|
| 外掛(Java) | ModeledEntity#playAnimation(String, boolean blend, boolean loop) / #stopCurrentAnimations() / #hasAnimation(String) |
| 道具 Lua 腳本 | context.prop:play_animation(name, blend, loop) / context.prop:stop_animation() |
| 任何 Lua 實體表 | entity.model:play_animation(name, blend, loop) / entity.model:stop_animations()(當 entity.is_modeled 為 true 時可用) |
相關介面請參閱 API 與開發者指南與 Lua:道具 API。
Lua 預設參數不同:context.prop:play_animation(name) 預設為 blend=true, loop=true,而 entity.model:play_animation(name) 預設為 false, false。如果這個區別會影響行為,請明確傳入兩個布林值。
疑難排解
我的動畫從來不會自動播放。
共用狀態機辨識小寫的 spawn、idle、walk、attack 與 death。移動驅動 idle/walk 切換,攻擊與死亡仍需對應的執行階段觸發。除了偽裝控制器額外選擇的名稱,其他名稱都需要明確呼叫 playAnimation / play_animation。
我的模型完全沒有動作。
它很可能既沒有 spawn 也沒有 idle 動畫,因此建立時不會進入任何狀態。請加上一個 idle。
我的動畫有播放,但什麼都沒動。 請檢查動畫長度。零長度動畫依設計會被視為靜態姿勢並被靜默略過。
旋轉是鏡像的。
請檢查 .bbmodel 中的 meta.format_version。FMM 會為格式版本 5 及以上翻轉 X/Y 旋轉的正負號;宣告某個版本卻攜帶另一版本資料的檔案,出來的結果就會是鏡像。
主控台顯示 Malformed animation timeline for model ...。
該動畫中有一條軌道無法被讀取或插值。這則警告在每個動畫只會出現一次,並指出牽涉到的骨骼或 IK 控制器;該模型的其他動畫仍會正常轉換。
我的 Blockbench 時間軸中的音效沒有作用。 音效關鍵影格不會被匯入。請改從 Lua 腳本或你自己的外掛觸發音效。粒子關鍵影格則會被匯入;若粒子沒有顯示,請參閱粒子。