サンプルプロジェクトをgithubにあげてます。
こないだUnityの勉強会に行って、UnityのAssetでTweenアニメをしてくれるDoTweenというものがあるのを知りました。
そこで出てきたサンプルコードで以下の様なものがありました。
obj.GetComponent<CanvasGroup>().DoFade( 0, 1 ).OnComplete( completeFunction )
おぉ!これはかっこいい!スマート!こんな風に書けるようなのを作ってみたい!って思ったので試してみました。やりたいこととしては、
- あたかもUnityEngine.UI.CanvasGroupがアニメーションの関数を持っているようにしたい
- アニメーションの関数を数珠つなぎして色々指定したい
- 上記関数を呼ぶ以外には、他に何の前処理も必要ないのが良い
という3つ。
C++erな私は知らなかったのですが、1に関してはC#の拡張メソッドという機能を使えばできます。
public static class CanvasGroupExtention { //拡張メソッド public static void AnimFade(this CanvasGroup canvas_group, float to, float duration) { ... } }
って感じ書いておくと
canvasGroup.AnimFade( 0, 1.0 );
などとかけるようになります。
さて、2の「アニメーションの関数を数珠つなぎして色々指定したい」に関しては、関数がcanvasGroupを返すようにすりゃ良いかな?っと思ってました。こんな感じ...
public static class CanvasGroupExtention { //拡張メソッド public static CanvasGroup AnimFade(this CanvasGroup canvas_group, float to, float duration) { ... return canvas_group; } public static CanvasGroup OnComplete(this CanvasGroup canvas_group, CompleteFunction func ) { ... return canvas_group; } }
って思ってたんですが、OnCompleteのような関数は、その場で実行するんじゃなくてアニメーションが終わった後に、引数の関数を呼ばなきゃ駄目なので、どっかに渡された関数を覚えとかないと駄目なんですね。
というわけで、AnimUnitという別クラスを作って、それに覚えさせることに。そして、返り値は、その作ったAnimUnitを返すようにしました。
public class AnimUnit { ... public AnimUnit OnComplete(CompleteCallback callback) { OnCompleteCallback = callback; return this; } ... } public static class CanvasGroupExtention { //拡張メソッド public static AnimUnit AnimFade(this AnimUnit canvas_group, float to, float duration) { AnimUnit unit = new AnimUnit(); ... return unit; } }
んで、後はUnityのコルーチンを使ってFadeのアニメをさせます。そのへんは、もうAnimUnitクラスに持たせちゃいます。
ただ、一つ問題が。StartCoroutineってMonoBehaviorのインスタンスメソッドなので、なんらかのMonoBehaviorインスタンスがないと呼べない。
AnimUnitクラスをMonoBehaviorにするという手もあるけど、そうするとMonoBehaviorが増えて処理が重くなりそう。
仕方がないので、それ専用のMonoBehaviorを作ることに、
public class AnimationManager : SingletonMonoBehaviour<AnimationManager> { }
以上で、完成。
SingletonMonoBehaviourに関しては、以下の記事が詳しいです。
残念ながら事前にAnimationManagerを作っておくという前処理が必要になってしまいましたが、それ以外は当初の目的が達成しました。
以下のように、1frameかけてフェードアウトして終わったらActive falseにしてね。っていうのが簡単にかけます。
obj.GetComponent<CanvasGroup>().AnimFade( 0.0f, 1.0f ).OnComplete( () => canvas.gameObject.SetActive(false) );
CanvasGroup以外のクラスや、他のTweenアニメに関しても同様の方法で拡張できますね。
最後にソースコードを貼り付けておきます。
using UnityEngine; using UnityEngine.UI; using System.Collections; namespace Extentions { public class AnimUnit { public CanvasGroup CanvasGroup{ get; set; } public delegate void CompleteCallback(); public CompleteCallback OnCompleteCallback{ get; set; } public AnimUnit OnComplete(CompleteCallback callback) { OnCompleteCallback = callback; return this; } public IEnumerator FadeCoroutine(float to, float duration) { float speed = ( to - CanvasGroup.alpha ) / duration; while( ( duration = duration - Time.deltaTime ) > 0 ) { CanvasGroup.alpha += speed * Time.deltaTime; yield return null; } CanvasGroup.alpha = to; if(OnCompleteCallback != null) { OnCompleteCallback(); } } } public static class CanvasGroupExtention { public static AnimUnit AnimFade(this CanvasGroup canvas_group, float to, float duration) { AnimUnit unit = new AnimUnit(); unit.CanvasGroup = canvas_group; AnimationManager.Instance.StartCoroutine( unit.FadeCoroutine( to, duration ) ); return unit; } } }
作ったアプリです!良かったらダウンロードお願いします!
play.google.com