Roblox Animation Graphで「しゃがみ歩き+剣構え+銃構え」を1つのGraph IDで管理する考え方

Roblox StudioのAnimation Graph Editorを使って、
「しゃがみ歩き」と「剣構え」や「銃構え」を組み合わせるテストを行いました。

最初は、Animation Graph IDも通常のAnimation IDと同じように、
「1つのIDに対して1つの動きがある」という印象でした。
しかし実際に触ってみると、Animation Graphはそれだけではなく、
複数のAnimation Clipを内部に持ち、Parameterによって出力結果を切り替える仕組みとして使えることが分かりました。

今回のポイント
Animation Graph IDは、単なる「1本の完成済みアニメーション」ではなく、
複数のアニメーションを組み合わせるための制御装置として使うことができます。

通常のAnimation IDとの違い

通常のアニメーションでは、基本的に1つのAnimation IDに対して1つの動きを割り当てます。

CrouchWalkSword Animation ID
→ しゃがみ歩きしながら剣を構える動き

CrouchWalkGun Animation ID
→ しゃがみ歩きしながら銃を構える動き

この方式でも問題はありません。
ただし、Toolの種類や姿勢が増えると、必要なアニメーション数が一気に増えていきます。

CrouchWalkSword
CrouchWalkGun
CrouchWalkFlashlight
CrouchWalkPan

ProneSword
ProneGun
ProneFlashlight
PronePan

このように、姿勢とToolの組み合わせをすべて専用アニメーションとして作ると、
管理がかなり大変になります。

Animation Graphでの考え方

Animation Graphでは、すべての組み合わせを別々に作るのではなく、
動きを部品として分けて考えます。

Base Motion:
- SitWalk09
- CrouchIdle
- CrouchWalk
- ProneIdle
- ProneCrawl

Overlay Motion:
- SwordHold
- GunAim
- GenericToolHold

今回のテストでは、まずBaseとして「しゃがみ歩き」を置き、
その上に必要に応じて「剣構え」または「銃構え」を重ねる形にしました。

今回作ったGraph構造

今回のGraphの基本構造は次のような形です。

[ SitWalk09 Clip ]
        ↓
[ Sword Over ] ← [ SwordHold Clip → Mask ]
        ↑
   SwordWeight

        ↓
[ Gun Over ] ← [ GunAim Clip → Mask ]
        ↑
    GunWeight

        ↓
[ Graph Output ]

Graph Outputには最終的なPoseを1つだけ接続します。
そのため、Sword用とGun用をGraph Outputに並列で接続するのではなく、
Overノードを直列につなぐ形にします。

しゃがみ歩き
↓
剣構えを必要なら重ねる
↓
銃構えを必要なら重ねる
↓
最終的な見た目として出力

SwordWeightとGunWeightの関係

今回のGraphで重要になるのが、次の2つのParameterです。

SwordWeight
GunWeight

これは、剣構えと銃構えをON/OFFするための数値です。

0 = 無効
1 = 有効
状態 SwordWeight GunWeight 結果
Toolなし 0 0 しゃがみ歩きだけ
Sword装備中 1 0 しゃがみ歩き+剣構え
Gun装備中 0 1 しゃがみ歩き+銃構え
SwordとGunが両方有効 1 1 剣構えと銃構えが重なるため、基本的には避ける
注意点
SwordWeightとGunWeightを同時に1にすると、
剣構えと銃構えが両方重なってしまいます。
基本的には、コード側で一度すべて0にしてから、必要なものだけ1にするのが安全です。

コード側での切り替えイメージ

Animation Graph側では、SwordWeightとGunWeightのParameterを用意します。
そしてゲーム中のコード側で、現在装備しているToolの種類に応じて値を切り替えます。

track:SetParameter("SwordWeight", 0)
track:SetParameter("GunWeight", 0)

if toolType == "Sword" then
	track:SetParameter("SwordWeight", 1)
elseif toolType == "Gun" then
	track:SetParameter("GunWeight", 1)
end

このようにすることで、同じAnimation Graph IDを再生したまま、
内部のParameterだけを変更して見た目を切り替えることができます。

Toolの判別にはAttributeを使う

Animation Graphは、Toolが剣なのか銃なのかを自動で判断するわけではありません。
その判別はコード側で行います。

今回の方式では、ToolにAttributeを追加して判別する方針にしました。

Sword Tool:
MotionToolType = "Sword"

Gun Tool:
MotionToolType = "Gun"

AttributeはString型で統一します。
これにより、コード側ではToolのAttributeを読むだけで、
どのParameterを有効にすればよいか判断できます。

local toolType = tool:GetAttribute("MotionToolType")

if toolType == "Sword" then
	track:SetParameter("SwordWeight", 1)
elseif toolType == "Gun" then
	track:SetParameter("GunWeight", 1)
end

全体の処理フロー

今回のシステム全体の流れは、次のようになります。

┌──────────────────────────────┐
│ Tool                          │
│ Attribute                     │
│ MotionToolType = "Sword"      │
│ MotionToolType = "Gun"        │
└───────────────┬──────────────┘
                ↓
┌──────────────────────────────┐
│ LocalScript                    │
│ 装備中Toolを確認               │
│ MotionToolTypeを読む           │
└───────────────┬──────────────┘
                ↓
┌──────────────────────────────┐
│ Animation Graph Track          │
│ SetParameterで値を送る          │
│ SwordWeight / GunWeight        │
└───────────────┬──────────────┘
                ↓
┌──────────────────────────────┐
│ Animation Graph                │
│ SitWalk09                      │
│ + SwordHold or GunAim          │
└───────────────┬──────────────┘
                ↓
┌──────────────────────────────┐
│ Player Motion                  │
│ しゃがみ剣 / しゃがみ銃          │
└──────────────────────────────┘

Graph内の構図

Graph Editor内で見る場合は、次のような構図になります。

                 SwordWeight
                      ↓
SwordHold Clip → Mask → Sword Over
                         ↑
SitWalk09 Clip ──────────┘
                         ↓
                 GunWeight
                      ↓
GunAim Clip → Mask → Gun Over
                         ↑
Sword Over Output ───────┘
                         ↓
                  Graph Output

この構図で重要なのは、Sword OverとGun Overを別々にGraph Outputへつなぐのではなく、
Sword Overの出力をGun OverのBaseへ入れ、最後にGun OverをGraph Outputへつなぐ
という点です。

この方式のメリット

  • しゃがみ剣、しゃがみ銃などを別々のAnimation IDとして作らなくてよい
  • 1つのAnimation Graph IDの中で、複数の状態を切り替えられる
  • Toolの種類が増えても、Parameterを増やすことで対応しやすい
  • Maskを使うことで、下半身はしゃがみ歩き、上半身だけ剣構えや銃構えにできる
  • アセット販売用のシステムとして、内部のアニメーション制御を整理しやすい

注意点

この方式は便利ですが、すべてのケースで万能というわけではありません。

  • GraphはToolの種類を自動判別しないため、コード側で判別が必要
  • SwordWeightとGunWeightを同時に1にすると、両方の構えが重なる
  • キックや回転斬りのような全身を大きく使う動きは、専用アニメーションの方が自然な場合がある
  • Graphが複雑になりすぎると、管理が難しくなる

今後の発展案

今回のGraphは、しゃがみ歩きに剣構えや銃構えを重ねる基本形です。
今後は、さらに次のような拡張が考えられます。

CrouchIdle
CrouchWalk
ProneIdle
ProneCrawl

SwordHold
GunAim
GenericToolHold
TwoHandHeavyHold

このように増やしていくと、1つのAnimation Graphの中で、
しゃがみ、匍匐、Tool構えなどをまとめて管理できるようになります。

ただし、何でも1つのGraphに入れすぎると複雑になるため、
実際の商品化では「ステルス移動用Graph」「戦闘用Graph」「Tool構え用Graph」のように、
ある程度用途ごとに分けるのも良さそうです。

まとめ

今回のテストで、Animation Graphは単なるAnimation IDの代替ではなく、
複数のAnimation Clipを組み合わせるための制御システムとして使えることが分かりました。

特に、今回のように、

しゃがみ歩き
+
剣構え
+
銃構え

のような複数状態を扱う場合、Graphを使うことで、
すべての組み合わせアニメーションを個別に作る必要がなくなります。

SwordWeight = 0
GunWeight = 0
→ しゃがみ歩き

SwordWeight = 1
GunWeight = 0
→ しゃがみ歩き+剣構え

SwordWeight = 0
GunWeight = 1
→ しゃがみ歩き+銃構え

このように、1つのGraph IDを再生しながら、Parameterで見た目を切り替えることができます。

Animation Graphは、しゃがみ、匍匐、武器構え、Tool構え、移動中の上半身動作など、
複数の状態が重なるシステムと相性が良いと感じました。