AIプログラムとかUnityゲーム開発について

探索や学習などを活用したAI系ゲームを作りたいと思います。

FPSなんかの銃器の切り替えUI

以前も試してみたtsubakiさんの記事のスクロールビューを使って、銃器切り替えのようなUI部品を製作中です
tsubakit1.hateblo.jp

手順がすごいややこしいので、exportしてしっかり部品化したいと思います。
久しぶりにやったらはまりました(´・ω・`)
まず、
Canvasの下にemptyを作ってScrollViewの改名
②Mask,Image,ScrollRectをアタッチ
③その下にemptyを作ってContentに改名
④HorizontalLayoutGroup、ScrollController、ContentSizeFilterをアタッチします
 横スクロール型なので、HorizonFitをPreferredSizeにします。
 (こいつらはcomponent>layoutの中にいます。UIの中にあるかと勘違いした)
⑤ScrollViewのInstanceのContentに、さっき改名したContentをドロップします
 (viewするのはこの人ね、的な登録と思う)
⑥ScrollController.csをScrollViewにアタッチ(後述)

 横スクロール型のビューに表示されるノードを作ります。
 今回はFPS銃器切り替えなので、プレイヤーが保持する銃アイテムのベースになります。
 Tsubakiさんの例では、Imageの下にImage、Text、Checkmarkがぶら下がる構成ですが、
 今回は、Imageの下にButtonを起きます。クリッカブルにしたいので。button自体で画像とテキストも出せますし。
 直接Buttonをノードにしようと思いましたがうまく行きませんでした(研究の余地あり)
 このノードには、LayoutElementをアタッチします。これがノードのサイズを意味するので、自動レイアウトが働くようです。
 これをアタッチしないとノードが重なってレイアウトされません。
 今回は、横スクロールなので、MinWidthを100にしました。
 ノードはPrefabに入れておきます。


 実行画面は以下のような感じです。AssetStoreからダウンロードしたアイコンを使ってますが、ノードはコードで15個登録しているので、Cloneが15できています。
 ノードはボタンなのでクリックするとOnClickが発生します。イベントはListenerを登録して受け取ってDebug.Logで番号を表示しています。
 ここで、プレイヤーの銃器を切りかえる処理をすればOKです(まだ作ってませんが)
f:id:yasu9780:20161001183838p:plain


 ノードを動的に登録し、ノードをクリックした場合のイベントも受信するのがScrollControllerです。
 Prefabには先程作ったノードをドロップして登録します。
 ノードの画像はmultipleで切断されているスプライトです。LoadAllで配列として読み込めます。
 ノードを動的生成し、このコードが動いているScrollContorllerの子供として登録
 まずノードの子要素のボタンを探して、画像ボタンなので画像を書き換えます。ここで銃器の名称も書き換えると良いでしょう。
 次に、イベントリスナーを登録します。私はUIからOnClickを登録する作業がすごく嫌いで面倒くさいです。
 コードでやってしまいたい。
 AddListenerでコールバック関数を登録しますが、ボタンを区別するために引数iを渡したいところですが、これがなかなか動きません。
 ラムダ式というやつで、ローカル変数を経由すると渡せました。(以前は定数を使って、AddListenerを並べてました。クイズアプリとか)

 こちらが非常に参考になりました。ありがとうございました。
naochang | 動的にボタンにデータを持った機能を加える

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

public class ScrollController : MonoBehaviour {
    [SerializeField]
    RectTransform prefab = null;
    void Start () {
        Sprite[] sp = Resources.LoadAll<Sprite>("GUNS");
        for (int i = 0; i < 15; i++)
        {
            var item = GameObject.Instantiate(prefab) as RectTransform;
            item.SetParent(transform, false);

            GameObject bt = item.transform.FindChild("Button").gameObject;

            Image img = bt.GetComponentInChildren<Image>();
            img.sprite = sp[i];

            Text txt = bt.transform.FindChild("Text").gameObject.GetComponent<Text>();
            txt.text = "Gun " + i;

            Button bt2 = bt.GetComponent<Button>();
            int j = i;
            bt2.onClick.AddListener(() => { onButtonClick(j); });
        }
    }
    void onButtonClick(int no)
    {
        Debug.Log("Button Click: " + no);
    }
}