UIを裏返しにする【トランプを例に】

# 0.完成像
![StudyShaderG-test-PC_-Mac-_-Linux-Standalone-Unity-2020.3 (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1233990/25c12fc1-f43d-c910-fc20-0271d0710c85.gif)

UIのimage（トランプとか）をアニメーションつきで、任意のタイミングで裏返し・表返しできるようにする。

# 1.環境
- Unity2020.3.21f(LTS)
- Microsoft Visual Studio Community 2019 Version 16.11.8

# 2.解答（スクリプト）
とりあえず解答を書いてみる。

## 2-1.UI→ImageでImageのUIを作成
## 2-2.そのImageにアタッチするスクリプト```FrontBackManager.cs```を作成

```C#:FrontBackManager.cs
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// UIの表裏を実装する
/// 裏返し・表返しのアニメーションを実装する
/// </summary>

public class FrontBackManager : MonoBehaviour
{
    RectTransform rectTransform; //RectTransformコンポーネント
    public bool front = true; //現在の状態を管理。表面か否か。デフォルトはオン（表面）。

    Image image; //Imageコンポーネント
    Sprite frontsprite; //表面のスプライト（画像）
    [SerializeField] Sprite backsprite; //裏面に表示するスプライト（画像）

    void Start()
    {
        rectTransform = GetComponent<RectTransform>(); //recttransformコンポーネント取得
        image = GetComponent<Image>(); //Imageコンポーネント取得
        frontsprite = image.sprite; //表面のスプライト（画像）を変数に保存
    }

    void Update()
    {
        //ここでメソッドを毎フレーム呼ぶ
        ChangeAnim(front);
    }

    //以下は毎フレーム呼ぶことで連続したアニメーションになるメソッド
    void ChangeAnim(bool front)
    {
        //表返し
        if(front) //front==trueと同義
        {
            if (rectTransform.eulerAngles.y > 0) //もしrotation.yが0より上だったら
            {
                rectTransform.Rotate(0, 1, 0); //回転する

                //rotation.yが270以上で、かつ表示されているスプライトが表のスプライトではなかったら
                if(rectTransform.eulerAngles.y>270&&image.sprite!=frontsprite)
                {
                    image.sprite = frontsprite; //表のスプライトに変更する
                }
            }
        }
        else //裏返し
        {
            if(rectTransform.eulerAngles.y < 180) //もしrotation.yが180未満だったら
            {
                rectTransform.Rotate(0, 1, 0); //回転する

                //rotation.yが90以上で、かつ表示されているスプライトが裏のスプライトではなかったら
                if(rectTransform.eulerAngles.y >90 && image.sprite!=backsprite)
                {
                    image.sprite = backsprite; //裏のスプライトにする
                }
            }
        }
    }
}
```

## 2-3.Imageの諸々設定をする
- Imageコンポーネントの```Scource Image```に__表面のスプライト（画像）__をドラッグ&ドロップする。
- FrontBack.csのスクリプトの```Backsprite```の項目に、__裏面のスプライト（画像）__をドラッグ&ドロップする

![スクリーンショット (511).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1233990/68c9d333-85bb-64cf-1b15-273e8b91610e.png)

# 3.使い方
とりあえずお試ししたいのなら、ゲームプレイ中にFrontBack.csのスクリプトのfrontのチェックボックスを外したり入れたりしてみよう。
まあこのスクリプト一つで完結するはずもないので、あとは各自、ほかのスクリプトから操作するなり、このスクリプトを改造するなりしてください。

![StudyShaderG-test-PC_-Mac-_-Linux-Standalone-Unity-2020.3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1233990/c319e28d-b75a-bbf5-18a1-c2b981c46c44.gif)

# 4.開発後記
UIって今までY軸に回転できないと思っていたのだけれど、試しにやってみたら案外できてしまったので、こんなものを作ってみた。
UIは裏返しにしようがなんだろうが、レイヤーの表示順番をしっかり守る生き物なので、こちらで能動的にスプライトを変える必要がある。

スクリプトはif文の中にif文のさらに中にif文、という若干面倒な構造をしているが、ちゃんと言語化するとこんなイメージ。

Y軸が0度
↓
↓　　〇まだ表
↓
Y軸が90度
↓
↓　　〇裏返る
↓
Y軸が180度
↓
↓　　〇まだ裏
↓
Y軸が270度
↓
↓　　〇表返る
↓
Y軸が360度(=Y軸が0度)

まあ、Unityの面倒な角度の変更の方法については言及していないが（オイラーとかクォータニオンとか）、一番簡易にと突き詰めると、これが最適解じゃないか…？

あとはカードの後ろの画像については、トランプみたいに複数枚のカードをUIで扱う場合でもどうせ後ろの画像は共通だと思うので、一気に変更しやすいように仕組んだつもり。

適当に一時間くらい、遊びで作ってみたスクリプトとしては、汎用性が高いと自負している。

# 5.思いつく限りの注意点（後々気づけば追記更新するかも）
- もしほかの角度(x軸、z軸)を任意の数値だけ傾けていた場合
　→Y軸で回転させているので、変な挙動になると思う。解決策としては、最初から縦向きの画像素材を用意しておくのが最適解、無理ならばスクリプトを改造して、X軸で回転させるようにとか工夫したらいいのでないかな。

以上