【ゲーム制作向け】イージングのすゝめ

こちらはCCS Advent Calendar 2021 12日目の記事となります。 adventar.org

昨日の記事はこちら! note.com 最優秀賞めでたい!みんなもバグハンターにならないか?

真面目な話、一つのスキルになるし、教養展開の単位もとれるし、入賞すれば就活等のアピールで使えるかも?(あと景品のアマギフもらえるし...)

おすすめです。

はじめに

自分の作るゲームをちょっぴり良く見せたい!そんなアナタにイージングがおすすめです。

この記事ではイージングとは何か?から始まり実用例・実装を簡単に説明します。

イージングは気持ちの良い動きを追求するための技術です。気持ちの良い動きはゲームを遊んでいる時の面白さに繋がるものであり、重要な要素です。

知っているとゲーム制作以外にも役立てられるかも...?

イージングとは

まずはこの画像をご覧ください。

f:id:chinimuruhi:20211130161917g:plain

上のCubeと下のCubeは、動く時間も距離も同じです。では、何が違うでしょう? 上のCubeはずっと同じ速度で動いているのに対し、下のCubeは徐々に速くなるような動きをしています。このように、速度に緩急をつけることをイージング(Easing)と言います。


続いてこちらの画像をご覧ください。

f:id:chinimuruhi:20211130162640g:plain

上のように徐々に速くなる動きをイーズイン(Ease in)、中央のように徐々に遅くなる動きをイーズアウト(Ease out)、下のように最初と最後が遅くなる動きをイーズインアウト(Ease in-out)と言います。

イージングには様々な動きがあります。以下のサイトに動きとその数式が載っています。

easings.net

実用例

ゲーム内のオブジェクト

ゲーム内のオブジェクトにイージングを適用してみましょう。イージングをつける時は、物理的な挙動を意識すると不自然になりにくく、気持ちの良い動きになりやすいです。

例:ゴール時の衝突演出

f:id:chinimuruhi:20211130181910g:plain

球がカップに当たるとカップが反応を起こす、という動作での例です。ストローの動きとカップのスケールの動きにEase outを使用しています。

衝突によってカップに運動が伝わり、段々減衰していくことを考えてEase outを選択しています。

等速でストローを動かすよりも気持ちが良い動きになっており、ゴールした達成感をより強めることが出来ているかと思います。

また、正しい物理挙動が気持ちの良い動きとは限りません。速度の減衰のモデルを考えて...とするのではなく、様々な種類のイージングを試してみましょう。

不自然でない限りで、大袈裟に表現出来ていると嬉しい。

エフェクト

同様に物理的な挙動を意識しながら使っていきます。

例:打撃のエフェクトを出す例

f:id:chinimuruhi:20211130210050g:plain

ハンマーが当たるとエフェクトが出る例です。先ほど同様、衝突の運動が伝わり減衰していく様子を考え、Ease outを使用しています。

(ハンマーの動き自体にもイージングを使っています。隙あらば使っていきましょう。)

UI

プレイヤーの操作に依らない動きの場合、プレイヤーは要素がいつ動くのか分かりません。

そのため、Ease outのようにいきなり最高速度で動き出すとびっくりさせてしまう可能性があり、Ease in又はEase in-outを使うようにしています。

一方で、プレイヤーの操作によって起こる動作はEase outを使います。ボタンを押した衝撃がゲーム内に伝わるような体験をさせて、「自分が操作した感」を強めます。

アイテム欄っぽいものの例

f:id:chinimuruhi:20211130213500g:plain

出てきた時はEase in、アイテム欄の詳細を開くときはEase outを使っています。

実装

動きのイージングを楽に実装するために必要なものは以下の2つです。

  • 線形補完関数
  • イージング関数

線形補完関数

線形補完関数はこのような形をしていることが多いです。

//(double型などの型をTとする)
T lerp(T 開始の値, T 終了の値, T t)

tは基本的に0.0~1.0の間の値をとり、0.0の時は開始の値、1.0の時は終了の値を返します。

例
val = lerp(2.0, 5.0, 0.0)  //valは2.0
val = lerp(2.0, 5.0, 0.1)  //valは2.3
val = lerp(2.0, 5.0, 0.5)  //valは3.5
val = lerp(2.0, 5.0, 1.0)  //valは5.0

線形補完関数の開始の値と終了の値を移動の開始点と終了点にし、tを0.0~1.0で動かすことで移動の動作を実装することができます。 この時、tを一定の速さで動かせばオブジェクトも一定の速さで動きます。

イージング関数

実装したいイージングの数式をそのまま関数にしたものです。

InCubicの例

f:id:chinimuruhi:20211129182223p:plain

//(double型などの型をTとする)
T easeInCubic(T x){
    return x * x * x;
}

動きのイージングの実装

線形補完関数でオブジェクトの座標等を決めながら、線形補完関数のtの動きをイージングさせるようにします。

//InCubicでの例
pos = lerp(開始の値, 終了の値, easeInCubic(t))

tを0.0~1.0で一定の速さで動かすことによって、イージングされた動きでの座標を得ることができます。

フレームワークゲームエンジンによる実装

線形補完関数についてはC++であればstdにありますが、イージング関数については自作する or どこかから持ってくる必要があります。

cpprefjp.github.io

フレームワークゲームエンジンによっては、線形補完及びイージングを行える機能が備えられています。そちらを軽く紹介します。


OpenSiv3D

OpenSiv3Dでは座標等を保持するVec2型での線形補完や、約30種類のイージング関数が備えられています。便利!

zenn.dev


Unity

Unityには線形補完関数はありますが、イージング関数はデフォルトではありません。自作するか、どこかから持ってきましょう。 また、これらの線形補完関数のtは[0, 1]で制限されており、この範囲を超えることのあるBack等のイージングには使えないので注意しましょう。

Mathf-Lerp - Unity スクリプトリファレンス

Vector3-Lerp - Unity スクリプトリファレンス

このように自作しようとすると少々面倒ですが、イージングの動作を簡単に書けるAssetがあります。

assetstore.unity.com

DOTweenを使えば、イージングの動作も一行で書けちゃいます。簡単!

//(5,0,0)へ1秒でOutExpo移動する
transform.DOMove(new Vector3(5f, 0f, 0f), 1f).SetEase(Ease.OutExpo);

SetEaseの引数にはAnimationCurveも対応しており、SerializeFieldにしたAnimationCurveでGUI上から書いたグラフの通りに動かすこともできます。

おわりに

ここまでお読みいただきありがとうございました。 皆さんのゲーム制作(や日常生活?)に少しでも役立てたら幸いです。

イージングの使い方についても軽く紹介しましたが、あくまで目安として受け取ってください。目的は「気持ちの良い動きを作ること」であり、例の通りイージングを使うことではありません。人の直感を信じてトライアンドエラーしていきましょう。