Unityでソシャゲを作りたい#05 クエスト選択画面を作る。

作ります。

クエストの選択画面は、クエスト一覧が表示されて、好きなのを選択する初期の分けられる前のパズドラみたいなイメージです。

やりたいこと

今回は通信が入ってやや複雑なのでやることを整理しておきます。

今回やりたいことは

ゲームからリクエストを送る

サーバから開催中のクエスト情報一覧が送られてくる

それをリストとして画面に表示する

っていう感じです。

今回は表示用の画像も一緒にサーバから送られてきます。

サーバの作り方は個々調べてください。

作成

前回作ったクエストパネルのプレハブを編集していきます。

画像1

Qest_viewが縦のスクロールビューです。

前回は触られたくなかったのでRaycastを外しましたが、今回は触ってほしいので外しません。とは言ってもボタンがあるので外しててもその上触れば動くんですが。

パネルとビューポートの設定は上記以外ほぼほぼ一緒です。

コンテンツだけ若干違います。

画像2

前回はコンテンツ領域のサイズをスクリプトから手動設定しましたが、今回はContentSizeFilterなるものを追加したら子要素のサイズに合わせて広がってくれるらしいと知ったのでそれが増えてます。

前回もこれでよかったですが、あの頃の僕はこれを知りませんでした。

薄々気づきそうですが、前回はスクロールを完全にスクリプトで制御したかったので触られないようにレイキャスト消してましたがUI要素を置いたらその上は触れちゃいます。なので前回のスクリプトちょっと改修してます。

余談でした。

他に、タイトル用のImageを追加しておきました。画像作って設定すればタイトルを表示できます。

buttonは今回はサーバと通信するのでリクエスト呼び出しのテスト用です。

他に、クエストに入る用のボタンをプレハブ化して持っておきます。

なんとなくパネルに入れてるのは、後々ほかに表示したい情報が増えたとき楽なようにです。

画像3

あとはスクリプトを書きます

サーバ側の処理はさておき、リクエストを飛ばすとクエストの情報を返してくれるものが存在すると仮定します。

今回は普通にAPIサーバ作ってそこにリクエスト飛ばしてます。

帰ってくるのは

{
    "0":{"image":画像データ,"name":名前},
    "1":{"image":画像データ,"name":名前}, .....
}

みたいな形の長さが不明のオブジェクトです。

この画像たちをボタンの背景に設定して縦一列に並べます。

{"image":画像データ,"name":名前}の部分だけクラスで形を定義します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;

public class Qest_script : MonoBehaviour{
   void Start(){
       Set_Qest();
   }
   
   //画面要素のサイズ感設定
   void Set_Qest(){
       float w = Screen.width;
       float h = Screen.height;
       float ah = GameObject.Find("Home_view(Clone)").GetComponent<RectTransform>().sizeDelta.y;
       GetComponent<RectTransform>().sizeDelta     =   GameObject.Find("Home_view(Clone)").GetComponent<RectTransform>().sizeDelta;
       GameObject Qview = GameObject.Find("Qest_view");
       GameObject title = GameObject.Find("Q_title");
       
       title.GetComponent<RectTransform>().sizeDelta         = new Vector2(w,w/7f);
       title.GetComponent<RectTransform>().localPosition     = new Vector2(0f,(ah/2f)-(title.GetComponent<RectTransform>().sizeDelta.y/2f));
       Qview.GetComponent<RectTransform>().sizeDelta = new Vector2(w,ah-title.GetComponent<RectTransform>().sizeDelta.y);
       Qview.GetComponent<RectTransform>().localPosition = new Vector2(0f,-title.GetComponent<RectTransform>().sizeDelta.y/2f);
   }
   
   //リクエスト送る
   public void QestLoad(){
       StartCoroutine("QestAccess", "ここにサーバにアクセスするURLが入ります");
   }
   
   //読み終わったらこれが動く
   public void QestLoaded(JObject res){
       //一こずつ取り出す
       foreach(var qest in res){
           //いったん文字列に直す。qestそのまま入れると形が変になるので、Valueの方だけ
           string jsonStr = JsonConvert.SerializeObject(qest.Value, Formatting.None);
           //クラスにハメる
           QestData Q = JsonUtility.FromJson<QestData>(jsonStr);
           //プレハブを呼び出して当てはめていく
           GameObject Q_ct = (GameObject)Resources.Load(new ConfigDatas().prefabTempPath+"Home/Qest/Qest_ct");
           GameObject QCT =Instantiate(Q_ct) as GameObject;
           float btw = Screen.width*0.8f;
           QCT.GetComponent<RectTransform>().sizeDelta = new Vector2(btw , btw/4f);
           QCT.transform.SetParent(GameObject.Find("Q_content").transform, false);
           //画像をbase64っていうルールで変換した文字列データがimageに入ってるので、それをbyte[]に直してからSpriteにする関数に入れる
           //完成したSpriteはそのままimageに入れる。
           //同性同名がいっぱいいるのでFindは使えないから子要素を参照できるgetChildを使う。
           QCT.transform.GetChild(0).GetComponent<Image>().sprite = CreateSpriteFromBytes(Convert.FromBase64String(Q.image));
       }
   }
   
   //byte[]の画像データをSpriteにしてくれる関数
   public static Sprite CreateSpriteFromBytes(byte[] bytes){
       int pos = 16;
       int width = 0;
       for (int i = 0; i < 4; i++)
       {
           width = width * 256 + bytes[pos++];
       }
       int height = 0;
       for (int i = 0; i < 4; i++){
           height = height * 256 + bytes[pos++];
       }
       Texture2D texture = new Texture2D(width, height);
       texture.LoadImage(bytes);
       return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
   }
   //実際リクエストして戻り値受け取るコルーチン処理
   IEnumerator QestAccess(string url){
       UnityWebRequest webRequest = UnityWebRequest.Get(url);
       yield return webRequest.SendWebRequest();
       if (webRequest.isNetworkError){
           Debug.Log(webRequest.error);
       }else{
           //不定形のJsonをクラス定義なしでオブジェクト化してくれる
           JObject jsonObj = JObject.Parse(webRequest.downloadHandler.text);
           //終わったら終了時関数呼び出す。
           //コルーチンスタート時は引数1個しか送れないらしいのでURLもコールバックもっていうのは無理な模様。
           //引き数Funcにしてそれの呼び出し方でurl返すようにしたらできるか?
           QestLoaded(jsonObj);
       }
   }
}
//クエストデータの形を決めるクラス
//jsonutilityで楽に変換するには必要
public class QestData{
   public string image;
   public string name;
}

こんな感じですね。

ボタン押した際の挙動はまだ先を作ってないので入れてないですが、まぁ後々入れればいいでしょう。

画像4

サーバから画像がちゃんときてればこんな感じで表示されます。

この方式だと容量は食わないですが、通信量を食うのでお勧めはできませんが、画像はさておきクエストの情報はこうやって受け取れます。

JObjectがlinqだって気づかなかったせいで半日無駄にしました。

明日はもっと進むといいね。ハム太郎。



この記事が気に入ったらサポートをしてみませんか?