ユニティちゃんを眺めたいので頑張る②

Unity

ユニティちゃんを眺めたいので頑張る①の続き。

今回から必要な機能を実装していきます。

Scroll View

まずはスクロールビューの配置から。

今回はボタンを横に並べようと思います。シーンにCanvasとPanelを置き、スクロールビューを表示したい場所を決めてPanelの中にUI -> Scroll Viewを追加。

UnityChanViewer_002

こんな感じに配置しました。次にScroll Viewの設定。

Scroll ViewのInspectorを見るとコンポーネントのScroll Rectがくっついています。ボタンを横に並べたいので今回はVerticalが不要ですね。チェックボックスを外してVertical ScrollbarもNoneに変更。

UnityChanViewer_003

HierarchyのScroll View内にあるScrollbar Verticalも削除。Scroll ViewとScrollbar Horizontalの位置やサイズを画面横いっぱいに表示されるように調整しました。

UnityChanViewer_004

UnityChanViewer_005

今はこんな感じ。次にスクロールビューの中に表示させたいボタンを配置していきます。

 

Scroll View -> Viewport -> ContentにContent Size FitterHorizontal Layout Groupのコンポーネントを追加して画像のように設定。

  • Content Size Fitter 要素の数に合わせてオブジェクトのサイズを調整してくれる
  • Horizontal Layout Group 要素を横に整列

UnityChanViewer_006

Contentの中にUI -> Buttonを置いて、ButtonにLayout Elementコンポーネントを追加。Min WidthとMin Heightにチェックを入れ、ボタンのサイズを設定。

UnityChanViewer_007

ボタンの表示位置はContentのHorizontal Layout Groupから設定できます。

UnityChanViewer_008

設置したButtonを複製して並べたときの表示を確認。

UnityChanViewer_009

いい感じに並べることができました! スクロールビューで縦に要素を並べたいときはHorizontalをVerticalに置き換えて設定していけば作れます。

確認できたので複製したButtonたちは削除。

今回追加したスクロールビューでは、ボタンを押したときにユニティちゃんの表情を変更したいので、配置したUIの名前を以下の画像の通りに変更。

UnityChanViewer_010

ボタンの中に表示させたいものは、Animation Clipのファイル名にしようと思うので、デフォルトで入っているTextを使います。文字のサイズ調整だけ設定したいのでBest Fitにはチェックを入れました。

ボタンの設定が済んだらFaceNodeをプレハブ化。プレハブ化したらHierarchyのFaceNodeは削除。

UnityChanViewer_011

要素を動的に追加

スクロールビューに表示する要素を動的に追加するスクリプトを作成。

FaceListManager.csを作成して以下を記述。

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

public class FaceListManager : MonoBehaviour {

    // ユニティちゃんを指定する
    public GameObject unitychanObj;

    // ユニティちゃんのアニメーターを格納する
    private Animator anim;

    // 表情のアニメーションを配列に格納
    public AnimationClip[] animations;

    // 作成した表情切替ボタンをリストに格納
    private List<Button> nodes = new List<Button>();

    // ウェイト用
    public float delayWeight;

    // FaceList内コンテンツオブジェクト
    public GameObject faceListContent = null;

    // FaceNode
    public GameObject faceNode = null;

    // リストが作成された
    private bool isLoad = false;

    // ボタンが押されている
    private bool isPush = false;

    void Awake () {
        // アニメーターを取得しておく
        anim = unitychanObj.GetComponent<Animator> ();
    }

    void Start () {
        this.CreateFaceList ();
    }

    float current = 0;

    void Update ()
    {
        // 押下フラグが折れている場合にcurrentを線形補間する
        if (!isPush) {
            current = Mathf.Lerp (current, 0, delayWeight);
        }
        anim.SetLayerWeight (1, current);
    }

    // 表情切替リストを生成
    private void CreateFaceList () {
        Debug.Log ("表情ノードを生成します");
        if (!isLoad)
        {
            // アニメーションの数だけ表情切替ボタンを生成する
            foreach (var animation in animations)
            {
                // 子オブジェクトをインスタンス化して配列に格納する
                Button obj = this.SetChild (faceListContent, faceNode, animation.name).GetComponent <Button> ();

                // アニメーション名をボタンにセットする
                // ボタンノードは子オブジェクト
                obj.GetComponentInChildren <Text> ().text = animation.name;

                nodes.Add (obj);
            }
            isLoad = true;
        }
        Debug.Log ("表情ノードを生成しました");
        Debug.Log ("表情ノードの数:" + nodes.Count);
    }

    // 子オブジェクトセット処理
    private GameObject SetChild (GameObject parent, GameObject child, string animationName, string name = null) {
        // プレハブからインスタンスを生成
        GameObject obj = Instantiate (child);

        // 作成したオブジェクトを子として登録
        obj.transform.SetParent (parent.transform);

        obj.transform.localPosition = new Vector3 (0f, 0f, 0f);
        obj.transform.localScale = new Vector3 (1f, 1f, 1f);

        // ボタンにイベントトリガーを追加:アニメーション実行
        obj.AddComponent<EventTrigger> ();
        var trigger = obj.GetComponent<EventTrigger> ();
        trigger.triggers = new List<EventTrigger.Entry> ();

        // PointerDown(押している)時のイベントを設定
        var entryDown = new EventTrigger.Entry ();
        entryDown.eventID = EventTriggerType.PointerDown;
        entryDown.callback.AddListener ((x) => {
            // 押下フラグを立てる
            isPush = true;
            anim.CrossFade (animationName, 0);
            current = 1;
        });
        trigger.triggers.Add (entryDown);

        // PointerUp(離した)時のイベントを設定
        var entryUp = new EventTrigger.Entry ();
        entryUp.eventID = EventTriggerType.PointerUp;
        entryUp.callback.AddListener ((x) => {
            // 押下フラグを折る
            isPush = false;
        });
        trigger.triggers.Add (entryUp);

        // 作成したオブジェクトの名前に(Clone)がつかないようにプレハブの名前を再付与
        obj.name = (name != null) ? name : child.name;

        return obj;
    }
}

Hierarchyに空のGame Objectを作成し、FaceListManagerに名前を変更。上記のスクリプトファイルをアタッチ。

Inspectorで調整できるようにしてみました。

CreateFaceListでボタンを生成しています。

animationsに格納されたAnimation Clipの数だけSetChildでボタンを生成。ボタンを押している間だけアニメーションさせたいのでイベントトリガーを付与し、押している間と離した際の動きを設定しました。

アニメーションについては、

anim.CrossFade (animationName, 0);

これで動かせます。

animationNameはAnimation Clip名です。0としてるとこはフェードだったかな。今回は関係ないので0にしています。

 

Inspectorでの各設定について。

Inspectorから、AnimationsのSizeにアニメーションの数を設定します。表情のアニメーションは17個。

Element 0〜16に各Animation Clipを指定。

Delay Weightはアニメーションのウェイト用。表情が切り替わるアニメーションの切り替わる速度を調整できます。

Face List ContentにScroll View -> Viewport -> Contentにあたるオブジェクトを指定。

Face Nodeに先ほど作成したボタンのプレハブを指定。

これで動的にボタンを配置する準備が整いました。

動かしてみる

動かす前にユニティちゃんの表情がわかりやすい位置にカメラを調整。

あと、ユニティちゃんに元からついてるUIを非表示に変更。HierarchyにあるunitychanのIdle ChangerとFace Updateを無効化すれば非表示にできます。

それではいざ再生!

UnitychanViewer_FaceList

天使や……!

やったぜ! これで天使の表情一つ一つを好きなだけ眺められる! もちろんスマホでも動きます。

次はモーションを切り替えてみたいと思います!

Light_Frame
この作品は、『ユニティちゃんライセンス』で提供されています。

コメント

タイトルとURLをコピーしました