見出し画像

ダンスゲーを作りたい#26 スクロールビューでソシャゲっぽいホーム画面を作る

先日UI作成に入って以降、どうしても進まな過ぎてなんかもやもやしています。

どうやら停滞期ですが、こういう時になんか書いて公開してることがモチベーション維持につながるわけです。

UI以外でも進められる部分は多々ありまして、先に画面遷移系の処理部分をまとめて作ってしまいます。

今回は複数の画面を1シーンで完結させる手法の一つとしてスクロールビューでシャってやったら遷移する画面の基盤を作っていきたいと思います。

完成形はこんな感じ

画像3

スクロールビューの配置

UnityのScrollViewは、基本的に

ScrollRectを持つ最親
└見える範囲
 └中身(通常画面からはみ出す)

という感じの構成です。

画像1

今回はこんな感じで画面を配置しました。

OOパネルっていうやつが個々の画面だと思っていただければOKです。

右クリから新規追加するとスクロールバーももれなくついてきますが、スクロールバーはここでは要らないので抹消してます。

設定

設定としてやっといた方が楽そうなこととしては

・最親君を縦横ストレッチにしてTBLR調整して画面いっぱいに広げる
・ビューポートも同様
・最親のScrollRectのverticalのチェックを外しておく(縦移動しなくなります)

くらいでしょうか。

スクリプトからの制御

あとはスクリプトで愚直に設定をしていきます。

まず初期設定として、

・パネルの親を横幅の画面数倍の幅に指定(高さは画面合わせ)
・各パネル要素を画面サイズぴったりに指定
・各パネルを並べる

までやります。

コードはこんな感じ

    public void PrintHome(){
       //画面の縦横幅
       float sch= Screen.height;
       float scw= Screen.width;
       Debug.Log(scw);
       GameObject.Find("HomeWindowPanels").GetComponent<RectTransform>().sizeDelta=new Vector2(scw*4f,sch);
       GameObject.Find("HomeWindowPanels").GetComponent<RectTransform>().localPosition=new Vector2(0f,0f);
       //ホーム画面の各要素を描画
       GameObject.Find("HomePanel").GetComponent<RectTransform>().sizeDelta=new Vector2(scw,sch);
       GameObject.Find("HomePanel").GetComponent<RectTransform>().localPosition=new Vector2(scw*0.5f,-sch/2f);
       GameObject.Find("QestPanel").GetComponent<RectTransform>().sizeDelta=new Vector2(scw,sch);
       GameObject.Find("QestPanel").GetComponent<RectTransform>().localPosition=new Vector2(scw*1.5f,-sch/2f);
       GameObject.Find("StudioPanel").GetComponent<RectTransform>().sizeDelta=new Vector2(scw,sch);
       GameObject.Find("StudioPanel").GetComponent<RectTransform>().localPosition=new Vector2(scw*2.5f,-sch/2f);
       GameObject.Find("ShopPanel").GetComponent<RectTransform>().sizeDelta=new Vector2(scw,sch);
       GameObject.Find("ShopPanel").GetComponent<RectTransform>().localPosition=new Vector2(scw*3.5f,-sch/2f);
   }

あとはボタン入力で移動する時とタッチ入力で移動する時の処理を指定していきます。

ボタン入力で移動

単純にボタンを押したらScrollRect.horizontalNormalizedPositionにそれぞれのパネルの位置を代入するだけです。

注意点として、まずNormalizedって書いてるところからもわかる通り0-1の範囲で正規化されています。

一番右が0、左が1っぽいです。

ここで僕は少しハマったんですが、4分割なので、それぞれの位置は0.5,1,5,2.5,3.5かと思ったらそんなことなくて、冷静に考えればわかる事ですが、下のイメージのような感じなのです。

画像2

要するに0~N枚目のうちn枚目の位置は n/(N-1) ってことです。 

コードはこんな感じにしました。

public bool nowisBTpushMove=false; //ボタンの移動とタッチの移動を分けるbool
public void MoveTo(string panel){
   nowisBTpushMove=true;
   //OOの位置に移動します。
   float pos=0f;
   float scw= Screen.width;
   
   switch(panel){
       case "Qest":{
           pos=1f;
           break;}
       case "Home":{
           pos=0f;
           break;}
       case "Shop":{
           pos=3f;
           break;}
       case "Studio":{
           pos=2f;
           break;}
       default:{
           pos=1f;
           break;}
   }
   pos/=3f;
   MoveHome(pos);
   
}
//ゆっくり動いてもらうための関数 待ち時間があるのでasync
public async void  MoveHome(float pos){
   float nowPos=0f;
   float fpos=0f;
   ScrollRect scrollRect = GameObject.Find("HomeWinsowPanelScrollView").GetComponent<ScrollRect>();
   fpos=scrollRect.horizontalNormalizedPosition;
   while(true){
       nowPos=scrollRect.horizontalNormalizedPosition;
       if(nowPos==pos){break;}
       if(nowPos>pos){
           if(nowPos-((fpos-pos)/10f)<pos){
               scrollRect.horizontalNormalizedPosition = pos;
               break;
           }else{
               scrollRect.horizontalNormalizedPosition = nowPos-((fpos-pos)/10f);
           }
       }
       if(nowPos<pos){
           if(nowPos+((pos-fpos)/10f)>pos){
               scrollRect.horizontalNormalizedPosition = pos;
               break;
           }else{
               scrollRect.horizontalNormalizedPosition = nowPos-((fpos-pos)/10f);
           }
       }
       Debug.Log(nowPos);
       await Task.Delay(1);
   }
   
   nowisBTpushMove=false;
}

適当に置いたボタンのOnclickから文字入力すればそこに行くって感じです。

ただ代入すると瞬時に移動しちゃうので、設定で何とかできそうなもんですが、愚直に関数で移動するとこも作ってあげてます。

スワイプしたら移動する

正直スワイプを検出してとかは面倒なので、指が離れた瞬間にいた場所に一番近いパネルに移動させましょう。

   float[] list = new float[]{0f,1f/3f,2f/3f,1f}; //各パネルの位置リスト
  
   void Update() {
       //離した瞬間(マウス版)
       if (Input.GetMouseButtonUp(0)) {
           if(!GetComponent<Manager_home>().nowisBTpushMove){
               //一番近い場所を求めてそこに移動
               var nearest = list.OrderBy(x => Mathf.Abs( x - GameObject.Find("HomeWinsowPanelScrollView").GetComponent<ScrollRect>().horizontalNormalizedPosition)).First();
               GetComponent<Manager_home>().MoveHome(nearest);
           }
       }
       //離した瞬間(指版)
       if (Input.touchCount > 0) {
           if (Input.GetTouch(0).phase == TouchPhase.Ended) {
               if(!GetComponent<Manager_home>().nowisBTpushMove){
                   var nearest = list.OrderBy(x => Mathf.Abs( x - GameObject.Find("HomeWinsowPanelScrollView").GetComponent<ScrollRect>().horizontalNormalizedPosition)).First();
                   GetComponent<Manager_home>().MoveHome(nearest);
               }
           }
       }
   }

ボタンを押すときも離す動作が発生して誤動作するので、ボタンを押して移動してるときはタッチイベントを無視するよっていうbool値をつけて完成です。

タッチはタッチ管理マネージャにやらせてみましたが、別に一緒でいいですねこれ。

まぁとりあえずできたのでヨシ!

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