ゲームプレイとモーションの依存について

ネットの記事や本では、取り上げられることはほとんどなく、新しいことでもないですが、製作が長期に渡ることが多い市販のゲームでは、重要になってくる部分なので、まとめてみました。ゲームのジャンルによって、認識が大きく異なってくる部分でもあるので、いろんな視点からご意見をいただけると非常に嬉しいです。

読者対象:モーションを使って、ゲームを作ったことがあるプログラマ

注:この記事内の用語について
・ゲームプレイ:ゲームスレッドで動く、入力・移動・コリジョン判定・スコア更新といった、ゲーム部分を指します。
・レンダリングスレッド:ゲームスレッドから結果を受け取り、モデルを描画するために、GPUに描画コマンドを送るスレッドです。
・モーション計算:モーションデータから骨の位置・回転データを取ってきて、骨の木構造に沿って計算をし、各骨の位置や向きを求める計算の部分です。
・アニメーション:この記事では、絵の部分だけを指します。
・ゲームデザイナー:この記事では、「レベルデザイナー」「企画」と読み替えてもらってかまいません。

1 はじめに


図1:格闘ゲームのパンチ

2Dのゲームでは、図1のように「移動・コリジョン判定」と「キャラクターアニメーション」は別であり、「キャラクターアニメーション」が「移動・コリジョン判定」に直接影響を与えることは、まずありませんでした。
その後、ゲームに3Dの技術が導入されると、「モーション」が現れました。「モーション」は、「移動・コリジョン判定」にも「キャラクターアニメーション」にも両方に使用できます。現実の世界では、これらは完全に一致します。例えば、パンチをすれば、手が移動し、手があるところにコリジョンがあり、手があるところに手が見えます。ここから
「『移動・コリジョン判定』と『キャラクターアニメーション』を一致させれば、ゲームはリアルになる」
という考えもでてきました。これ自体は問題なく、それを目指してうまくいっているゲームもあります。

しかし、「移動・コリジョン判定」=「キャラクターアニメーション」と理解し、これらの依存関係などを気にせずゲームをつくると、後で大きな問題を引き起こしてしまうことがあります。今回の記事では、それについて述べたいと思います。

2 モーションに依存する実装と依存しない実装

2.1 例1 「弾を詰めて、大砲をうつ」


図2:弾を詰めて大砲をうつ、モーションの1ループ

ボタンをおすと、図2のようにキャラクターが大砲に弾を詰めたのち、弾をうつという状況を考えます。

(A)ゲームプレイがモーションに依存している実装例

注:今後出てくる擬似コードは、ゲームプレイ側のコードです。モーションライブラリのコードではありません。

if (弾を詰めるモーションが終了している && Aボタンを押した)
{
	弾を発射
	弾を詰めるモーションを再生する
}

(B)ゲームプレイがモーションに依存しない実装例

t = モーションの長さ(時間)
if (モーション再生開始からt秒経過した && Aボタンを押した)
{
	弾を発射
	弾を詰めるモーションを、ちょうどt秒間で再生が終了する速度で、再生開始する。
}

これらは、ほとんど同じに見えますが、全然違います。(A)はモーション側に、モーションの再生終了を問い合わせるので、ゲームプレイがモーションに依存しています。それに対して(B)は、ゲームプレイ側からモーション側に時間を渡していますが、モーションからデータを受け取ることはなく、モーションの経過時間もゲームプレイ側で管理しています。
例えば、「弾をどんどん発射したい。」という要望があった場合、(A)は、モーションデザイナーがモーションデータを変更して、モーション再生時間を短くするでしょう。(B)は、プログラマーがtの値を減らすか、ゲームエディタでtが調整可能な場合は、ゲームデザイナーが変更することになるでしょう。

一見、役割がかわるだけで、あまり変わらないように見えますが、(B)にはメリットが多くあります。

2.2 (B)モーションに依存しない実装のメリット

モーションに依存しない実装のメリットを5つあげてみます。

(B)のメリット1 : ゲームバランスの調整がしやすい

ゲームデザイナーが自由にパラメータを変更できる(B)は、いちいちモーションデザイナーにモーションの長さの変更を頼む必要もなく、ゲームバランスの調整がしやすく、有利です。

(B)のメリット2 : モーションデザイナー・ゲームデザイナーともに、時間を有効に使える

ゲームプレイがモーションに依存している場合は、モーションデザイナーがモーションを変えると、ゲームバランスが変わってしまいます。これでは、ゲームバランスの調整をいったんしたとしても、モーションの変更でゲームバランスが崩れてしまうので、

「モーションデータの変更を締め切る」→「その後、ゲームデザイナーがゲームを調整」

という流れにせざるをえません。こうなると、

  • モーションデザイナーは、締め切りが早まってしまい、プロジェクトの締め切りギリギリまで、モーションを改善するということはできなくなる。
  • ゲームデザイナーは、モーションデザイナーがモーションを完成するまで、待つことになる(それ以前にもゲームバランスの調整はできるけど、無駄になる可能性もでてくる)

となり、双方とも時間を損します。

(B)のメリット3 : デバッグがしやすくなる。

モーションがゲームプレイに影響しないということは、モーションデータやモーションのソースコードが変わっても、ゲームへの影響はありません。例えば、

「もともと1秒おきに砲弾をうてたのに、なぜか10秒おきにしかうてなくなってしまった」

というバグが発生したとしましょう。(B)であれば、このバグは明らかにゲームプレイのバグなので、先ほどのコードの部分だけ確認すればデバッグは容易でしょう。しかし(A)だと、ゲームプレイのバグかもしれませんし、モーションデータがおかしいだけかもしれませんし、モーションコンバーターのバグかもしれません。デバッグで疑うべき部分が一気に増えてしまい、デバッグに時間がかかってしまいます。

(B)のメリット4 : 早回しができる

早回しとは、ゲームを通常の速度より高速に実行することです。これには様々なメリットがあります。

  • 同じ時間で、ゲームをより多く実行することができるので、ゲームプレイ部分のデバッグの際に有利。例えば、10msで動いてたゲームが、5msで動けば、バグ再現までの時間が半分になる。10時間に1回しか発生しないバグを、5時間に1回発生させることができる。
  • 対戦モードがあるゲームであれば、CPU同士の対戦時間を高速化することができる。この結果は、ゲームのバランス調整に使うこともでき、また、CPU同士の対戦を実際に行うシミュレーションゲームなどでは、そのまま使用することもできる。

(B)の場合はいっさいモーションの計算をせずにゲームを実行することが可能です。モーションの計算時間は、ゲームの処理時間の中でも大きな割合を占めることが多いです。モーションの計算時間を短くすることで、早回しの際に有利になります。

ちなみに、早回しをしたい場合は、ゲームスレッドだけを実行できる(グラフィックは無視する。もちろん垂直同期も待たない)必要があります。そもそも、その設計ができてないゲームエンジンを過去に見たことがあるので、気をつけてください。

(B)のメリット5 : 低スペックマシンへの移植がしやすくなる

スマートフォン・携帯ゲーム機・コンソール機・PC、マシンの性能はさまざまです。例えばPS3版で3Dポリゴンを使ってたゲームを、スマートフォンに移植することを考えます。スマートフォン版では2Dスプライトで表示、ただしゲームプレイはPS3版のまま変えたくないとしましょう。このとき、モーションに依存してないのであれば、スマートフォン版は単に2Dスプライトに置き換えれば終了です。しかし、モーションに依存した実装だと、スマートフォン版でも、モーション計算をせざるを得ず、処理落ちを起こしてしまうかもしれません。

2.3 (A)モーションに依存する実装のメリット

(A)にもメリットはあります。

(A)のメリット1 : モーション制御技術を必要としない。プログラマーが、モーション制御の技術を持ってなくても良い。

例えば、(B)の場合、「もともとt秒だったモーションを、s秒で再生する」という機能が必要になります。これはさすがに「再生速度を変更する機能を追加し、s/t倍速で再生する」だけで、まぁ良いでしょう。ただ今回のケースはもっとも単純で、実際にはモーション制御は、もっと難しいです。

(A)のメリット2 : 無理なモーション制御による、アニメーション品質の低下がおきにくい。

例えば、(B)の場合、ゲームデザイナーが、「0.3秒おきに砲弾を打てるようにしたい」とするかもしれません。これだけ短くなると、単に0.3/t倍速再生しただけでは、アニメーション的には、とても変になることが想像できると思います。
また、仮に1.1倍速で、ほとんど再生速度が変わらないといった場合でも、人間の動きはそんなに単純ではありません。速く動こうとすれば、動作自体も違ってきます。それであれば、1.1倍速用のアニメーションを、モーションデザイナーに作ってもらったほうが良いでしょう。
ただ、(B)でも、まずゲームデザイナーがいったん調整して、アニメーションの時間を確定したのち、モーションデザイナーにアニメーションを作ってもらうという風にすれば、問題はありません。

3 ゲームプレイ用のモーションデータを用意する方法

3.1 例2 「ボールをしゃがんで避ける」


図3:ボールをしゃがんで避けるゲーム

主人公の頭をめがけて、ボールがどんどん飛んできます。ぶつかったらゲームオーバーです。主人公は普段は動けませんが、ボタンを押すとしゃがんで避けることができます。タイミングよくボールを避けましょう。

(A2)ゲームプレイがモーションに依存している実装例

if (避けるモーションが終了している && Aボタンを押した)
{
	避けるモーションを再生する
}


現在の時間のモーションの骨位置を計算し、頭の位置を求める
if(頭の位置がボールと重なった)
{
	ゲームオーバーへ
}

さて、この例で、モーションに依存せずに、実装することはできるでしょうか?
「頭の位置を計算しないといけないから、モーションに依存するのは当たり前だろう」

と思うかもしれませんが、何個か対策はあります。

(B2.1) ゲームのルールを単純にする。

「Aボタンを押して、避けるモーションが再生している間は、無敵」としてしまいましょう。モーションはt秒間再生するということにします。それであれば、以下のような実装で済み、モーションに依存しません。

t = モーションの長さ(時間)
if (モーション再生開始からt秒経過した(=避けてない) && Aボタンを押した)
{
	避けるモーションを、ちょうどt秒間で再生が終了する速度で、再生開始する。
}

if((モーション再生開始からt秒経過した && もともとの頭の固定位置に、ボールがある){
	ゲームオーバーへ
}


ゲームによってはこれで良い場合もありますが、厳密ではありません。例えば、実際ボールが頭にかすってるように見えるのにもかかわらず、避けるモーション再生中ということで、ゲームオーバーにならないといった問題が起こりえます。また、ゲームが少し複雑になり、いろんなところにボールが飛んでくるようになったら、この方法ではうまくいきません。

(B2.2) 頭の位置yはゲームプレイ側で動かす。そして、モーションの頭の位置がyにくるようにモーションを制御する。

モーション経過時間uから、頭の位置yを決める(例えば y = 1.5+0.5*cos(u*2π); )
モーションを計算するスレッドに、頭の位置yを渡す
if(頭の位置yと、ボールが重なった)
{
	ゲームオーバーへ
}

この実装の問題としては、まず頭の位置をてきとーに三角関数で動かしてみましたが、実際は、これで人間っぽい動きでなくなってしまう可能性が高いです。普通、しゃがむときの頭の動きはもっと複雑です。
また、モーションを計算するスレッドでは、受け取った頭の位置yから、アニメーションを決める必要があります。ここでモーションの制御方法も、いくつかあります。

  • (1) 頭の位置yとモーションのマッピング(yごとに対応する姿勢を用意する)
  • (2) モーションブレンド(立っている姿勢と、しゃがんでいる姿勢のブレンド)
  • (3) IK(腰・足・頭を決め、その他の骨の位置をInverse Kinematicsで決める)

この例だと、どれもあまり旨くいかず((1)が一番マシかと思いますが…)、アニメーション品質は落ちる可能性が高いです。

つまり、(B2.1)ではゲームの質が下がる、(B2.2)ではアニメーションの質が下がる可能性があります。

3.2 ゲームプレイ用のモーション

(A)(B)とは違った別の解決方法もあります。

(C) ゲームプレイに使うモーションデータと、アニメーションに使うモーションデータを分け、ゲームプレイはゲームプレイ用のモーションデータにのみ依存する。

  • ゲームプレイ用のモーションは、ゲームプレイで使用する。
  • アニメーション用のモーションは、ゲームプレイでは使用しない。
  • ゲームプレイ用のモーションは、ゲームプレイに使う部位のデータだけを抽出。

つまり(A)(B)の中間のような解決策です。これは、最初に述べた2D時代の考え方に近いともいえるでしょう。今回の場合だと、ゲームプレイ用のモーションは頭の部分だけでよいです。頭の位置は、ルートからの相対座標として保存します。ゲームによっては、頭・腰・手先・足先のように、もうちょっと増えるでしょう。

アニメーションに使うモーションデータを変更したら、結局それにあわせてゲームプレイに使うモーションデータに合わせないといけないので、(A)と同じで意味がないように見えます。

しかし、ゲームプレイに使用するモーションの計算時間は、非常に短くなるため、(B)にあった

(B)のメリット4 : 早回しができる
(B)のメリット5 : 低スペックマシンへの移植がしやすくなる

といったメリットを少し持っています。

また、ゲームプレイ用のモーションに、アニメーション用のモーションを合わせるようなモーション制御をすれば、ゲームプレイで使うモーションデータとアニメーションに使うモーションデータを、完全に一致させる必要はありません。しかも、それらのデータは似ているはずなので、制御も(B)に比べたら難しくありません。つまり、ある程度なら、ゲームプレイに影響なくアニメーションも変更可能になるので、

(B)のメリット2 : モーションデザイナー・ゲームデザイナーともに、時間を有効に使える

というメリットも少しでてきます。
また、ゲームによっては、

(C)のメリット1 : ゲームプレイに使うモーションデータを、ゲームデザイナーによって編集させ、ゲームを改善させることができる

といったメリットもあります。例えば、格闘ゲームなら、パンチする位置を少し前にして、ゲームバランスがどうなるか試すといったかんじです。アニメーション用のデータにくらべデータは少なく単純で編集はしやすいし、そのためのツールを作ることも簡単でしょう。この場合、ゲームプレイのデータ変更が大きすぎると、アニメーションがおかしくなる可能性がありますが、ゲームが改善しているのであれば、ゲームプレイのモーションデータにあわせて、アニメーションを作り直して同期させるということも可能でしょう。

4 どの実装を選ぶべきか?

今まで述べてきたメリット・デメリットの重みは、製作するゲームの内容、ゲームの製作期間、メンバーの人数や能力によって全然違ってくると思います。

  • 小さいゲームや個人製作のゲームであれば、(A)で十分。(B2.1)のような手抜きも有効。
  • 長期のプロジェクト(続編など含む)であればあるほど、(C)が有利。
  • モーションデザイナーが多ければ優秀であれば、(A)が有利。
  • プログラマーがモーション制御が得意なら、(C)が有利


ゲーム内容で考えると、RPG等、移動が主体で、他のキャラや物体とのインタラクションが少ない場合は、(A)で良いと思います。格闘ゲームやスポーツゲームのように、物体とのインタラクションが多く、しかも(B)のような実装も難しい場合は、(C)を選ぶのが良いと思います。

また、(B)→(C)→(A)への変更は比較的簡単ですが、(A)→(C)→(B)の変更は難しい場合が多いです。こういった点も考慮にいれましょう。

5 関連トピック

5.1 ゲームプレイのプロトタイピング

ここでは、ゲームプレイのプロトタイピング=「単純にゲーム部分が面白いかどうか試すために、ゲームの簡易版をつくること」とします。

ゲーム開発の序盤ですので、そもそもモーションデザイナーがチームにいないということすらありえます。ここで、モーションなしで面白いゲームを作れたとします。

設計としては、既に(B)のモーションに依存しないゲームができているので、良いことではあるのですが、落とし穴もあります。あとでモーションを入れることを全く考慮せずにゲームを作った場合、
「プロトタイプでは面白かったのに、プロダクションに入り、モーションが入ったら面白くなくなった。」
というケースです。極端な話、一番最初の大砲の例で、
「モーションなしで、待ち時間0秒で、弾がバンバンうてて、気持ちいい!」
という実装にしたら、モーションを入れることができず、だからといって待ち時間を変えてモーションを入れたら、プロトタイプのときとゲームが変わってしまいます。プロトタイプとはいえども、モーション再生用の、現実的な待ち時間は考慮しましょう。

5.2 モーションを検索して動くAI

ゲームによっては、

「現在使用できるモーションを検索し、その中でベストなモーションを使用する」

ということをやりたくなる場合もあります。例えば、野球ゲームでフライを取ろうするとき、「ジャンピングキャッチ」「スライディングキャッチ」等のモーションの中から、タイミングよくフライが取れそうなものを検索する。検索結果によりAIの行動も決める。といった実装もできます。これが、人間の知能により近い考え方なのか、リアルな動きになるのか、ゲームとして面白くなるのか、これから議論されていくところです。

ただし、そういった議論以前に、この実装は、強くゲームプレイがモーションに依存しているということに注意してください。これで(A)のような実装をすると、モーションを検索するだけで莫大な時間がかかったりということもあります。最悪でも(C)のような形にするか、高速な検索方法を考える必要があるでしょう。

5.3 どのスレッドでモーションの計算を行うか

(A)であれば、ゲームスレッド側でモーションの計算をします。
(B)であれば、レンダリングスレッド側でモーションの計算をさせることもできますが、処理時間が足りなければゲームスレッド側で計算させるということも可能です。
(C)であれば、両方から呼び出すということがありえます。

XBOX360やPS3では、モーション計算用のスレッドを独立させるというのも有力な選択肢になります。逆にゲームスレッドとレンダリングスレッドが分けられないようなマシンもあるかとは思います。

ということで、どこでモーションの計算を行うかというのは、思ったよりも選択肢があります。モーションエンジンの部分は独立させて、柔軟に対応できるようにはしておきましょう。

6. まとめ

ゲームプレイとモーションの依存関係は、ゲームバランスの調整やデバッグ期間など、ゲームの品質に直接影響してくることがあるので、事前によく考えましょう。
また、モーション制御の技術は、「アニメーションの品質を改善する」「少ないアニメーション数で、多くのアニメーションをみせる」といった、グラフィック的な改善のためだけはなく、ゲームプレイとモーションの依存を減らすためにも使われます。制御技術を生かしましょう。