【unity】入手したアイテムのログを流すUIを作ってみた

どうも、N高等学校の生徒のシュンです。Unityが本当の意味でﾁｮｯﾄﾃﾞｷﾙだけのよくある名前の人です。

この記事は、[N高等学校アドベントカレンダー](https://qiita.com/advent-calendar/2019/n-highschool)6日目の記事です。枠が空いているということで書くことにしました。
僕はょゎょゎえんじにあかつQiita自体初めて投稿するので生暖かい目でじっとりと見てくださると幸いです。

# 作ったもの
![gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541941/8440c623-f91f-f86f-0de0-c09fe40893e3.gif)
このように、アイテムを入手した時に「〇〇を手に入れた」とログを一番下に挿入して表示するようなUIを作ってみました。それぞれ一定時間経過した文章は徐々にフェードアウトしていきます。
また、文字数が長い場合改行されるようにしてみました。

ちなみにこれは今作っている脱出ゲームのようなサムシングのために作ったものなので、関係ないUIが映り込んでますが気にしないでください(？)

### 実行環境
- Unity2019.3.2f1(画像は少し古いですが変更点はないです)

# 作り方
## 前提となるオブジェクトやコンポーネントを配置
![892742318081356.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541941/a8f84119-6ecc-e420-ac2b-6283d57091a4.png)
このようにCanvasの子に空のゲームオブジェクト、その子にTextを任意の数配置します。
配置したら、空のゲームオブジェクトにVertical Layout GroupとContent Size Fitterコンポーネントを追加します。
![42456234356410.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541941/030b1a0a-b335-b50d-1fd8-a1b4eecf0bca.png)
コンポーネントの設定は画像の通りです。
Spacingは子オブジェクトの間隔なので任意の値にしてください。
またChild Alignmentは子のTextの文字の開始場所になるので、これも適当に設定してください。
位置は適当に調整してください。また、Widthを変更することでTextの文字が改行される位置を調整することができます。

Text達は特に変更する必要はありません。必要に応じてFont Sizeなどを変更してください。(ただし、Horizontal Overflowの設定をOverflowにすると改行されなくなります。)
## スクリプトを書く
```C#:OutputLog.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace Managers
{
    public class OutPutLog : MonoBehaviour
    {
        private int textCount; // 子オブジェクト(Text)の数
        private Text[] logText;
        private textProperty[] textProperty;
        [SerializeField] float fadeoutTime = 1f; // 完全に透明になるまでにかかる時間(秒)
        [SerializeField] float fadeoutStartTime = 5f; // 透明化が始まるまでにかかる時間(秒)

        void Start()
        {
            textCount = transform.childCount;
            logText = new Text[textCount];
            textProperty = new textProperty[textCount];
            for (int i = 0; i < textCount; i++)
            {
                logText[i] = transform.GetChild(i).GetComponent<Text>();
                logText[i].color = new Color(logText[i].color.r, logText[i].color.g, logText[i].color.b, 0f);
                textProperty[i].Alfa = 0f;
                textProperty[i].ElapsedTime = 0f;
            }
        }

        void Update()
        {
            // 一番上のテキストは強制的に透明化開始させる
            if (textProperty[0].Alfa == 1)
            {
                textProperty[0].ElapsedTime = fadeoutStartTime;
            }

            for (int i = textCount - 1; i >= 0; i--)
            {
                if (textProperty[i].Alfa > 0)
                {
                    // 経過時間がfadeoutStartTime未満なら時間をカウント
                    // そうでなければ透明度を下げる
                    if (textProperty[i].ElapsedTime < fadeoutStartTime)
                    {
                        textProperty[i].ElapsedTime += Time.deltaTime;
                    }
                    else
                    {
                        textProperty[i].Alfa -= Time.deltaTime / fadeoutTime;
                        logText[i].color = new Color(logText[i].color.r, logText[i].color.g, logText[i].color.b,
                                           textProperty[i].Alfa);
                    }
                }
                else
                {
                    break;
                }
            }
        }
        // ログ出力
        public void OutputLog(string itemName)
        {
            if (textProperty[textCount - 1].Alfa > 0)
            {
                UplogText();
            }
            logText[textCount - 1].text = itemName + "を手に入れた"; // ここの文字列を変えればログの文章が変わります
            ResetTextPropety();
        }
        // ログを一つ上にずらす
        private void UplogText()
        {
            // 古いほうからずらす
            for (int i = 0; i < textCount - 1; i++)
            {
                logText[i].text = logText[i + 1].text;
                textProperty[i].Alfa = textProperty[i + 1].Alfa;
                textProperty[i].ElapsedTime = textProperty[i + 1].ElapsedTime;
                logText[i].color = new Color(logText[i].color.r, logText[i].color.g, logText[i].color.b,
                                   textProperty[i].Alfa);
            }
        }
        // ログの初期化
        private void ResetTextPropety()
        {
            textProperty[textCount - 1].Alfa = 1f;
            textProperty[textCount - 1].ElapsedTime = 0f;
            logText[textCount - 1].color = new Color(logText[textCount - 1].color.r, logText[textCount - 1].color.g, logText[textCount - 1].color.b,
                                           textProperty[textCount - 1].Alfa);
        }
    }

    struct textProperty
    {
        private float _alfa;
        public float Alfa // 透明度、0未満なら0にする
        {
            get
            {
                return _alfa;
            }
            set
            {
                _alfa = value < 0 ? 0 : value;
            }
        }
        public float ElapsedTime { get; set; } // ログが出力されてからの経過時間
    }
}

```
これを空のゲームオブジェクト(Text達の親)につければ完成です。
後はログを流したいタイミングでOutPutLogメソッドを呼び出せばOKです。
fadeoutTimeとfadeoutStartTimeはそれぞれフェードアウトにかかる時間とフェードアウトが始まる時間なので、インスペクタから設定してください。
(2020/2/15追記:スクリプトをわりと変更しました、まだまともなコードになった…と思います、たぶん、おそらく、きっと)
# 終わりに
~~いかがでしたか。~~
まあ本当にいかがでしたかサイトレベルの内容なんですが、いろいろ突っ込みをもらわないよう祈りたいと思います。
実際突っ込みどころは色々あると思うので、そこはお手柔らかにお願いします…(改善点などあればぜひ教えてもらえると助かります)(関係ないですが変数とかの命名苦手です)