コンボした時の演出をつくってみた。こんなの。
メイキング
上のgif画像みたいになるまでの過程をメモしていこうと思います。
コンボとは
今回,コンボを「何かしらのアクションが連続的に行われた時のカウンター」とします。とすると、最低限実装すべきものは「カウンター」 ですよね...?
んじゃとりあえず変数用意してインクリメント。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ComboSystem : MonoBehaviour {
[SerializeField] string comboWord;
[SerializeField] GameObject comboObj;
Text comboText;
RectTransform comboRectTrans;
int counter = 0;
void Awake() {
comboText = comboObj.GetComponent<Text>();
comboRectTrans = comboObj.GetComponent<RectTransform>();
}
public void IncreaseCombo() {
counter++;
UpdateCombo(counter);
}
<summary>
</summary>
<param name="comboCount"></param>
void UpdateCombo(int comboCount) {
Show();
comboText.text = comboCount + comboWord;
}
void Show() {
comboText.enabled = true;
}
}
文字のスケールを拡大縮小
コンボとしての役割は果たしているのであとは演出を凝る。文字の大きさを大→小に変化させることでインパクトある感じに。実装方法はコルーチンとAnimationCurveを使いました。参考記事Unityで対象のポイントへ等速で動かす - テラシュールブログ
一定時間コンボが増えない場合の処理
コンボが発生した時、ある程度時間経っても増えない場合はコンボ数をクリアするようにします。
文を傾ける
数字と大きさの変化だけじゃなんか物足りない...
そこで毎回ランダムに文を傾けるようにします。個人的こだわりポイント。この時点でほぼ実装完了って感じ。
段階的に表示する
あとはプラスアルファ。
ぷよぷよとかパズドラ見たいに段階的にコンボが増える仕様なら大丈夫ですが、一気に1→5になることもゲームによってはありえると思いますよね...現状では2,3,4を飛ばして5を表示する仕様になってますが、個人的には2,3,4も表示させたい...!!
なので、一度に(厳密には目で追えない早さで)増えても段階的に表示させるように改良。実装方法はQueueを使ってコンボ数を貯めておき、ある程度時間がたったらDequeueするという感じに。
その他細かい部分
コンボ数が積み重なるほど盛り上がる感じが欲しかったので、いい感じになるようにいじります。
いろいろこねくり回しているとトップgifのようになりました。
Githubとか使えば良かったんですが、なんとなく直貼り。もっとこうした方がいいみたいなのあったら教えて頂けると嬉しいです...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ComboSystem : MonoBehaviour {
[SerializeField] string comboWord;
[SerializeField] GameObject comboObj;
[SerializeField] AnimationCurve scaleCurve;
[SerializeField, Range(0.2f, 0.5f)] float initEffectDuration = 0.2f;
[SerializeField, Range(0.01f, 0.1f)] float durationIncrement = 0.03f;
[SerializeField, Range(0.4f, 0.7f)] float maxEffectDuration = 0.4f;
[SerializeField, Range(1.2f, 1.5f)] float initMaxScale = 1.4f;
[SerializeField, Range(0.2f, 1f)] float scaleIncrement = 0.6f;
[SerializeField, Range(5, 10)] float maxScale = 5f;
[SerializeField, Range(0, 0.2f)] float basicScaleIncrement = 0.09f;
Text comboText;
RectTransform comboRectTrans;
int counter = 0;
bool playingEffect = false;
float scale;
float basicScale;
float effectDuration;
float timer = 0f;
Coroutine effectCol;
Queue<int> comboOrder = new Queue<int>();
void Awake() {
comboText = comboObj.GetComponent<Text>();
comboRectTrans = comboObj.GetComponent<RectTransform>();
}
void Update () {
if (comboOrder.Count == 0) return;
timer += Time.deltaTime;
var tempRate = Mathf.Clamp((1f-counter/10f), 0.3f, 0.5f);
if (timer > effectDuration * tempRate) {
timer = 0;
UpdateCombo(comboOrder.Dequeue());
}
}
public void IncreaseCombo() {
counter++;
comboOrder.Enqueue(counter);
if (counter == 1)
UpdateCombo(comboOrder.Dequeue());
}
<summary>
</summary>
<param name="comboCount"></param>
void UpdateCombo(int comboCount) {
Show();
comboText.text = comboCount + comboWord;
comboRectTrans.localRotation = Quaternion.Euler(0, 0, Random.Range(-15f, 15f));
if (playingEffect) {
StopCoroutine (effectCol);
if (effectDuration < maxEffectDuration) {
effectDuration += durationIncrement;
}
if (scale < maxScale) {
scale += scaleIncrement;
}
if (counter < 7) {
basicScale += basicScaleIncrement;
}
} else {
scale = initMaxScale;
basicScale = 1;
effectDuration = initEffectDuration;
}
effectCol = StartCoroutine(PlayEffect(effectDuration));
}
void Show() {
comboText.enabled = true;
}
void Hide() {
comboText.enabled = false;
}
void Clear() {
counter = 0;
comboOrder.Clear();
Hide();
}
<summary>
</summary>
<param name="duration"></param>
IEnumerator PlayEffect(float duration) {
var timer = 0f;
var rate = 0f;
var startScale = new Vector3 (scale, scale, 1);
var endScale = new Vector3 (basicScale, basicScale, 1);
playingEffect = true;
while (rate < 1) {
timer += Time.deltaTime;
rate = Mathf.Clamp01(timer / duration);
var curvePos = scaleCurve.Evaluate(rate);
comboRectTrans.localScale = Vector3.Lerp(startScale, endScale, curvePos);
yield return null;
}
yield return new WaitForSeconds(0.5f);
Clear();
playingEffect = false;
}
}
使い方は、下の画像のように上記のソースコードを空のオブジェクト(画像内ではComboSystem)にアタッチ。
その後、ComboSystemコンポーネントのパラメータを埋めて、ボタンをクリックするとIncreaseComboメソッドが実行されるように設定します。
感想
今回、色と音については特に触れませんでした。
もっと爽快感ある感じにできたらいいな...