Unity を検索

究極のデザインレバー、アニメーションカーブ

2022年7月21日 カテゴリ: ゲーム | 27 分 で読めます
A white truck going down on a forest road, all made in Unity editor
A white truck going down on a forest road, all made in Unity editor
取り上げているトピック
シェア

Is this article helpful for you?

Thank you for your feedback!

Christo Nobbs によるゲームデザイナー向けのブログ記事の第 3 弾です。このシリーズは、「The Unity game designer playbook」で彼が担当した内容を発展させたものです。このプレイブックはゲームデザイナーが Unity でゲームプレイのプロトタイプ、制作、テストを行う方法について解説した、100 ページを超える詳細なガイドです。Christo が執筆した過去のブログ記事へのリンクは、本記事の最後に掲載しています。

Unity では、データの保存に使用できる「タイプ」がいくつかあり、システムバランス、ゲームプレイ、キャラクター設定、乗り物のプロファイルなどに使える、デザインレバーと同じくらい有益なものです。アニメーションカーブはそのようなコンポーネントタイプの 1 つで、ゲームデザイナーやクリエイターが、特にプロトタイピングを行うときに興味深く感じる機能を提供します。これはプロジェクト内部で使用するもので、例えば、パーティクルシステムに使ってアニメーションの変数を制御したり、オーディオソースコンポーネントでロールオフやその他のプロパティを管理したりするために使うことができます。

曲線(カーブ)とは、入力(X 軸)の値を変化させたときの応答(Y 軸)を示す折れ線グラフのことです。Unity では、特にアニメーションにおいて、さまざまな文脈でカーブが使用されています。Curve エディターには、さまざまなオプションやツールが用意されており、それらを活用することができます。

この記事では、変数型 AnimationCurve を使用して、Unity API によるアニメーションカーブの操作に焦点を当てます。このように、データを取り込んで保存することで、結果の分析に役立てることができるのです。カーブは ScriptableObject とも互換性があり、先に紹介したプレイブックで説明されているように、ゲームプレイデータを編集するのに適しています。

アニメーションカーブは、公開の変数であるとき、またはシリアル化された状態であるときは、インスペクター内で編集することができます。編集モードまたは実行時に、保存、エクスポート、読み込みができます。編集可能な接線により、キーとキーの間のカーブの形状を制御することが可能です。

An Animation Curve property in the Inspector
インスペクターのアニメーションカーブプロパティ。クリックすると Curve エディターが開き、カーブを調整したり、歯車のアイコンを選んで自分のライブラリに保存したりすることができる。
A tangent's key in Unity
カーブをダブルクリックすると、そのカーブを操作するための新しいキーが作成され、キーのハンドルを制御するためのいくつかのオプションも提供されます。

キーの追加、接線の変更、カーブ内のハンドルの操作により、カーブを思い通りの結果を返す形状に仕上げることができます。

An Animation Curve with multiple tangents
有機的な山や谷、急角度を表現する接線を含むアニメーションカーブ

日常の動きや動作に生きているようなディテールを加える

アニメーションカーブのような視覚的なデザインレバーがあれば、ゲームデザイナーは複雑な数学を扱ったり、イージング関数を記述することなく、ゲームプレイを微調整することが可能になります 。 

アニメーションカーブの使い方として、タイムラインで直線的な動きにニュアンスやディテールを加えるというものがあります。例えば、キャラクターが車のドアを閉めたとき。ドアを閉めるために手がレバーをつかみ、ドアがグラグラするところから動きが始まります。最初はゆっくりとドアが閉まりはじめ、ドアが閉まるにつれて動きが速くなり、最後は小さなバウンドやカチッという音を立てて、急に動きは止まります。これらの動きをすべて、シーケンスで使う同じカーブ内に保存することができます。

A brown door opening and closing on a green gar in the Unity editor
アニメーションのタイムライン上でカーブを用いて開閉するドア
The curve for opening a door
ドアを開けるカーブ
The curve for closing a door
ドアを閉めるカーブ

この例からわかるように、アニメーションカーブはオブジェクトのプロパティを時間経過とともに変化させ、自然な動きを作り出すのに有効です。他にも、物体の移動や回転、走っているキャラクターの加速や減速、エンジンから自動車のコントローラーへの動力伝達など、様々な用途で活用されています。

Animation curve C# code
インスペクターのアニメーションカーブが、X 軸の任意の位置で Y 軸のデータを返す仕組みについては、こちらの概要をご覧ください。下のメソッドは、目的の曲線と位置を渡して EvaluateCurve メソッドを使用する方法を示しています。

アニメーションカーブを作成してインスペクターで編集する場合、パラメーターを渡すことでカーブを評価することができます。Unity では、このパラメーターは time と表されています。この記事の後半で、時間に対応する X 軸を使わない場合、なぜ位置がより記述的になるのかについて見ていきます。

エンジン出力を制御するための「擬似」モータートルクカーブ

ここではアニメーションカーブを使って、自動車のエンジンの出力を制御する方法を考えてみましょう。現在のエンジン回転数(RPM:1 分間あたりの回転数)をもとに、自動車にかかる力を返す「擬似」モータートルクカーブを作成することができます。これは、プレイヤーがアクセルを踏み込むと時間経過とともに増加します。

各ギアや自動車の回転数の範囲をすべてマッピングするのではなく、回転数を 0 〜 1 の間で「正規化」することができます。作成した「トルク」カーブは保存して、他の車やギアに再利用することが可能です。

この値は生の値または現在の値を最大値で割って設定します。

normalisedCurrentRPM = currentRPM / maxRPM

出力の力(Y 軸)も 0 〜 1 の間で使用し、Curve エディターを管理しやすくし、カーブ自体も再利用できるようにします。この値を自動車を動かす力に加えることで、自動車のリジッドボディを Z 軸方向に前進させることができる。

An example script to normalize the RPM
以下は、回転数を「正規化」し、与えられた回転数でのトルク曲線の Y 値にエンジンの出力を掛けたものを基に力を加えるスクリプトの例です。

他の車種でも同じ設定で、カーブ上の (0, 0) と (1, 1) の値の間に留まることで、さまざまな結果を作り出すことができます。

An upwards green curve
この曲線は、車体が動き始めると安定した出足になるが、ピークパワーになるとエンジンの出力をロスしてしまうため、適切な位置でギアチェンジをするのが適当であることをプレイヤーに伝える。

自動車のエンジンに基本的なギア比の方程式を加えることで、ギアを回して異なる出力のカーブを描いたり、同じカーブを異なるポイントで描いたりして、リアルな車の動きや揺れを表現することができるのです。そのためには、車がリジッドボディであることが必要です。トランクや後部座席に他のリジッドボディを追加すると、自動車の動きがそれに影響され、時間制限のある配送ミッションなどで使うと面白いでしょう。

カスタムの自動車のコントローラーを使用していて、Unity の物理システムを使用したくない場合は、追加のリジッドボディを積んでいない場合のカーブと積んだ場合のカーブをそれぞれ作成し、実行時にこれらのカーブを入れ替えることで、車両を思い通りに走らせることが可能です。

頻繁に使うことはないと思われますが、Unity API を使って、実行時にキーを追加したり、キーを修正したり(この操作は新しいキーを削除したり追加したりすることで実現します)、キーをカーブ上で完全に削除したりすることができます。 これにより、カーブの修正をより自由に行えるようになり、必要に応じて接線のスムージングを行うこともできます。

Curves for a heavy vehicle, such as a truck with automatic gears that starts up slowly but then doesn’t lose power after reaching peak RPM: This curve shows the truck without a load.
自動変速機付きのトラックのように、ゆっくりと始動し、ピーク回転数に達した後も出力を失わないような重い自動車のカーブ。この曲線は無負荷の状態を示しています。
This curve shows a truck with a heavy load. By adding another key and a power reduction after the vehicle has started moving, you can make the truck feel like it has a drawn-out second gear, for instance, giving it more personality.
一方、この曲線は、重い荷物を積んだトラックを表す。動き出した後にもう 1 つキーを追加して出力を下げることで、例えば 2 速の区間を引き伸ばすような感覚で、トラックに個性を持たせることができる。
A single curve for a vehicle that has multiple gears
多段ギアを持つ車両を単一のカーブで表したもの。ギアボックスを持つエンジンシステムを実装せずに自動ギアを持つような感覚を出せる。この曲線は 2 速、3 速、4 速で大部分の出力がなされており、3 速、4 速、5 速は長いギアで、5 速の区間で最高速度に達するまでしばらく続く。さまざまな接線を使って、目的の結果を作り出している。

アニメーションカーブを使えば、複雑なシステムをうまく抽象化して視覚的に制御できます。エンジンの例では、上図のようなカーブ(擬似的なギアボックスを表す)で加速する際に時間をかけて出力をかけ、出力が供給されるとピッチを上げ、各ギアのトップで出力が切れると再び下げるという、自動車のギアチェンジの感覚を作り出すことができます。これは、1 速の開始点 x0,y0 から 5 速の最高到達点 x1,y1 まで、すべてのギアをマッピングした 1 本のカーブに自動車の出力をすべて乗せることで、自動車の動きのプロトタイプを作るのに適しています。

回転数は通常、加速する際に時間とともに蓄積されるため、基本的には、移動する物体に直線的な動きを加えるように、時間経過に合わせて値をプロットすることになります。これについては、「Game designer playbook」のタイミングとアニメーションに関するセクションをお読みください。

Three futuristic looking cars are racing on a large grid road with neon blue lights surrounding the road
「擬似」物理は、Unity で作られた近未来世界を舞台としたレースゲーム『Antigraviator』のように、現実の物理法則に従わない動きをするゲームで有効に使える。

上記は他にも、例えば、自動車が不整地を走るとき、コーナーを曲がるとき、あるいは車輪に動力を供給するときのサスペンションと動きなどに使えます。ステアリングの改善、横力の制御、タイヤのスリップなど、すべてアニメーションカーブで管理することで、洗練されたリアルな動きを視覚的な操作で作り出すことができます。

作るものがホバービークルでも車輪付きでも、乗り物にレイキャストベースの仕組みを入れる場合、エンジンに「サスペンション」の効果を作り出すために、各レイに上向きの力をかけ、PID(比例-積分-微分)制御アルゴリズムで跳ね返りを制御するか、場合によってはフックの法則でダンピングするという方法がよく使われます。この手法の使用例は、Unity の「Hover Racer Live 7/21 Cycle 4.2」で見ることができ、この記事のさらに後で紹介する、このサンプルをベースにした PID を使った例と併せて見ることができます。

PID 制御アルゴリズムは、制御ループのフィードバック機構、つまりコントローラーで、ゲーム開発をはじめ多くの産業で、応答性の良い補正が必要な場合に使用されています。PID 制御は、測定されたプロセス変数と所望の目標値との差として誤差値を計算し、弾性体との関係では(あるいは私たちの与えられた例では)フックの法則の代わりとして使うことができます。ゲームでの PID も実用的です。以下のようなユースケースがあります。

  • 積載重量やプレイヤーの入力、地形の角度などの影響を予測不能に受ける環境で、自動車に巡行制御モードで目標速度を維持させる。
  • 敵の AI エージェントがプレイヤーに反撃する際の精度を制御しながら、プレイヤーは被弾しないようにする。
  • マルチプレイヤーゲームにおけるレイテンシ予測。

PID はゲーム開発のあらゆる場面で利用でき、特にサンドボックスやシミュレーションでは、「正確で最適化された自動制御」が必要とされます。Squad の『Kerbal Space Program』では、PID を使って宇宙船を 1 つの方向に向かわせます。

この研究によると、ゲーム開発以外では「PID 制御は連続システムの中で最も成熟し、広く使われている技術」であるとのことです。さらに知りたい方は、こちらの「Control System lecture: Introduction to PID control」(英語)を参照してください。

A space rocket is in a hangar, with an interface open on the left, showing customization options for the rocket
Steam で配信されている Squad の『Kerbal Space Program』では、PID 制御アルゴリズムが採用されている。

PID 制御のアルゴリズムは作るのにそれほど時間がかからないかもしれませんが、バランスをとるのに時間がかかります。その時間は制御する乗り物の数に比例して長くなります。しかし、プロトタイピングの時には、アニメーションカーブを代わりに使用することで、時間を節約したり、複数の PID 制御を実装してバランスをとるという技術的な課題を回避することができます(最終的には、カーブによるソリューションを PID に置き換えて完璧な制御を実現したくなるでしょう)。

カーブは、視覚的な操作で実世界における目標となる参照例との一致を探るために使えるため、プロトタイピングに最適です。空間に関して言えば、これはゲームエンジンでは「数学的に完璧」なことで、反力は、別途追加するか、デフォルトの重力を有効にしない限りかかりません。そのため、単純なカーブを使った方が変化を制御しやすく、頑健な結果が得られることが多いのです。

自動車のサスペンションを作る場合、PID 制御で減衰を作るのではなく、スプリングの圧縮レベルに基づいて、どれだけの反力を適用するかをアニメーションカーブで知らせることができます(0 と 1の間で正規化)。リジッドボディと小さな摩擦を組み合わせることで、跳ねるときの振動を抑制し、負荷の増減にサスペンションが反応するようにします。

スプリングの圧縮率を求めるには、スプリングの長さからレイヒット距離を 1.0f から差し引く必要があります。長さに関係なく、スプリングが 25% 圧縮のとき、圧縮値は 0.25 となります。この圧縮の値をアニメーションカーブの X 値として設定し、(規格化された値で作業しているので)想定しているスプリングの力を掛け、AddForceAtPosition で使用して、ループ内の各ポイントで、サスペンション点の数に基づいて上向きの力を適用します。Unity のデフォルトの重力(-9.81f)以外には、下向きの力を加える必要はありません。

計算式は以下のようになります。

upwardsForce = forceMultiplier * forceCurve.Evaluate(springCompressionNormalized);

rigidBody.AddForceAtPosition(hitNormal * upwardsForce, point.transform.position);

質量の力の比として 13:110 を使い、下のカーブを使用している。

A white van without wheels falling down on a road in front of a forest, in Unity
サスペンションの長さを伸ばした(スプリングの長さを 1m に設定)車輪のないバン。傾いて落ちるバン、まっすぐ落ちるバン、前後に揺れるバンの例を示す。
A double sigmoidal curve
ダブルシグモイドに似たカーブ。最初の短い位相が逆カーブで、2 番目の位相の始まりでわずかに負に傾斜したカーブになっている。X 軸 = 正規化されたスプリングの圧縮、Y 軸 = 出力(0 ~ 1)として描いた力のカーブは、落下するリジッドボディ(上の動画のバン)に減衰を与え、サスペンションのシミュレーションを行うために使われる。

質量、上向きの力、振動を抑えるための小さな線形抗力と角抗力を適切に設定することで、約 50% の圧縮で車体が沈んだ状態になります。これにより、極端に高いところから落としたり、プレイヤーが質量を増やして過負荷にならない限り、車体が跳ねたり沈んだりすることはあっても、底付きすることはないのです。

良い値を見つけるには、y = b^x の曲線(円を 4 分の 1 にしたものに似ている)から始めるとよいでしょう。摩擦を低く抑え、自動車の質量を現実のものに合わせて設定しましょう。その後、スプリングの圧縮率が 50% 程度になるまで、上方向の力を調整します。何度か車を落として底付きしていないか、跳ねた後の沈み具合を確認します。この考え方を、各点でトラクションの増減がある不整地を走る車のサスペンションに用いることで、素早く制御可能なサスペンションシステムを実現することができるのです。

サスペンションモデルにアニメーションカーブを使用することで、普通の自動車だけでなく、サスペンションの悪いバンやトラック、つまりいつも底付きしている車や、アーケードゲームのように跳ねる車、コーナーでロールして加速やブレーキでふらつく車など、自動車のさまざまなモーションを作り出すことができます。カーブは、Unity のリジッドボディシステムや独自のサスペンション方式を使用していない場合、既存のシステムと組み合わせて使用することができます。カーブを使ってステアリングを操作したり、エンジンの出力、サスペンション、摩擦、タイヤのスリップ、ブレーキ力などを増幅させたりすることが可能です。アニメーションカーブは、各車両にデザインレバーを追加し、インスペクターで視覚的にその特性を制御できる、Unity の便利で多用途なツールです。

Grey balls falling off with different characteristics and curves in Unity
リジッドボディごとに異なるカーブを使用し、落とした時の特徴を見たところ
The curves for each sphere in the previous image
上の画像の各球体につけたカーブ
A code snippet in C# for dropping objects
落ちる球体につけたコードスニペット

上の画像の球体の列は、複数のリジッドボディを 1 列に配置し、そのFreeze Position プロパティを X 軸と Z 軸に設定して拘束することで作成されています。そして、圧縮された上向きの力をベースにしたアニメーションカーブを用いて上向きの力を加えつつ、視覚的にわかりやすいように横に並べた球体ごとに異なるカーブを適用したものです。このテクニックを使って、オブジェクトにとって適切な跳ねる大きさを見つけたり、既存の跳ね方を微調整して特性のバランスをとることができます。デザイナーとしては、上に向かう力の特性を操作できることで、より複雑な機能を抽象化したものを作ることができます。

カーブは強力な XY チャートのデータ型で、技術的には完全ではありませんが、インスペクターで視覚的に編集でき、実行時にプリセットとして保存できるスピーディな減衰ソリューションのプロトタイピングに役立ちます。このブログで、Alexis Bacot 氏は減衰の技術について解説し、そこで「良い減衰に依存する」すべての事柄にスポットライトを当てています。「カメラ、アニメーション、動き、カラーグラデーション、UI トランジションなどなど...あらゆるところで使われています。減衰を理解することは、作品に素晴らしい仕上げを行うためにカギとなる技術です。減衰ひとつで、体験の良し悪しが決まることもあります」。

同記事では、Unity の SmoothDamp を、美しいイーズインとイーズアウトを作成し、目標が変化するのに正確に反応する方法を実演しています。しかし、「車のサスペンションや擬似球の物理演算に最適な、振動する高度なスプリングダンパー」のような弾み方はしません。これはアニメーションカーブが大きな強みを発揮できる例です。

もちろん、曲線はゲームプレイを操作するための XY データ型としてだけでなく、もっと多くの用途があります。また、Unity API 経由で AddKey を使うことで、視覚的にデータを取り込む評価ツールとしても扱えます。自動車のサスペンションの例で見た減衰や、落下する球体など、時間に合わせて位置を評価する場合は、メソッドで AddKey (elapsedTime, currentSpringCompression) を使い、そのメソッドを呼び出して InvokeRepeating を経由して、繰り返しレートとして captureResolution を渡します。キャプチャの分解能が 0.1f の場合、0.1 秒ごとにカーブにキーが追加されることになる。インスペクターで縮小版の結果を見るか、グラフを開いて完全なデータを見ることができます。

A plotted curve
跳ねるときの線形なカーブと 0,0 から 1,1 までの直線を持つ使用した場合のカーブをプロットした結果
A plotted curve
上のカーブと似ているが、非線形でダブルシグモイドのようなカーブを使用した場合のカーブをプロット結果

跳ねるバンに戻る

最後にもう一度、落下するバンを見てみましょう。アニメーションカーブでは、スプリングの圧縮量に応じて力のかけ方を決め、3 回目のバウンドで少し振動が大きくなるような、目標に近い結果を作り出しています。Unity の「Hover Racer Live 7/21 Cycle 4.2」の PID を使って、アニメーションカーブで作成したサスペンションと PID 制御のサスペンションを比較することができます。唯一の違いは、PID の結果にアニメーションカーブの Y 値ではなく、ホバーする力が掛けられることです。

PID を実装し、多くのバランス調整を行った結果、車両のサスペンションは後輪の振動が少なくなり、抑制に必要な抵抗も少なくなり、目標に近づいたように感じます。残念ながら、質量値が異なる場合は、車両ごとに PID のバランスをとる必要があり、時間がかかってしまいます。プロトタイピングの場合は、アニメーションカーブでこれを視覚的に素早く行うことができ、プロットされた動作の結果を分析することができます。PID の実装を評価するには、やはり、カーブを使って空白のカーブに結果をプロットするとよいでしょう。その結果、2 回目の跳ね返りはやや誇張されたものになりましたが、大きな浮き上がるバンに必要な動きと見栄えは確保できました。

A white van without wheels suspended in the air, in Unity
PID を用いた車両サスペンションの最終的な実装。ただし、プロトタイピング中に開発されたアニメーションカーブをベースにしている。サスペンションの誇張が残っている。スプリングの長さは 1m としている。
A target damping curve on the left, with a plotted result curve on the right
左側が Alexis Bacot 氏による、目標とする減衰曲線の結果、右側が PID を実装した後の自動車の動きのプロット結果。

まとめとして、自動車の動きを開発する際には、以下のようにアニメーションカーブを使用します。

  • 自動車のエンジンの出力をプロットし、スムーズな出力の推移を演出する。
  • 素早くブレーキをかけ、時間をかけてブレーキの力を弱めて、現実の車のブレーキをシミュレーションしたり、またゲームでは『iRacing』のように、ドライバーがタイヤの限界となるところでブレーキをかけ、車をスピンさせずに短時間で減速したりと、リアルなブレーキの挙動を作りだすことが可能になる。
  • 自動車に上向きの力を与えるサスペンションシステムのシミュレーションを行う。
  • 横方向のトラクションをシミュレーションし、車が左右に滑り過ぎないようにする横方向の反力計算を行う。
  • コントローラー使用時のステアリングをシミュレーションする(ステアリングは中央付近、-0.5 ~ 0.5 付近で使用可能。スティック位置が -1 または 1 に近づくと徐々に速くなる)。
A green block floating on blue water, surrounded by mountains, in Unity
このプロトタイプでは、curve.Evaluate(time) を使って、プラットフォームの Transform を Y 軸上で時間経過とともに移動させる。

アニメーションカーブは、乗り物の物理に加え、プレイヤーの動きや攻撃を受けた際の時間経過に合わせたダメージモーションなどをプロトタイピングするためのデザインレバーとして使用することができます。強力なプロトタイピングツールとして、アニメーションカーブは、ゲームデザイナーが複雑なアルゴリズムや物理計算を記述することなく、さまざまな力がかかる場面のテストを行い、ゲームメカニクスの正しい「手触り感」を見出せるようにしてくれます。

さらにガイダンスとインスピレーションの源をお探しの方は無料でダウンロードできる「Game Designer Playbook」をご覧ください。

2022年7月21日 カテゴリ: ゲーム | 27 分 で読めます

Is this article helpful for you?

Thank you for your feedback!

取り上げているトピック
関連する投稿