懶人包
- 香港獨立開發者零零(@00vchannel)在 2026-10-17 發了一篇 Threads:花一週讓角色走樓梯時每一步都踩在階上,標竿是《絕區零》。到 2026-10-25 這篇有 1.9 萬次瀏覽、440 讚。
- 沒有腳步 IK 時,角色上樓腳會插進階梯、下樓腳會懸空。我用 POC 統計,階高 22 時上樓的不良樣本 373 筆是插入、下樓 360 筆是懸空。
- 腳步 IK 拆成四步:射線找落點、挪到踏板中央、兩段骨 IK 解膝蓋、骨盆往較低的腳下沉。
- 我用單一 HTML 檔重做成對照實驗,模擬 20 秒、階高 22:腳底誤差從 4.22 px 降到 0.32 px,支撐不良從 32% 降到 5%。
- 逐項關閉的結果:關踏板吸附誤差回到 1.81 px,關骨盆下沉回到 1.77 px、支撐不良升到 14%。骨盆下沉的效果要有下樓的場景才量得出來。
- 要做進遊戲,Unity 和 Unreal 都有現成的 foot placement 方案可用;這個 POC 的用途是看懂原理。
一篇「浪費時間」的貼文為什麼有 1.9 萬次瀏覽?
2026-10-17,香港的獨立開發者零零(Threads 帳號 @00vchannel)分享了一段影片:自己的遊戲角色走上一段樓梯,每一步都踩在階面上。他在原貼文裡這樣寫:
分享一下做了一週的角色腳步走樓梯功能~ 其實我的遊戲好像也沒有特別需要走樓梯的功能,但是看到《絕區零》的角色腳步可以完美配合樓梯,真的很想嘗試一下。我都不知道我浪費時間在這些幹什麼?哈哈~
我在 2026-10-25 查的時候,這篇有 1.9 萬次瀏覽、440 讚、33 則留言。留言裡有人說「Ik 算很久喔」,也有人問「好想知道怎麼做到的」。零零目前在做獨立遊戲《異世界港V》和《異世界潛行者》,個人頁寫預計 2026 年底上架。
這是一個玩家多半說不出哪裡不對、開發者卻很在意的細節。他沒有公開程式碼,《絕區零》怎麼做的我也找不到官方資料,所以這篇不猜他們的實作。我做的是另一件事:把通用的腳步 IK 拆開,用瀏覽器做一個能逐項關掉的對照實驗,看每一步各自貢獻多少。
沒有腳步 IK,角色走樓梯會怎樣?
一般的角色控制器用一顆膠囊體貼著地面走。膠囊體跟著腳下的地面高度升降,腿則播一段在平地錄好的走路動畫。平地上兩者對得起來,到了樓梯就對不起來了:動畫裡的腳以為地面是平的,實際上每隻腳底下的高度都不一樣。
我在 POC 裡統計了沒有 IK 那組的錯誤方向。階高 22、模擬 20 秒,支撐期腳底標紅的樣本裡:
| 區段 | 腳插進階梯 | 腳懸空 |
|---|---|---|
| 上樓 | 373 | 64 |
| 下樓 | 84 | 360 |
腳步 IK 怎麼做?四個步驟
Vulkan 官方教學〈Foot Placement on Uneven Terrain〉把不平地形的腳步放置整理成每幀依序執行的流程:從每隻腳上方往下打射線、對命中點做時間上的平滑、把骨盆往下移到夠得著較低的那隻腳、再用 IK 解腿並讓腳掌貼合地面法線。
我的 POC 是 2D 的樓梯,踏板都是水平面,所以用的是這套流程的簡化版:
| 步驟 | 做什麼 | 解決什麼 |
|---|---|---|
| 1. 射線找落點 | 擺動腳出發時,往前一個步幅處向下打射線,拿到那裡的地面高度 | 腳要落在哪一階 |
| 2. 踏板吸附 | 落點在樓梯範圍內,就挪到該階踏板中央 | 避免腳跟踩空、腳尖頂到下一階 |
| 3. 兩段骨 IK | 已知大腿長、小腿長、髖和踝的位置,用餘弦定理解出膝蓋角度 | 腿長固定,膝蓋自己彎到對的角度 |
| 4. 骨盆下沉 | 骨盆高度跟著較低的那隻腳走(擺動中的腳用它的落點算) | 低的那隻腳伸得到地 |
第 3 步不需要通用的 IK 解法。腿只有大腿、小腿兩段,髖、膝、踝構成一個三角形,三邊長都知道(第三邊是髖到踝的距離),膝蓋角度用餘弦定理一次算出來。Vulkan 教學用的是 CCD 或 FABRIK 這類迭代解法,那是為了處理更多節骨頭的鏈;兩段骨用解析解就夠了。POC 裡這段只有幾行:
function solveIK(hip, target) {
const dx = target.x - hip.x, dy = target.y - hip.y;
const d = Math.min(Math.max(Math.hypot(dx, dy), 1e-3), LEG - 0.01);
const base = Math.atan2(dy, dx);
const cosA = (THIGH * THIGH + d * d - SHIN * SHIN) / (2 * THIGH * d);
const a = Math.acos(Math.max(-1, Math.min(1, cosA)));
const knee = { x: hip.x + THIGH * Math.cos(base + a), y: hip.y + THIGH * Math.sin(base + a) };
const ankle = { x: hip.x + d * Math.cos(base), y: hip.y + d * Math.sin(base) };
return { knee, ankle };
}
d 被夾在腿長以內。目標點太遠時,腿會打直、踝停在伸得到的最遠處,不會被拉長。這個限制後面量測時很重要。
對照實驗怎麼做?
POC 是一個不用安裝任何套件的 HTML 檔,畫面上下兩組角色走同一段樓梯,先上 5 階、走一段平台、再下 5 階:
- A 組(沒有 IK):身體跟著腳下地面高度走,腿播平地走路動畫。
- B 組(腳步 IK):四個步驟全開。
腳底那一小段會變色:支撐期的腳如果超過 15% 的取樣點離地面超過 2 px,就畫成紅色,否則綠色。
量測方式是這樣:只量支撐期(腳應該踩在地上的時候),沿腳底每 1 px 取一個點,算腳底高度和地面高度的差。統計兩個數字:
- 腳底接觸誤差:所有取樣點的平均高度差,單位 px。
- 支撐不良:誤差超過 2 px 的取樣點比例。
window.simulate(mode, seconds),用固定步長跑模擬、不畫圖,結果不受瀏覽器幀率影響。每組跑 20 秒、dt = 1/120。
結果:四個步驟各貢獻多少?
| 情境 | 無 IK 誤差 / 支撐不良 | IK 誤差 / 支撐不良 |
|---|---|---|
| 階高 8 | 1.53 px / 23% | 0.27 px / 5% |
| 階高 22 | 4.22 px / 32% | 0.32 px / 5% |
| 階高 34 | 6.52 px / 36% | 0.39 px / 6% |
| 階高 22,IK 關閉踏板吸附 | — | 1.81 px / 8% |
| 階高 22,IK 關閉骨盆下沉 | — | 1.77 px / 14% |
幾個讀法:
- 階越高,沒有 IK 越糟。誤差從 1.53 px 一路漲到 6.52 px,有 IK 的那組則一直壓在 0.4 px 以下。
- 關掉踏板吸附,誤差回到 1.81 px。腳落在階緣附近時,腳底有一段懸在空中。
- 關掉骨盆下沉,誤差 1.77 px,支撐不良升到 14%,是兩個開關裡傷得最重的。下樓時骨盆不先降,低的那隻腳伸不到地,IK 只能把腿打直、踝停在半空。
量測過程修正了兩次
第一次:量的位置。 第一版直接拿 IK 的目標點去比地面高度。目標點本來就是射線打到的地面,所以 IK 組的誤差恆為 0,等於什麼都沒量到。改成量 IK 實際解出來的踝位置後,腿伸不到的情況才會反映在數字上,這也是前面 d 被夾在腿長以內的原因。
第二次:場景只有上樓。 原本的樓梯只往上走。上樓時骨盆的平滑會自然落後,身體比腳低,腿怎樣都伸得到,關掉骨盆下沉也看不出差別。補上下樓之後,關掉骨盆下沉的誤差才跳到 1.77 px。
兩次修正的共同點:量測要能量到「失敗」,數字才有意義。一個永遠回報 0 的指標,跟沒有指標一樣。
78 秒看完四個步驟
同一個實驗剪成了一支直式短片,用吉祥物當角色,依序講問題、四個步驟和數據:
這個 POC 沒處理什麼?
- 只有 2D、水平踏板。 沒做腳掌依地面法線旋轉,斜坡和不規則地形不在範圍內。
- 只有走路。 零零的貼文底下就有人接著問「再來是樓梯奔跑與跳躍」,這兩種情況步幅和節奏都不同,POC 沒有涵蓋。
- 前提是樓梯碰撞體是一階一階的。 有 Skyrim 模組作者在開發紀錄裡提到,如果樓梯的碰撞體做成一個斜坡,射線打到的是斜面,樓梯 IK 就失效了。要做腳步 IK,得先確認樓梯的碰撞體是一階一階的。
- 不是遊戲引擎套件。 Unity 和 Unreal 都有現成的 foot placement 做法與討論,例如 Unity 論壇的 FOOT PLACEMENT IK 官方討論串、Unreal 論壇的 Foot placement。要放進遊戲,從引擎現成的方案開始比較實際。
想自己動手的話
- 打開 html.yanchen.app/stairs-foot-ik,先把階高拉到最高,看 A 組下樓時的腳。
- 關掉「骨盆下沉」,看 B 組下樓時腿怎麼打直、腳懸在半空。
- 再關掉「踏板吸附」,看腳落在階緣的樣子。
- 要看程式,右鍵檢視原始碼,
solveIK、stepIK、footContact三個函式就是全部的核心。
常見問題
腳步 IK 是什麼?
IK 是 inverse kinematics(反向運動學)。一般動畫是給每個關節角度,算出腳在哪裡;IK 反過來,先決定腳要踩在哪裡,再算出膝蓋和髖要怎麼彎。腳步 IK 就是讓角色的腳貼合實際地形,而不是照著平地錄的動畫走。
為什麼走樓梯特別難?
樓梯每一階的高度是跳躍式的,兩隻腳常常踩在不同高度,腳也可能落在階緣。我的 POC 裡,沒有 IK 時上樓腳插進階梯、下樓腳懸空,兩種錯誤方向相反,只調整整個角色的高度修不好。
骨盆下沉為什麼這麼重要?
腿長是固定的。下樓時如果骨盆不先往下,低的那隻腳到地面的距離超過腿長,IK 只能把腿打直,腳停在半空。實驗裡關掉骨盆下沉後,支撐不良從 5% 升到 14%。
兩段骨 IK 一定要用 FABRIK 或 CCD 嗎?
不用。大腿和小腿只有兩段,髖、膝、踝是一個三邊長都已知的三角形,用餘弦定理就能直接解出膝蓋角度。FABRIK、CCD 這類迭代解法適合更長的骨鏈,例如觸手或尾巴。