【Unity】Animationカーブを使って加速を演出

2021/8/8 グラフの数値を訂正・追記
2021/8/11一部修正


前回、転倒モーションを作ってみたのですが、
内容は、障害物に躓くと一回転して座り込む感じで処理をしました。

座り込む際に止まって、立ち上がると走り出す感じなんですが、
走り出しでトップスピードになるのも少々困りものでっす(- .-)ヾ ポリポリ

やはり走り出しは、加速していく感じにしたいので、
処理を考えてみました。

当初は、Updateで秒数を読み取りスピードに加算する方法にしたのですが、
調べてみるとAnimationカーブってのが存在するそうなので、
折角なら使ってみたいですよね(^.^; オホホホ

上手く作れたかは置いといて、処理を考えたので記事にします。
(;^o^) \(ToT )あんたほんとにそれでいいの


まず、Animationカーブってなんぞや?てことなんですが、
アニメーションクリップでそのプロパティーの変化を時系列に制御
スクリプトリファレンス抜粋

書いてみましたが、ちょっと何言ってるかわかんない(-_-)ゞ゛ウーム

簡単に言うと、グラフを使って時間に沿った処理を行えるみたいです。
位置、大きさ、etc

本来、アニメーションクリップと連動させて使うみたいですが、
スクリプトからグラフの曲線を読み取る事ができるようなので、
利用してみたいと思います。

まずテスト用に床と移動用のボールを作ります。
ダッシュ⑦.jpg
加速の違いを比較する為に3つほど用意しました。

続いて、ベースになるAnimationカーブが必要になるので、
新規のスクリプトを立ち上げて、CurveTestとでもしておきます。
CurveTest

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CurveTest : MonoBehaviour
{
[Header("スピードカーブ")]
public AnimationCurve speedCurve; //ボールのAnimationカーブ

パブリックな変数でAnimationCurveを宣言します。

Unityに戻ってボールにスクリプトをアタッチします。
ダッシュ⑧.jpg
追加した変数が表示されているので、スクショの赤枠で囲った、
灰色の部分をクリックします。
ダッシュ②.jpg
カーブのウィンドウが開きました。

このグラフにカーブを設定する事で、時系列で処理が行えるそうなんです。

見かたとしては、
横軸:処理時間
縦軸:処理値
カーブの種類:赤枠で囲った部分

では早速カーブを設定してみます。
ダッシュ③.jpg
カーブの種類を選択するとカーブの曲線が表示されます。

横軸が経過時間で縦軸が値となります。
デフォルトでは、横1.0縦1.0の曲線が表示されます。

このグラフからデータを取得する場合、
経過時間をグラフに渡すと曲線から値を返すようにできています。

例えば、0.1秒とグラフに入力した場合
ダッシュ⑤.jpg
だいたい0.18~0.19の値が返ってきます。

曲線に沿った数値が返ってくるので、
加速させたいカーブを描いておけば経過時間を入力するだけで
スピードを取り出す事ができるので、面倒な計算などが要らなくなります。

曲線の傾斜は、任意で変える事ができます。
ダッシュ④.jpg
曲線上で右クリックするとキーの追加が行えるので、
曲げたい部分などに追加するとカーブを変える事ができます。

実際に少しいじってみようと思います。
ダッシュ⑥.jpg
追加したキーをクリックすると灰色のバーが出るので、
バーのポッチをドラッグして回転させると曲線が変化します。

こんな感じでグラフを作っておいて、
経過時間と値を元にスピードを設定します。

グラフの注意点ですが、
縦1.0横1.0になっているので、1秒間で上限に達する設定です。

グラフに経過時間を渡すのですが、1.5秒と渡しても上限が1.0秒なので、
1.0秒の値が返ってきます。

1秒以上の加速時間を設定したい場合は、
カーブの終点キーを1秒以上の位置に設定する必要があります。

だいたいの説明でしたが、分かってもらえたでしょうか?
(°°)\(-O-;) セツメイガヘタデワカラン

説明だけでは分かりにくいので、
実際にスピードを変化させるスクリプトを作ってみます。
CurveTest

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CurveTest : MonoBehaviour
{
[Header("スピードカーブ")]
public AnimationCurve speedCurve; //ボールのAnimationカーブ

private float moveTime; //ボールの移動時間
private float speed; //ボールの速度
private const float maxSpeed = 5f; //ボールの最高速度

private Rigidbody2D ballRB; //ボールのRigidbody

// Start is called before the first frame update
void Start()
{
ballRB = GetComponent<Rigidbody2D>();
}

// Update is called once per frame
void Update()
{
SpeedController();
}

private void FixedUpdate()
{
ballRB.velocity = new Vector2(speed, ballRB.velocity.y);
}

//ボールの速度をコントロールする
private void SpeedController()
{
moveTime += Time.deltaTime;
speed = speedCurve.Evaluate(moveTime) * maxSpeed;
}
}

SpeedController関数の中身なんですが、
まず、経過時間が必要になるので、deltaTimeの加算が必要になります。

経過時間を取得できたらグラフに入力するのですが、
AnimationCurve.Evaluate(経過時間)で値を取り出す事ができます。

返ってくる値は、上限1.0までの数値が返ってきます。
そのままの値をSpeedに代入しても遅いので、補正する必要があります。

カーブの上限値が1.0に設定されているので、
上限1.0の時にマックススピードになるように補正すればOKかと。

なので、計算式としては、カーブの値✕上限速度とすれば、
カーブ上限に達した所がマックススピードになります。


スクリプトが準備できたので、各ボールの加速設定をします。
ダッシュ⑩.jpg
①初速が遅くて最後にマックススピードまで上がる
②初速からほぼマックススピード
③プリセットの加速カーブ

これで動きをテストしてみます。

ちょっと分かりにくいですかね~(;^_^A
各ボール、グラフ通りの加速をしております。

このスクリプトを元にアンドロイド君にも加速処理を施してみます。
ActionTest

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ActionTest : MonoBehaviour
{
[Header("ダッシュカーブ")]
public AnimationCurve dashCurve; //キャラのAnimationカーブ
private float dashTime; //加速時間

private float runSpeed = 0f; //走るスピード
private const float speedMax = 10f; //最高速度
// Update is called once per frame
void Update()
{
SetLinecast();

if (bodyUnder)
{
if (runSpeed < speedMax)
SpeedController();

if (Input.anyKeyDown)
KeySelect();

AnimationChange(actionNum.run);
}
else
AirMotion();
}

//キャラの速度コントローラー
private void SpeedController()
{
dashTime += Time.deltaTime;
runSpeed = dashCurve.Evaluate(dashTime) * speedMax;
}

床の接地はbodyUnderフラグに取っています。

床に接触してる時だけ速度をコントロールするようにしました。
これで床に接触している間は、加速する事ができます。

続いて、転倒処理を修正していきます。
・転倒したら止まる
・起き上がりから加速

この二つを実装する必要があるので。
ActionTest

private const float moveStopTime = 0.62f; //転倒時の移動停止時間
private const float restart = 0.87f; //転倒時の動き出し時間


//転倒アクション
private void FallDown()
{
fallDownProgress += Time.deltaTime;

if (fallDownProgress >= moveStopTime)
{
if (fallDownProgress >= restart)
SpeedController();
else
{
runSpeed = 0.0f;
dashTime = 0.0f;
}
}

if (fallDownProgress < fallDownTime)
AnimationChange(actionNum.fallDown);
else
{
obstacle = false;
fallDownProgress = 0f;
}
}

転倒の処理については前回記事を参照下さい。

躓いてから一回転して止まる動作をさせているので、
尻もちを着く0.62秒後に速度と加速時間をリセットしてやります。

転倒から0.87秒後に立ち上がり始めるので、
SpeedController関数を呼び出せば、上手く加速していくかと思います。

これで、動作処理としては完成なんですが、
走るAnimationクリップは、常に同じスピードで再生されます。

速度が変わるのに腕や足の動きがトップスピードのままってのも変なので、
走るAnimationの時だけ、移動速度に合わせた再生スピードに変更します。
ActionTest

//アニメーション切り替え
private void AnimationChange(actionNum num)
{
motion.SetInteger(CLIP_KEY, (int)num);

if (num != actionNum.run)
motion.speed = 1;
else
motion.speed = dashCurve.Evaluate(dashTime);
}

Animationの切り替え関数内で、
Run以外のクリップ再生なら1に設定します。

Runの場合、移動速度から再生速度を計算する必要がありますが、
速度は、加速カーブを元に計算しているので、そのまま流用する事ができます。

クリップの再生速度の上限を1としておけば、カーブの上限速度も1なので、
そのままカーブの値を入力すれば、無補正で再生速度となります。

最後に加速カーブを設定します。
ダッシュ⑪.jpg
立ち上がり時に動きが出ている方が自然に見えるので、
初速を0.2くらいに設定しました。

残りはプリセットの加速カーブに近づけて、自然に加速する感じにしてみます。
準備ができたのでPLAYしてみます。

動きと速度が分かるように、背景と速度表示を付けてみました。

立ち上がりから走りだしまで、スムーズな感じに仕上がったかと思います。
加速も上手く機能しているので、問題もないと思います。

加速の処理は、それなりに面倒なのですが、カーブを使うと簡単に作れますね~

今回は、横方向の処理に使いましたが、落下や上昇にも使えるかと思います。
カーブの特性で加速感が変わるので、いろいろ試してみたい所でっす。

ジャンプの処理なんかもAddForceより狙った動作が作れるかもしれませんね~

加速処理については以上となります。
Animationカーブの参考にでもなれば幸いかと思います。

それではこのへんで (^^)/~~デハデハ



追記
カーブから0.1秒の数値を読み取る例を記載していましたが、
誤1.8~1.9
正0.18~0.19

訂正しました。

上限1.0と書いたのに1.8~1.9ってと思われた方には申し訳ないです。
(ToT)>゛スンマセン

この記事へのコメント