ゲーム中でキャラに向けてハートを飛ばしたい!
ぴっくるでは現在、研究開発の一環で、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年目になる会社です。
他のデベロッパー会社と一緒にプロジェクトに参加して、いろいろなゲーム開発に携わっています。
音声収録・動画配信スタジオを運営し、会社・スタッフともに色々な情報発信を行っています。
そんなぴっくるではゲームプログラマースタッフを絶賛募集中です。
コメント