1. 程式人生 > >unity3d5.1物體橢圓旋轉選擇介面實現(一)

unity3d5.1物體橢圓旋轉選擇介面實現(一)

  偶然在群裡看到有人拿了一張橢圓物體旋轉選擇介面來問怎麼實現(也不知道這樣描述對不對,反正是橢圓的,而且還是旋轉的,類似於關卡和角色選擇),於是

想了下自己寫了一個類似的功能,方法可能不是很完美,但是也算是一個思路吧,就當練練手熟悉unity。原圖如下:

附自己完成後的效果圖:

遺憾的是不會做動態圖片,也不知道大神寫部落格是怎麼弄執行程式碼時的動態效果圖,只能附上渣渣圖片了~


基本效果能夠達到一致,但是隻是直接移動,原本是想實現繞橢圓軌跡移動,這裡不得不說,unity動作機制幾乎沒有,原本api就難找,自己找半天連一個move的函

數都沒有,如果不去找一個外掛,只能通過update每一幀去手動設定GameObject的位置來達到move的效果,原本我以為是能夠像cocos那樣,最起碼,moveto,得有,

然後用貝塞爾模擬,可惜只能每幀重新整理的話就先不寫了。

設計思路

  • 方塊的擺佈:

    首先需要明確的是方塊的排布問題,擺佈有多種方式,可以先將所有的方塊儲存到容器,之後按照一定的座標差值來遞增,遞減這些方塊的擺放位置,最後達到

    該視覺效果,只是在排列的過程中需要長時間的除錯效果,因而沒有采用;同時也可以按照橢圓的軌跡來擺放,根據物件容器的遍歷,每次遞增或遞減一定角度

    達到該效果,這個方式是比較方便的,只需要根據當前角度偏移量來計算出方塊對應的位置即可。當然,我們還需要考慮方塊的奇偶性,在方塊為奇數時,除去

    第一個顯示在正中央的方塊,剛好還剩下偶數個方塊,左右正好排布一半,但是當方塊為偶數個時,除去第一個,還會剩下最後一個方塊。

    • 方塊為奇數時:      該情況較為簡單,除去第一個,剩下的剛好對半分成,可以這樣考慮:將所有需要排布的方塊Object存放到一個數組sprites裡邊,取size=(length+1)/2

      例如有七個方塊,前邊size個(四個)從中間開始往右遞增排布,即保證容器前size個是順次排布,剩下三個從中間(除去中間那個點)往左邊排布。

    • 方塊為偶數時:      該情況稍微複雜一點,除去第一個,再分去左右對稱的,還會多出一個來,可以這樣考慮:將所有方塊存放到一個數組sprites裡,取size=length/2

      例如有八個方塊,前邊size個(四個)從中間開始往右遞增排布,剩下三個從中間(除去中間那個點)往左邊排布,最後一個可以放到第一個的正對面。

    • 顯示層級:  在cocos2dx中,子類節點都是通過掛載到父節點的形式新增到場景中,在addchild的時候提供一個zorder引數,即精靈的渲染層級,而

      unity不同,查詢api找了半天,最後找到SetSiblingIndex函式,值越大越後顯示,沒次初始化和移動都必須重置顯示層級,所以需要單獨封裝函式。

  • 點選按鈕之後的回撥

    • 向左按鈕:點擊向左按鈕時,右邊的方塊同一往左移一格位置,左邊的方塊統一往上移一格位置,左邊最後一個方塊移動到右邊最後一個方塊
    • 向右按鈕:同理。

開始動手開發

  • 新建場景
    • 新建專案:2d,3d無所謂,這裡是3d,但是要用一般是在2d,只是專案而已。
    • 新增控制元件:首先新增七個Image物件(控制元件可以是按鈕,都行);新增left和right的button,擺佈沒有要求,隨意擺放,反正都是要做排序的。
    • 如圖:(這裡panel是沒必要的,我多加的)
  •  新增UI按橢圓順序排布指令碼
    • 新建指令碼:Ellipse.cs指令碼,物件繫結到Canvas物件。
    • 編寫程式碼:  
      //儲存需要排序的精靈容器
          public GameObject[] Sprites;
          public Transform centerPoint;//橢圓的中心點
          public float anglecheap = 25;//每個方塊間的角度偏移
          //儲存位置點
          private List<Vector3> location = new List<Vector3>();
          private float angle =270;//第一個保證是中心位置的,當前到的角度
          private float firstangle = 270;//記錄第一個角度,用以左右對稱
          private float r =90;//橢圓的兩個弦長
          private float R = 150;
        int size = 0;//即物件陣列的一半,奇數為總長度+1/2,偶數為一半<pre name="code" class="csharp">// Use this for initialization
      	void Start () 
          {//初始化size
              if (Sprites.Length % 2 == 0)
              {
                  size = Sprites.Length / 2;
              }
              else
              {
                  size = (Sprites.Length + 1) / 2;
              }
              //排序分級顯示
              makespriteSort();
              //重置渲染層級
              ResetDeep();
      	}
          //給這些精靈排序顯示
          void makespriteSort()
          {
              //取出橢圓的中心點
              Vector3 center = centerPoint.position;
              //判斷該陣列的個數奇偶性,如果是偶數,那麼需要留出一個來放到對面
              if (Sprites.Length % 2 == 0)
              {
                  //右半邊
                  for (int i = 0; i < size; i++)
                  {
                      Sprites[i].transform.position = getPosition(angle, center);
               //       m_rightsprite.Add(Sprites[i]);
                      angle += anglecheap;
                  }
                  //第一個已經得是左邊了
                  angle = firstangle - anglecheap;
                  //左半邊
                  for (int i = size; i < Sprites.Length-1; i++)
                  {
                      Sprites[i].transform.position = getPosition(angle, center);
                      angle -= anglecheap;
                    //  m_leftsprite.Add(Sprites[i]);
                  }
                  //最後一個
                  Sprites[Sprites.Length - 1].transform.position = getPosition(firstangle-180, center);
                 // m_leftsprite.Add(Sprites[Sprites.Length - 1]);
                  return;
              }
              //如果不是偶數,那麼出去中間那個,正好正常顯示
              else
              {
                  //右半邊
                  for (int i = 0;i<size; i++)
                  {
                      Sprites[i].transform.position = getPosition(angle, center);
                  //    m_rightsprite.Add(Sprites[i]);
                      angle += anglecheap;
                  }
                  //第一個已經得是左邊了
                  angle = firstangle - anglecheap;
                  //左半邊
                  for (int i = size;i < Sprites.Length; i++)
                  {
                      Sprites[i].transform.position = getPosition(angle, center);
                    //  m_leftsprite.Add(Sprites[i]);
                      angle -= anglecheap;
                  }
                  return;
              }
             
          }
          //獲取當前角度的座標
          Vector3 getPosition(float _angle,Vector3 _centerposition)
          {
              float hudu = (_angle/180f) * Mathf.PI;
              float cosx = Mathf.Cos(hudu);
              float sinx = Mathf.Sin(hudu);
              float x = _centerposition.x + R * cosx;
              float y = _centerposition.y + r * sinx;
              Vector3 point = new Vector3(x, y, 0);
              //新增到容器儲存
             location.Add(point);
              return  point;
          }
          
          //根據當前左右容器調整所有控制元件的渲染層級
          void ResetDeep()
          {
              dep = 0;
              //右半邊
              for (int i =size-1; i>=0; i--)
              {
                  Sprites[i].GetComponent<Transform>().SetSiblingIndex(dep);
                  dep++;
              }
              dep = 0;
              //左半邊
              for (int i = Sprites.Length - 1; i >=size; i--)
              {
                  Sprites[i].GetComponent<Transform>().SetSiblingIndex(dep);
                  dep++;
              }
          }
      執行後可以看到如圖效果(不要忘了把這幾個物件拖到腳本里,中心點是傳入的物件,所以有一個位置要擺好,擺在想要的中心點中,也可以自己改成手動輸入x,y,z):