くるくる回るメニュー

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

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

こんなの

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

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

##中身

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

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

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

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();
}
}
}

はい、今回はここまで