気ままなUnityエンジニアブログ

新米Unityエンジニアが送る解説アウトプットブログです。Twitter : @UjinUnity

MENU

【Unity ゲーム制作】神経衰弱ゲームを作ろう!〜その9 ~( DoTweenで綺麗なアニメーション)

スポンサーリンク

前っせっwっqZzz回のカードの表示切り替えの処理を実装しましたが、
動きが雑に見えた人も多いと思います。

そこで今回は、切り替え処理を綺麗にアニメーションするように変更していきましょう。

そのためには「Dotween」コンポーネントを新たに導入しようと思います。
Dotween は Unityに搭載されているコンポーネントではないため、AssetStoreから導入していきましょう!

AssetStoreからDotweenを導入しよう!

まずはUnityからAssetStoreを開きます。
画像を参照に開きましょう。

f:id:Wojtek:20190928183122p:plain


AssetStoreが開けたら検索をします!


f:id:Wojtek:20190928183156p:plain


Dtoweenが表示されたら、右側にある無料版を選択してUpdateボタンを押し、importしましょう。


f:id:Wojtek:20190928183214p:plain


Unityでこの画面が出たら、右下のimportを押します。


f:id:Wojtek:20190928183227p:plain


フォルダにDotweenが表示されたら導入成功です!


f:id:Wojtek:20190928183241p:plain


では、実際にDotweenを動かしてみましょう!

DotweenをCard.csに組みこもう!


Dotweenを使用するには、以下のusing を記述してください

using DG.Tweening;


試しに、カードを選択したら回転する 処理を実装してみましょう。

まずはCard.csにRectTransform 型の変数を実装します。

    // 座標情報
    private RectTransform mRt;


そうしたら、その変数にカードオブジェクトの座標情報を代入しましょう。

    // カードの設定
    public void Set (CardData data) {

        // カード情報を設定
        this.mData = data;

        // IDを設定する
        this.Id = data.Id;

        // 表示する画像を設定する
        // 初回は全て裏面表示とする
        this.CardImage.sprite = Resources.Load<Sprite> ("Image/card_back");

        // 選択判定フラグを初期化する
        this.mIsSelected = false;

        // アルファ値を1に設定
        this.CanGroup.alpha = 1;

        // 座標情報を取得しておく
        this.mRt = this.GetComponent<RectTransform> ();

    }

mRt変数に、このCardオブジェクトの座標情報が導入されました。
次は、onClickにて、カードが回転する処理を記述します。


    public void OnClick () {

        // カードが表面になっていた場合は無効
        if (this.mIsSelected) {
            return;
        }

        Debug.Log ("OnClick");

        // Dotweenで回転処理を行う
        this.mRt.DORotate (new Vector3 (0f, 90f, 0f), 0.2f)
            // 回転が完了したら
            .OnComplete (() => {
                // 選択判定フラグを有効にする
                this.mIsSelected = true;

                // カードを表面にする
                this.CardImage.sprite = this.mData.ImgSprite;

                // Y座標を元に戻す
                this.onReturnRotate ();
            });
    }

    /// <summary>
    /// カードの回転軸を元に戻す
    /// </summary>
    private void onReturnRotate () {

        this.mRt.DORotate (new Vector3 (0f, 0f, 0f), 0.2f)
            // 回転が終わったら
            .OnComplete (() => {
                // 選択したCardIdを保存しよう!
                GameStateController.Instance.SelectedCardIdList.Add (this.mData.Id);
            });
    }

this.mRt.DORotate () では、「回転する回転」と「回転する時間」を設定しています。
この処理では カードオブジェクトのY軸を「0.2秒」かけて 90度 に変更する 内容になっています。

下の OnComplete() は、上のDORotate()の処理が終了した後に呼ばれます。
回転が終わった後にカード画像を「表面」に変更して、「onReturnRotate」関数を読んでおります。


onReturnRotate関数は 先ほど 90度にしたカードオブジェクトの角度を元に戻す関数です。
選択したカードが表面に戻ったら、「SelectedCardIdList」に選択したカードIDを保管しています。

ここまで出来たらGameを起動して、実際にカードを選択しましょう。

f:id:Wojtek:20190928183425g:plain


どうでしょうか! カードをくるっと回転したと思います。

次はカードを背面する時にも同様の処理を実装していきましょう。


今回の回転処理は、

1.カードを90度に回転した後、カード画像を変更する
2.変更したあと、カードの角度を元に戻す

の2つになっています。

そこで、「カードを90度に回転する」関数と「カードの角度を元に戻す」関数の2つを作成しましょう。
そうすれば、「カードを選択した時」「カードを裏面に戻す時」でも、同じ関数を呼ぶだけで処理を実行できるようになります。

今回はこの関数の共通化を実装していきましょう!

まずは using System を追加してください。

using System;
/// <summary>
    /// カードを90度に回転する
    /// </summary>
    private void onRotate (Action onComp) {

        // 90度回転する
        this.mRt.DORotate (new Vector3 (0f, 90f, 0f), 0.2f)
            // 回転が終了したら
            .OnComplete (() => {

                if (onComp != null) {
                    onComp ();
                }
            });
    }

    /// <summary>
    /// カードの回転軸を元に戻す
    /// </summary>
    private void onReturnRotate (Action onComp) {

        this.mRt.DORotate (new Vector3 (0f, 0f, 0f), 0.2f)
            // 回転が終わったら
            .OnComplete (() => {

                if (onComp != null) {
                    onComp ();
                }
            });
    }

「カードを90度に回転する」関数と「カードの角度を元に戻す」関数を作成しました。

ポイントは それぞれの関数の引数にある「Action onComp」という部分です。
今回は「Action」側の コールバック関数を実装しました。

コールバックとは、「何かの処理が終わった後に呼ばれる処理を予め設定しておく」関数のことです。
今回の例だと、「回転する処理が終わった」後に設定しておいたコールバックを実行する!
内容になっております。

では、共通化した部分をOnClick関数に導入し、コールバックがどのように設定されているのかを確かめてみましょう!

    public void OnClick () {

        // カードが表面になっていた場合は無効
        if (this.mIsSelected) {
            return;
        }

        Debug.Log ("OnClick");

        // 回転処理を行う
        this.onRotate (() => {
            // 選択判定フラグを有効にする
            this.mIsSelected = true;

            // カードを表面にする
            this.CardImage.sprite = this.mData.ImgSprite;

            // Y座標を元に戻す
            this.onReturnRotate (() => {
                // 選択したCardIdを保存しよう!
                GameStateController.Instance.SelectedCardIdList.Add (this.mData.Id);
            });
        });
    }

ここでポイントなのが、this.onRotate (() => {}  のように、関数の引数のところでなにやら怪しげな処理を行なっているところです。

これは「無名関数」と呼ばれるもので その名の通り、「名前を付けずに定義された関数」になります。
主にUnityでは「ラムダ式」による記述が主流とおり、

() => {
   //ここに処理を書く
}

上記のように{}で囲った部分に記述した処理が、無名関数が呼ばれた時に実行されます。

カード背面表示にする時は以下のように記述しましょう。

    ///  <summary>
    /// カードを背面表記にする
    /// </summary>
    public void SetHide () {

        // 90度回転する
        this.onRotate (() => {

            // 選択判定フラグを初期化する
            this.mIsSelected = false;

            // カードを背面表示にする
            this.CardImage.sprite = Resources.Load<Sprite> ("Image/card_back");

            // 角度を元にもどす
            this.onReturnRotate (() => {
                Debug.Log ("onhide");
            });
        });
    }

それでは、Gameを起動して動作をみてみましょう。


f:id:Wojtek:20190928183655g:plain


カードが回転するようになりましたね。
ですが、選択したカード以外も回転してしまう問題があります。

そこでCard.csに 選択済みのカードか否か外部からでも判別できる変数を追加しましょう。

選択済みのカードだけ回転するようにしよう!

public class Card : MonoBehaviour {

    // カードのID
    public int Id;

    // 表示するカードの画像
    public Image CardImage;

    // 透過処理用
    public CanvasGroup CanGroup;

    // 選択されているか判定
    private bool mIsSelected = false;

    public bool IsSelected => this.mIsSelected;

Card.csに IsSelected 変数を実装しました。

ここでは 「IsSelected => this.mIsSelected」と記述しており、
これによって mIsSelected の値が IsSelectedにいつでも反映される状態になっています。
逆に、IsSelected の値を変更しようとしても、mIsSelectedには全く反映されません。

これで外部からでも選択済みカードか判別できるようになったため、CardCrateManagerにてその判別処理を実装します。

// <summary>
    /// 取得していないカードを背面にする
    /// </summary>
    public void HideCardList (List<int> containCardIdList) {

        foreach (var _card in this.CardList) {

            // 既に獲得したカードIDの場合、非表示にする
            if (containCardIdList.Contains (_card.Id)) {

                // カードを非表示にする
                _card.SetInvisible ();
            }
            // カードが表麺 && 獲得していないカードは裏面表示にする
            else if (_card.IsSelected) {

                // カードを裏面表示にする
                _card.SetHide ();
            }
        }
    }


判別処理が実装出来ましたね。

では、Gameを起動してみましょう!。


f:id:Wojtek:20190928183858g:plain


綺麗にアニメーションするようになりましたね!。

ここまでで、神経衰弱の土台は出来上がりました!
次回からはブラッシュアップ版を作成していきたいと思います!