Unityでソシャゲを作りたい#04 ホーム画面を作る

さて、本日から盆休みなので一気に進めていきたいと思います。

ホーム画面の機能全般を作ってしまいます。

各画面の細部は小分けにしますが、
・ヘッダー
・フッター
・ホーム
・クエスト
・ショップ
・ガチャ
・育成
・コンテンツ

まではつくります。

ヘッダー

表示する要素は

・石
・金
・スタミナ
・名前
・経験値
・ランク

でいきます。

文字が出ればいいので全部テキストで。パネルにまとめてこう。

画像1

これ、例えば文字枠ごとに背景を設定する場合はテキストごとにさらにパネルに入れて各パネルにImageを設定するとかしますが、今回はスクリプト制御でアスペクト比を一定にしてるのでレイアウトが崩れません。

よって全部分の背景を親パネルに設定するだけで十分です。

この方式は理論上大丈夫ってだけであんまりよくないのでおすすめはしませんが、まぁいいでしょう。

各テキストに文字サイズ自動でそろえてくれる設定をしていきます。

画像2

BestFitにチェック入れて0-300(300が最大)に設定しときます。

フォントサイズ超えないと反映しないとかあったら嫌なので絶対超えるように元のフォントサイズも一応300にしてます。

これで枠の大きさを指定するだけで勝手にフォントサイズ直してくれます。

フォント変えたいときはプロジェクトにフォントのファイル置いて、Fontってとこに投げ込めば設定できます。

したらスクリプトを書きます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Headre_script : MonoBehaviour{
   void Start(){
       Set_Header();
   }
   void Update(){
       //Dataマネージャを作ってそこの値を参照し毎フレーム表示を書き換える処理を後で入れる
   }
   public void Set_Header(){
       GameObject HD           = GameObject.Find("Header_panel(Clone)");
       GameObject HD_Stone     = GameObject.Find("HD_Stone");
       GameObject HD_Stamina   = GameObject.Find("HD_Stamina");
       GameObject HD_Coin      = GameObject.Find("HD_Coin");
       GameObject HD_Rank      = GameObject.Find("HD_Rank");
       GameObject HD_EXP       = GameObject.Find("HD_EXP");
       GameObject HD_Name      = GameObject.Find("HD_Name");
       float w = Screen.width;
       float h = Screen.height;
      
       float txtw = w*(1f/3f);
       float txth = txtw*(1f/5f); //0-5文字はサイズが不変
       
       /*
       ↑文字枠の大きさを決める
       文字枠の横幅を決定したら高さを横に対して1/nに指定すると
       0-n文字目まではサイズが変わらない文字枠が作れる。
       */
      
       HD.GetComponent<RectTransform>().sizeDelta      =   new Vector2(w,txth*2f);
       HD.GetComponent<RectTransform>().localPosition  =   new Vector2(0f,(h/2f)-(txth*2f)*0.5f);
       
       HD_Stone.GetComponent<RectTransform>().sizeDelta        =   new Vector2(txtw*0.8f,txth*0.8f);
       HD_Stone.GetComponent<RectTransform>().localPosition    =   new Vector2(w/3f,txth/2f);
       HD_Coin.GetComponent<RectTransform>().sizeDelta         =   new Vector2(txtw*0.8f,txth*0.8f);
       HD_Coin.GetComponent<RectTransform>().localPosition     =   new Vector2(w/3f,-txth/2f);
       
       HD_Name.GetComponent<RectTransform>().sizeDelta         =   new Vector2(txtw*0.8f,txth*0.8f);
       HD_Name.GetComponent<RectTransform>().localPosition     =   new Vector2(-w/4f,txth/2f);
       HD_Stamina.GetComponent<RectTransform>().sizeDelta      =   new Vector2(txtw*0.8f,txth*0.8f);
       HD_Stamina.GetComponent<RectTransform>().localPosition  =   new Vector2(-w/4f,-txth/2f);
       
       HD_Rank.GetComponent<RectTransform>().sizeDelta         =   new Vector2(txth*1.5f,txth*1.5f);
       HD_Rank.GetComponent<RectTransform>().localPosition     =   new Vector2(0f,0f);
       HD_EXP.GetComponent<RectTransform>().sizeDelta          =   new Vector2(txtw,txth*0.5f);
       HD_EXP.GetComponent<RectTransform>().localPosition      =   new Vector2(0f,-(txth*0.75f));
   }
}

画像3

背景はあとで作るとしてこんな感じです。終了。

ホーム一式

別なとこで一回書いてますが改良するので改めて。

基本的にスクロールビューを駆使して作ります。位置設定が楽だからです。

以前作った際のを見てた人向けに捕捉ですが、以前はスクロールビューをさわって動かして、指が離れたとき一番近くの基準スクロール位置に移動する挙動でした。

がしかしこれだと画面内に別の縦スクロール要素とか入れちゃうと、その上では触って横移動ができなくなります。

そこで今回は、要素に触れたか否かによらず、触った位置からはなした位置が一定以上離れてたら画面遷移するという方針に変更しました。

では作っていきます

画像4

スクロールビューを置いてスライダーを全消ししたものになります。

それぞれ設定をしていきます。


ScrollRectがついてる最親のHome_viewはサイズをスクリプトから指定するのでトランスフォームを矢印じゃないやつにしときます。

今回は触って動かれるとうざいのでImageのRaycast Targetを切っておきます。

ScrollRectはVarticalがオフならなんでもいいと思います。

画像6

ビューポートも念のためRayCastを切って、サイズは親合わせでいいのでストレッチで全部ゼロにします。

画像7

HA_contentは子要素に個別で作成した各画面のプレハブが入るイメージです。

高さは親合わせでいいので縦だけストレッチにしときます。

Imageは今は不要なので切っちゃってますが、レイキャストオフにして全体分の背景をセットしたらいいと思います。

AddcomponentからHorizontalRayoutGroupを追加します。これがあると勝手に横一列に並べてくれるので便利です。

画像8

最親のHome_viewにスクリプトを二つつけてます。

サイズとか要素の読み込み用のと、タップ挙動管理用のです。

別に分けなくていいと思います。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HomeAll_script : MonoBehaviour{
   void Start(){
       Set_HomeAll();
   }
   void Update(){
   }
   void Set_HomeAll(){
       float w = Screen.width;
       float h = Screen.height;
       
       float hh = GameObject.Find("Header_panel(Clone)").GetComponent<RectTransform>().sizeDelta.y;
       float fh = GameObject.Find("Footer_panel(Clone)").GetComponent<RectTransform>().sizeDelta.y;
       GetComponent<RectTransform>().sizeDelta =   new Vector2(w,h-hh-fh);
       GetComponent<RectTransform>().localPosition =   new Vector2(0f,(fh-hh)/2f);
       //自分のコンテンツパネルのサイズだけ決める
       var CP = GameObject.Find("HA_Content").GetComponent<RectTransform>();
       CP.sizeDelta    = new Vector2(w*5f,CP.sizeDelta.y);
       
       //各画面のプレハブを読み込む
       GameObject H_prefab = (GameObject)Resources.Load(new ConfigDatas().prefabTempPath+"Home/Home/Home_panel");
       GameObject H =Instantiate(H_prefab) as GameObject;
       H.transform.SetParent(GameObject.Find("HA_Content").transform, false);
       GameObject Q_prefab = (GameObject)Resources.Load(new ConfigDatas().prefabTempPath+"Home/Qest/Qest_panel");
       GameObject Q =Instantiate(Q_prefab) as GameObject;
       Q.transform.SetParent(GameObject.Find("HA_Content").transform, false);
       GameObject G_prefab = (GameObject)Resources.Load(new ConfigDatas().prefabTempPath+"Home/Gacha/Gacha_panel");
       GameObject G =Instantiate(G_prefab) as GameObject;
       G.transform.SetParent(GameObject.Find("HA_Content").transform, false);
       GameObject B_prefab = (GameObject)Resources.Load(new ConfigDatas().prefabTempPath+"Home/Build/Build_panel");
       GameObject B =Instantiate(B_prefab) as GameObject;
       B.transform.SetParent(GameObject.Find("HA_Content").transform, false);
       GameObject C_prefab = (GameObject)Resources.Load(new ConfigDatas().prefabTempPath+"Home/Chara/Chara_panel");
       GameObject C =Instantiate(C_prefab) as GameObject;
       C.transform.SetParent(GameObject.Find("HA_Content").transform, false);
   }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Threading.Tasks;
using System;
public class HomeMove_script : MonoBehaviour{
   float[] poslist; //画面の位置リスト。画面がN枚なら0/N ~ N/N まで値を入れとく。
   
   void Start(){
       float w = Screen.width;
       float cw = w*4f;
       poslist=new float[]{0f,1f/4f,2f/4f,3f/4f,1f};
   }
   
   float TDP;  //触った場所のX座標
   int nowpanel=0;
   void Update(){
       //マウス版の処理
       //クリックした瞬間ならx座標を記録
       if (Input.GetMouseButtonDown(0)) {
           TDP=Input.mousePosition.x ;
       }
       //離した瞬間に移動幅を計算し画面幅の1/3以上なら動いた方向の画面に移動する
       if (Input.GetMouseButtonUp(0)) {
           if(Input.mousePosition.x-TDP<-Screen.width*0.3f){
               nowpanel+=1;
               if(nowpanel>4){nowpanel=0;}
               if(nowpanel<0){nowpanel=4;}
               move(nowpanel);
           }
           if(Input.mousePosition.x-TDP>Screen.width*0.3f){
               nowpanel-=1;
               if(nowpanel>4){nowpanel=0;}
               if(nowpanel<0){nowpanel=4;}
               move(nowpanel);
           }
       }
       
       //同じ処理のスマホでタッチ版
       if (Input.touchCount > 0) {
           if(Input.GetTouch(0).phase == TouchPhase.Began){
               TDP=Input.GetTouch(0).position.x ;
           }
           if(Input.GetTouch(0).phase == TouchPhase.Ended) {
               if(Input.GetTouch(0).position.x-TDP>Screen.width*0.3f){
                   nowpanel+=1;
                   if(nowpanel>4){nowpanel=0;}
                   if(nowpanel<0){nowpanel=4;}
                   move(nowpanel);
               }
               
               if(Input.GetTouch(0).position.x-TDP<-Screen.width*0.3f){
                   nowpanel-=1;
                   if(nowpanel>4){nowpanel=0;}
                   if(nowpanel<0){nowpanel=4;}
                   move(nowpanel);
               }
           }
           
       }
   }
   //実際に動かす処理
   public async void move(int panel){
       nowpanel=panel;
       float pos = poslist[panel];
       float nowPos=0f;
       float fpos=0f;
       ScrollRect scrollRect = GetComponent<ScrollRect>();
       fpos=scrollRect.horizontalNormalizedPosition;
       
       //一瞬で動いていいからasync使いたくないときは↓でOK
       //scrollRect.horizontalNormalizedPosition = pos;
       
       //一瞬で動くとダサいので非同期でちょっとずつ動かす
       while(true){
           nowPos=scrollRect.horizontalNormalizedPosition;
           if(nowPos==pos){break;}
           if(nowPos>pos){
               if(nowPos-((fpos-pos)/50f)<pos){
                   scrollRect.horizontalNormalizedPosition = pos;
                   break;
               }else{
                   scrollRect.horizontalNormalizedPosition = nowPos-((fpos-pos)/50f);
               }
           }
           if(nowPos<pos){
               if(nowPos+((pos-fpos)/50f)>pos){
                   scrollRect.horizontalNormalizedPosition = pos;
                   break;
               }else{
                   scrollRect.horizontalNormalizedPosition = nowPos-((fpos-pos)/50f);
               }
           }
           
           Debug.Log("now::"+nowPos);
           Debug.Log(" f ::"+fpos);
           await Task.Delay(1);
       }
   }
}

次は内側に入れる各パネルです。

内容はあとで考えればいいので適当にガワだけ作ります。

画像9

こんな感じでパネルに要素まとめただけのプレハブを作ります。

あとはスクリプト。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Home_script : MonoBehaviour{
   void Start(){
       Set_Home();
   }
   void Update(){
       
   }
   void Set_Home(){
       GameObject news = GameObject.Find("H_news");
       GameObject box = GameObject.Find("H_box");
       float w = Screen.width;
       float h = Screen.height;
       float btw = w/9f;
       GetComponent<RectTransform>().sizeDelta     =   GameObject.Find("Home_view(Clone)").GetComponent<RectTransform>().sizeDelta;
       news.GetComponent<RectTransform>().sizeDelta        = new Vector2(btw,btw);
       news.GetComponent<RectTransform>().localPosition    = new Vector2(w/8f,w/8f);
       
       box.GetComponent<RectTransform>().sizeDelta         = new Vector2(0f,0f);
       box.GetComponent<RectTransform>().localPosition     = new Vector2(0f,0f);
       
   }
}

呼ばれたらサイズ決めるくらいしかしてませんが、描画時に通信したデータが欲しい場合なんかはここでうまい事やったらいいわけです。

他の画面も同じ感じで作ります。

フッター

フッターはサイズ決めてボタン置いてOnclick指定するだけです。

画像10

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Footer_script : MonoBehaviour
{
   // Start is called before the first frame update
   void Start()
   {
       Set_Footer();
   }
   public void Set_Footer(){
       GameObject FT       = GameObject.Find("Footer_panel(Clone)");
       GameObject Home     = GameObject.Find("FT_Home");
       GameObject Qest     = GameObject.Find("FT_Qest");
       GameObject Build    = GameObject.Find("FT_Build");
       GameObject Chara    = GameObject.Find("FT_Character");
       GameObject Gacha    = GameObject.Find("FT_Gacha");
       float w = Screen.width;
       float h = Screen.height;
       float btw = w*(1f/6f);
       float bth = btw*1.5f;
       FT.GetComponent<RectTransform>().sizeDelta      =   new Vector2(w,bth);
       FT.GetComponent<RectTransform>().localPosition  =   new Vector2(0f,-(h/2f)+(bth/2f));
       Home.GetComponent<RectTransform>().sizeDelta        =   new Vector2(btw*0.8f,bth*0.8f);
       Home.GetComponent<RectTransform>().localPosition    =   new Vector2(-btw*2f,0f);
       Qest.GetComponent<RectTransform>().sizeDelta        =   new Vector2(btw*0.8f,bth*0.8f);
       Qest.GetComponent<RectTransform>().localPosition    =   new Vector2(-btw,0f);
       Gacha.GetComponent<RectTransform>().sizeDelta       =   new Vector2(btw*0.8f,bth*0.8f);
       Gacha.GetComponent<RectTransform>().localPosition   =   new Vector2(0f,0f);
       Build.GetComponent<RectTransform>().sizeDelta       =   new Vector2(btw*0.8f,bth*0.8f);
       Build.GetComponent<RectTransform>().localPosition   =   new Vector2(btw,0f);
       Chara.GetComponent<RectTransform>().sizeDelta       =   new Vector2(btw*0.8f,bth*0.8f);
       Chara.GetComponent<RectTransform>().localPosition   =   new Vector2(btw*2f,0f);
   
   }
   public void OnClick(int No){
       GameObject.Find("Home_view(Clone)").GetComponent<HomeMove_script>().move(No);
   }
}

スクリプトをFooter_Panelにつけて、ボタンのOnclickに入れるオブジェクトはFooter_Panelにし、さっき作ったHome_Viewの移動スクリプトを探して動かす関数OnClickがあるので、各ボタンはこの関数を呼び出すように設定します。

ボタンの位置と並び順が手動設定なので、そこは気を付けてください。

呼び出し

呼び出すときは、ヘッダとフッタを呼び出した後にホームを呼び出します。

ホームはサイズ指定の都合上ヘッダとフッタのサイズを参照するしくみにしちゃったからです。

計算できるのでそうするか、存在すればって形に書き換えれば、いつ呼び出しても大丈夫です。

  public void HomeMaking(){
       GameObject HD_prefab = (GameObject)Resources.Load(c.prefabTempPath+"Header/Header_panel");
       GameObject HD =Instantiate(HD_prefab) as GameObject;
       HD.transform.SetParent(Canvas.transform, false);
       GameObject FT_prefab = (GameObject)Resources.Load(c.prefabTempPath+"Footer/Footer_panel");
       GameObject FT =Instantiate(FT_prefab) as GameObject;
       FT.transform.SetParent(Canvas.transform, false);
       GameObject HA_prefab = (GameObject)Resources.Load(c.prefabTempPath+"Home/Home_view");
       GameObject HA =Instantiate(HA_prefab) as GameObject;
       HA.transform.SetParent(Canvas.transform, false);
   }

以上で完成。

画像10

あとはここの画面を作るだけです。

なんか停滞したなーって気がします。

サクサク進むといいね。ハム。

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