[Unity] FF4、FF5のダメージ表示アニメーションをUnityで再現する

ハイスコアガールのハルオ世代がほいほい釣れそうなFF4やFF5のダメージ数値が表示される時のアニメーションをUnityで再現してみます。実装方法が間違っているかもしれませんが懐かしむ感じで。

FFダメージ表示アニメーション(FF4~6?)

ff-popup-damage

こんな感じのアニメーションを作ってみます。

 

2015/1/24 触れるもの作ってみました →  [Unity] FF1からFF6までのダメージ表示アニメーションを再現する

 

 

 

実装方法

Twitterで教えていただいた方法

すべて答えが載っています。やったね!(Unity初心者の心の中:Canvas Groupって何だろう?文字表示が終わったという判定はどうやるのだろうか?)

 

アニメーション作成

まずはTextを作ります。Outlineコンポーネントを付けて装飾。フォントサイズは24。幅高さは30にしました。

WindowメニューからAnimationを選択。Animationウィンドウでアニメーションを作成していきます。Add Curveボタンを押し、DamagePopupAnimation.Animファイルを保存します。

ff001

数値がポンっと飛び出す感じにアニメーションを作成します。動きは好きなように作りましょう。

アニメーションのループ設定をOFFにします。

ff002

※本当は「何もしない状態」「数値が飛び出すアニメーション」「消えるときのアニメーション」「消えた後の状態」の4つアニメーションをコントロールしたかったのですが、判らなかったのでとりあえずポップアップするアニメーションだけ作りました。

※この部分ですがアニメーションを再生し終えたら、AステートからBステートに遷移させる…、なんてことができると思うのですよ・・・。ほいでAnimator.GetState的なメソッドで状態を取れたりすると思うのですよ・・・。今回ははまりそうだったのでパス。

 

テキスト用スクリプトの作成

作成したTextで「アニメーション終了イベント」を受け取りる為のスクリプトを作成します。

using UnityEngine;
using System.Collections;

public class NumberTextScript : MonoBehaviour {

	public bool IsFinish = false;

	public void OnAnimationFinish()
	{
		this.IsFinish = true;
	}
}

作成したらTextにスクリプトを追加します。

 

アニメーションイベントの追加

アニメーションが終了したときNumberTextScript.OnAnimationFinish(上で作成したスクリプトのメソッド)が呼ばれるように設定します。Animationウィンドウに行き、最終フレームにイベントを追加します。

ff003

イベントには先ほど追加したOnAnimationFinishを指定します。

ff004

 

テスト再生とプレハブ化

再生されたでしょうか。よければ作成したTextをPrefab化して消します。Canvasは使うのでそのままで。

 

休憩

なれない作業でここまでで1.5時間くらいかかってたりします。慣れている人で2~3分程度じゃないだろうか。

 

ダメージ表示用GameObjectの作成

各文字のアニメーションを行い、自分自身の破棄までの一連の動作を行うスクリプトを作成します。

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

public class PopupDamageGen : MonoBehaviour {
	
	/// <summary>
	/// 出力先キャンバス
	/// </summary>
	public GameObject TargetCanvas;
	
	/// <summary>
	/// 表示する文字
	/// </summary>
	public string PopupString;

	/// <summary>
	/// ポップアップするテキストオブジェクト
	/// NumberTextScript付き
	/// </summary>
	public GameObject PopupTextObject;
	
	/// <summary>
	/// ポップアップする位置
	/// </summary>
	public Vector3 PopupPosition;
	
	/// <summary>
	/// 1文字の幅
	/// </summary>
	public float PopupTextWidth;

	/// <summary>
	/// ポップアップの実行
	/// </summary>
	public void Popup()
	{
		StartCoroutine (Execute());
	}

	/// <summary>
	/// ポップアップ実行
	/// </summary>
	private IEnumerator Execute()
	{
		var pos = this.PopupPosition;
		var texts = new List<NumberTextScript> ();

		var root = new GameObject ();
		var canvasGroup = root.AddComponent<CanvasGroup> ();
		root.transform.SetParent (this.TargetCanvas.transform);
		
		foreach (var s in this.PopupString) {
			var obj = new GameObject ();
			obj.transform.position = pos;
			obj.transform.SetParent (root.transform);

			// 1文字ずつ生成
			var valueText = (GameObject)Instantiate (this.PopupTextObject, pos, Quaternion.identity);
			var textComp = valueText.GetComponent<Text> ();
			textComp.text = s.ToString ();
			valueText.transform.SetParent (obj.transform);
			texts.Add( valueText.GetComponent<NumberTextScript>() );
			
			// 0.03秒待つ(適当)
			yield return new WaitForSeconds (0.03f);
			
			// 次の位置
			pos.x += this.PopupTextWidth;
		}
		
		// 適当に待ち
		while (!texts.TrueForAll( t => t.IsFinish )) {
			yield return new WaitForSeconds (0.1f);
		}

		// フェードアウト
		for (int n=9; n>=0; n--) {
			canvasGroup.alpha = n / 10.0f;
			yield return new WaitForSeconds (0.01f);
		}
		
		// 破棄
		Destroy (root);
		Destroy (gameObject);
	}
}

行っていることは

  • 一気に透明化できるようにRootとなるGameObject+Canvas Groupの作成(破棄するのも簡単だしね)
  • 一定時間ごとに1文字ずつTextオブジェクトを生成する
  • アニメーション終了チェック
  • Canvas GroupのAlpha値を変えながらフェードアウト処理
  • 自分自身の破棄

です。

コルーチンで処理していますが、Updateメソッド内でTime.deltatimeを使った処理の方が正しいかもしれません。フェードアウトしていく処理もText側のアニメーションで作成したほうがデザイン側とコーディング側が分かれて幸せになれるはずですが・・・。

 

左クリックでポップアップするテストスクリプトを作成(テスト用)

using UnityEngine;
using System.Collections;

public class Test_PopupDamage : MonoBehaviour {
	
	/// <summary>
	/// 出力先キャンバス
	/// </summary>
	public GameObject TargetCanvas;
	
	/// <summary>
	/// ポップアップするテキストオブジェクト
	/// NumberTextScript付き
	/// </summary>
	public GameObject PopupText;

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
		if (Input.GetMouseButtonDown (0)) 
		{
			var temp = new GameObject();
			PopupDamageGen gen = temp.AddComponent<PopupDamageGen>();
			gen.PopupString = ((int)(Random.value * 10000.0f)).ToString();
			gen.PopupPosition = Input.mousePosition;
			gen.PopupTextWidth = 20.0f;
			gen.TargetCanvas = this.TargetCanvas;
			gen.PopupTextObject = this.PopupText;
			gen.Popup ();
		}
	}
}

作成したらCameraにでも追加しましょう。

 

実行

クリックするとぽろろんっと表示される!

 

まとめ

どうにか作ってみましたが「Unityの流儀に反しているかも?」とか、「この方法は一般的なんだろうか?」みたいな疑問がいっぱいです。

 

参考URL

Animatorの終了判定
http://perillasoft.blog75.fc2.com/blog-entry-48.html

コルーチンについて
http://qiita.com/fujimisakari/items/811e350cbaeb45b6165e


希木小鳥

Diablo1でハクスラの世界に。今はBorderlands2をプレイ中。ぬるゲーマー。

あわせて読みたい