読者です 読者をやめる 読者になる 読者になる

DoTweenのcanvasGroup.DoFade( 0, 1 ).OnComplete( completeFunction )みたいなことがしたい

Unity c#

サンプルプロジェクトをgithubにあげてます。

github.com

こないだUnityの勉強会に行って、UnityのAssetでTweenアニメをしてくれるDoTweenというものがあるのを知りました。

dotween.demigiant.com


そこで出てきたサンプルコードで以下の様なものがありました。

obj.GetComponent<CanvasGroup>().DoFade( 0, 1 ).OnComplete( completeFunction )

おぉ!これはかっこいい!スマート!こんな風に書けるようなのを作ってみたい!って思ったので試してみました。やりたいこととしては、

  1. あたかもUnityEngine.UI.CanvasGroupがアニメーションの関数を持っているようにしたい
  2. アニメーションの関数を数珠つなぎして色々指定したい
  3. 上記関数を呼ぶ以外には、他に何の前処理も必要ないのが良い

という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に関しては、以下の記事が詳しいです。

tsubakit1.hateblo.jp


残念ながら事前に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;
        }
    }   
}

作ったアプリです!良かったらダウンロードお願いします!

Make 10 by using 4 numbers

Make 10 by using 4 numbers

  • Ken Watanabe
  • ゲーム
  • 無料
play.google.com