【Unity】UIでポップアップウィンドウを作る

投稿者: | 2020-12-29

UIのパネルとテキストでポップアップウィンドウを作ってみました。テキストだけでボタンは無く自動で画面外に流れます。

まずポップアップを表示するCanvasを作って、UI Scale ModeをScale With Screen Sizeにします。

テキストをパネルの子にしたプレハブを作りました。パネルにはスクリプトとAnimatorがついています。

これらを上のCanvasの子としてシーンに配置し、Gameウィンドウを見ながらパネルのサイズを調節して、それに合わせてテキストのWidthとHeightも調節します。

Horizontal OverflowはWrapにすると、Widthの長さで折り返します。あまり長い文章は使わないことにして、Vertical OverflowでTruncateを選択し溢れたら表示しないようにしました。

パネルを選択してAnimationウィンドウで新しいアニメーションクリップを作ります。Add PropertyからRectTransformのAnchored Positionを追加できるので、パネル位置のアニメーションを付けられます。

左下で画面外から出現して、少し止まった後また画面外に逃げていくアニメーションを作りました。

ポップアップウィンドウを管理するスクリプトを空のゲームオブジェクトにつけて、表示するCanvasと上のパネルとテキストのプレハブをアタッチします。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Notification : MonoBehaviour
{
    [SerializeField] Canvas canvas;
    [SerializeField] NotificationPanel notificationPanelPrefab;
    NotificationPanel currentPanel;

    [SerializeField] List<string> texts;
    bool IsWaiting;

    static Notification instance;

    // インスタンスを取得
    public static Notification GetInstance()
    {
        return instance;
    }

    private void Awake()
    {
        instance = this;
        texts = new List<string>();
    }

    // テキストをリストに入れてポップアップを表示
    public void PutInQueue(string text)
    {
        texts.Add(text);
        StartNext();
    }

    void StartNext()
    { 
        // 待機中でなくてテキストが残っていれば
         if(!IsWaiting && texts.Count != 0)
        {
            IsWaiting = true; // 待機中にする
            // ポップアップウィンドウを作る
            currentPanel = Instantiate(notificationPanelPrefab.gameObject, canvas.transform).GetComponent<NotificationPanel>();
            currentPanel.SetText(texts[0]); // テキストを入れる
        }
    }

    // アニメーションが終わったら
    public void AnimationEnd()
    {
        // リストから削除
        texts.RemoveAt(0);
        IsWaiting = false; // 待機中でなくする
        StartNext(); // 次のポップアップを表示
    }

}

ポップアップウィンドウを表示したいときは、静的メソッドからこのインスタンスを取得して、テキストをリストに入れます。すると、ポップアップが表示中でなければ上のプレハブからポップアップウィンドウがインスタンス化されます。

ポップアップが表示されているときに次のポップアップのためのメソッドが呼ばれた場合、テキストをリストに入れて待機します。

インスタンス化されるとアニメーションがすぐに始まります。アニメーションが終わるとメソッドが呼ばれて、最初のテキストをリストから削除し待機中でなくしてから次のポップアップを表示します。もしリストが空なら表示されません。

パネルに付けたスクリプトでは、テキストをセットするだけです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class NotificationPanel : MonoBehaviour
{

    public void SetText(string text)
    {
        Text t = transform.GetChild(0).GetComponent<Text>();
        t.text = text;
    }

}

アニメーターコントローラーでは、デフォルトステートに上のアニメーションが付いています。

このBaseレイヤーにスクリプトがついていてアニメーションが終了したときに終了メソッドを呼びます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NotificationBehaviour : StateMachineBehaviour
{
    // OnStateEnter is called before OnStateEnter is called on any state inside this state machine
    //override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    
    //}

    // OnStateUpdate is called before OnStateUpdate is called on any state inside this state machine
    //override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    
    //}

    // OnStateExit is called before OnStateExit is called on any state inside this state machine
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
       if(stateInfo.IsTag("End"))
        {
            Notification.GetInstance().AnimationEnd(); // アニメーションの終了を教える
            Destroy(animator.gameObject); // パネルを破壊
        }
    }

    // OnStateMove is called before OnStateMove is called on any state inside this state machine
    //override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    
    //}

    // OnStateIK is called before OnStateIK is called on any state inside this state machine
    //override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    
    //}

    // OnStateMachineEnter is called when entering a state machine via its Entry Node
    //override public void OnStateMachineEnter(Animator animator, int stateMachinePathHash)
    //{
    //    
    //}

    // OnStateMachineExit is called when exiting a state machine via its Exit Node
    //override public void OnStateMachineExit(Animator animator, int stateMachinePathHash)
    //{
    //    
    //}
}

ステートを選択してインスペクタからタグが付けられます。

アニメーションがついたステートからどこにも遷移しないと、OnStateExitメソッドが呼ばれないようです。遷移のインスペクタでは1回のアニメーションで自動で遷移させます。

これで複数のポップアップウィンドウを順番で表示できました。

if(Input.GetKeyDown(KeyCode.Alpha7))
{
    Notification.GetInstance().PutInQueue("はじめの通知");
    Notification.GetInstance().PutInQueue("2番目の通知");
}
else if (Input.GetKeyDown(KeyCode.Alpha8))
{
    Notification.GetInstance().PutInQueue("通知通知通知通知通知通知通知通知通知通知通知通知通知通知通知");
}

コメントを残す

メールアドレスが公開されることはありません。