【Unity開発】放物線を描いて飛ばす表現方法【コラム】

PurpleMandrill
スポンサーリンク

ゲーム中でキャラに向けてハートを飛ばしたい!

ぴっくるでは現在、研究開発の一環で、PurpleMandrillの開発を進めています。

今回はキャラクターに向かってハートを飛ばす実装を考えます。

テンションの上がるコメントが入力された場合、テンションゲージが上がるのですが、その際に視覚的にキャラクターに向かってハートを飛ばすようにします。

飛ばし方ですが、ユーザーのコメントがハートになって、プレイヤーに飛んでいくようなイメージなので、画面下からプレイヤーのいる画面中央あたりに飛んでいくことを想定します。

ボールを投げるように放物線を描きたいと思います。

まずはまっすぐ飛ばしてみる

3Dで表現する場合、カメラ位置のちょい下からプレイヤーの位置までを移動すれば良いですが、今回はカメラとプレイヤーの位置が固定なので、手を抜いて2DのUGUI上で行います。

ハートは1枚画像で、Imageコンポーネントを使います。

まずは手始めに直線で等速に飛ばします。

var startPos = new Vector2(Random.Range(-350f, 350f), -1080 / 2 - 100);
var endPos = Vector2.zero;
var pos = Vector2.Lerp(startPos, endPos, m_Timer / Duration);
m_RectTrans.anchoredPosition = pos;

始点と終点の距離を出して、時間を正規化して現在の表示座標を出してやる感じですね。

式にすると、

現在座標=始点+(終点-始点)×経過時間÷総時間

になります。

Unityには便利なLerp関数があって、これを使えば同じ事が出来ます。

線グラフで表現したもの

実際のゲーム映像


このままではちょっと味気ないですね。

なので、次は放物線を描くようにしたいと思います

直線ではなく、放物線を描くようにする

放物線を描くには、放物線の式を使います。

y=ax^2

みたいなやつですね。

まずX座標については従来通りの等速移動を行います。

Y座標は、

Y座標=始点+(終点-始点)×(経過時間÷総時間)^2

という感じになります。

処理を書き換えてみます。

var startPos = new Vector2(Random.Range(-350f, 350f), -1080 / 2 - 100);
var endPos = Vector2.zero;
var pos = new Vector2();
var t = m_Timer / Duration;
pos.x = startPos.x + (endPos.x - startPos.x) * t;
var l = (endPos.y - startPos.y);
pos.y = startPos.y + l * t * t;
m_RectTrans.anchoredPosition = pos;

終点に近づくにつれて、ちょっと動きが滑らかになりましたね。

ただしこの式では、終点が山の頂上に来るので、放物線を描いて飛んでるようには見えません。

終点の少し前に頂上があって、少し降りてくるような動きにさせたいです。

この場合、3次曲線を使います。

よくエルミート曲線などと言われるものです。



エルミート曲線は自前で組むと少し面倒なのですが、UnityにはAnimationCurveという便利なクラスがあるのでそれを使います。

var startPos = new Vector2(Random.Range(-350f, 350f), -1080 / 2 - 100);
var endPos = Vector2.zero;
var pos = new Vector2();
pos.x = startPos.x + (endPos.x - startPos.x) * m_Timer / Duration;

var l = (endPos.y - startPos.y);
var animCurve = new AnimationCurve();
var keyFrameS = new Keyframe(0, startPos.y, 0, l);
var keyFrameE = new Keyframe(Duration, endPos.y, -l * 2, 0);
animCurve.AddKey(keyFrameS);
animCurve.AddKey(keyFrameE);

pos.y = animCurve.Evaluate(m_Timer);
m_RectTrans.anchoredPosition = pos;

山なりになりました。

タンジェントの指定が難しいです。

ここにはy/xで表せる傾きを入れればいいのですが、UnityEditor上で良い感じのカーブを作ってその値を入れちゃうのが手っ取り早いですね。

毎回AnimationCurveやKeyframeを作るのはもったいないので、初期化クラスに移動させてUpdateではEvaluateだけするようにしてやります。

あとはスケールもアニメーションして、奥に行っている感を出せばより良くなります。

射出までにディレイをランダムに設ければ、もう少しばらついた感じでハートを出せるようになります。

飛び込んでいってますね。

まとめ

と、ここまで色々と説明したものの、Unityを使ってるのであれば、AnimationCurveで上の3つは表現できてしまいますし、より複雑な動きもさせられます。

他にも「Animationを使えば良いじゃん」とか「パーティクルでやれば良いじゃん」いう話にはなるのですが、まあ原理を知っていても損はないということで…



今回は「結論、AnimationCurve便利!」って話でした。


有限会社ぴっくるとは?

ゲーム開発を行って19年目になる会社です。
他のデベロッパー会社と一緒にプロジェクトに参加して、いろいろなゲーム開発に携わっています。
音声収録・動画配信スタジオを運営し、会社・スタッフともに色々な情報発信を行っています。
そんなぴっくるではゲームプログラマースタッフを絶賛募集中です。

コメント

タイトルとURLをコピーしました