くるくる回るメニュー

ayumegu(プログラマー)
よろしくお願いします。

今回はクリックすると円形にくるくる回るメニューのようなものを作成してみました。
ボタンのアイコンが適当なのはご愛嬌
レイアウトはNGUIを使用しています。

こんなの

ボタンを押すと円形にサブメニューがでまして、周りをドラッグしてまわすことができます。
利用用途としては右下左下などのすみに配置すると素敵かなと
こんな感じ

あまりかさばらずにたくさんサブメニューがおけます

中身

画面は位置はこのようになっています

  • KuruKuruMenu:下記KuruKuruMenu.csをアタッチ
    • MainMenu:メインメニューです。背景の黄色いボタンと2dのCircleColliderあとはクリック時にMainMenuClickが呼ばれるようにしています。
      • Icon:ボタンのアイコン画像です
    • AroundMenuParent:サブメニューの親GameObjectです。ここにクリックされた際に呼び出すTweenScaleを0から1で設定しています。あとは2dのCircleCollider。ここをドラッグした際に回転するようにするためにつけています。
      • AroundManu:サブメニューです。位置はScriptから設定されるので適当な位置においておけばOK。ここにも2dのCircleColliderあとはサブメニューをクリックされた際のアクションなどコンポーネントを追加してね。
        • Icon:サブメニューのアイコン画像

ソースは下記1ファイル。
ちょっと無駄が多いかもですが・・・。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class KuruKuruMenu : MonoBehaviour {
  
  public GameObject mainManu;                  // メインのメニューボタンGameObject
  public Transform aroundMenuParentTran;       // サブメニューの親のTransform
  public GameObject uiCamera;                  // menuを移しているカメラ
  
  private GameObject startAroundMenu;          // 一つ目の子のサブメニュー。これの位置で現在の回転角度を算出
  private int subMenuCount = 0;             // サブメニューの数
  private bool isSubMenu;                      // サブメニューが表示されているかどうか
  private bool isRotateMenu;                   // サブメニューが開店中かどうか
  private float menuRotation;                  // 1つ目のサブメニューの回転角度
  private float radius = 150;                   // サブメニューの半径
  
  void Awake()
  {
      isSubMenu = false;
      isRotateMenu = false;
      menuRotation = 0;
      foreach(Transform tran in aroundMenuParentTran)
      {
          // サブメニューの数を数えるついでに名前変更
          if(subMenuCount == 0)
              startAroundMenu = tran.gameObject;
          subMenuCount++;
          tran.name = "SubMenu";
      }
      // 初期配置
      RotateSubMenu(0);
  }
  
  // Use this for initialization
  void Start () {
      
  }
  
  // Update is called once per frame
  void Update () {
      if(Input.GetMouseButtonDown(0) && isSubMenu && !isRotateMenu)
      {
          RaycastHit2D hit2d = Physics2D.Raycast(uiCamera.GetComponent<Camera>().ScreenToWorldPoint(Input.mousePosition), Vector3.forward);

          // 自分以外がタッチされたら閉じる 自分だった場合は回転などの処理
          if (hit2d.collider != null)
          {
              if(hit2d.collider.name == "AroundMenuParent" || hit2d.collider.name.IndexOf("SubMenu") != -1)
              {
                  if((hit2d.collider.name == "AroundMenuParent" && hit2d.collider.transform == aroundMenuParentTran) ||
                     (hit2d.collider.name.IndexOf("SubMenu") != -1 && hit2d.collider.transform.parent == aroundMenuParentTran)
                     )
                  {
                      isRotateMenu = true;
                      StartCoroutine(MoveSubMenu());
                  }
                  
              }
              else if(hit2d.collider.name == "MainMenu")
              {
                  if(hit2d.collider.gameObject != mainManu)
                      MainMenuClick();
              }
              else
                  MainMenuClick();
          }
          else
              MainMenuClick();
      }
      
  }
  
  private IEnumerator MoveSubMenu()
  {
      menuRotation = GetRotation(aroundMenuParentTran.position, startAroundMenu.transform.position);
      
      // 動作開始位置
      Vector3 moveStartPos = uiCamera.GetComponent<Camera>().ScreenToWorldPoint(Input.mousePosition);
      float moveStartRotation = GetRotation(aroundMenuParentTran.position, moveStartPos);
      
      Vector3 nowMousePos = Vector3.zero;    // 現在のマウスの位置
      float nowRotation = 0;                // 現在のマウスの角度
      float moveRotation = 0;               // 動かした角度
      
      float prevRotation = 0;               // 前の角度
      float delta = 0;                  // 動かす角度

      // ドラッグ中の回転
      while(Input.GetMouseButton(0))
      {
          nowMousePos = uiCamera.GetComponent<Camera>().ScreenToWorldPoint(Input.mousePosition);
          nowRotation = GetRotation(aroundMenuParentTran.position, nowMousePos);
          
          // 動いた角度 
          moveRotation = nowRotation - moveStartRotation;
          RotateSubMenu(moveRotation);
          
          delta = nowRotation - prevRotation;
          prevRotation = nowRotation;
          yield return null;
      }
      menuRotation = GetRotation(aroundMenuParentTran.position, startAroundMenu.transform.position);
      
      isRotateMenu = false;
      
      if(delta > 20) delta = 20;
      else if(delta < -20) delta = -20;

      // ドラッグを離したあとの自動で動く処理
      while(!Input.GetMouseButton(0) && delta != 0)
      {
          RotateSubMenu(delta);
          
          delta *= 0.9f;
          if(Mathf.Abs(delta) < 0.01f) delta = 0;
          menuRotation = GetRotation(aroundMenuParentTran.position, startAroundMenu.transform.position);
          yield return null;
      }
      isRotateMenu = false;
  }

  // メニューをdelta回転させる
  private void RotateSubMenu(float delta)
  {
      float rot = 0;
      float rad = 0;
      Vector3 pos = Vector3.zero;            // サブメニューの位置
      
      int i = 0;
      foreach(Transform tran in aroundMenuParentTran)
      {
          rot = 360 / subMenuCount * i + 90 + delta + menuRotation;
          rad = rot * Mathf.Deg2Rad;  // 角度からラジアンに変換
          pos = Vector3.zero;
          pos.x = Mathf.Cos(rad) * radius;
          pos.y = Mathf.Sin(rad) * radius;
          
          tran.localPosition = pos;
          i++;
      }
  }

  // basePosからtargetPosまでの角度を返す
  private float GetRotation(Vector3 basePos, Vector3 targetPos)
  {
      float dx = targetPos.x - basePos.x;
      float dy = targetPos.y - basePos.y;
      float rad = Mathf.Atan2(dy, dx);
      float rotation = rad * Mathf.Rad2Deg - 90;
      
      return rotation;
  }

  // メインのメニューボタンが押されたとき
  public void MainMenuClick()
  {
      if(isSubMenu)
      {
          isSubMenu = false;
          aroundMenuParentTran.GetComponent<TweenScale>().PlayReverse();
      }
      else
      {
          isSubMenu = true;
          aroundMenuParentTran.GetComponent<TweenScale>().PlayForward();
      }
  }
}

はい、今回はここまで