それで、マイク・ハント、あなたの質問は私にとても興味があったので、私は完全な解決策を実装することにしました。3時間さまざまなことを試した後、私はこの段階的な解決策になりました。
(これは非常に良いコードではないので、編集を受け入れることに注意してください)
コンテンツパネルの作成
(このパネルは、コンテキストメニューボタンのコンテナになります)
- 新しく作る
UI Panel
anchor
左下に設定
width
300に設定(必要に応じて)
- パネルに新しいコンポーネント
Vertical Layout Group
を追加し、幅(高さではなく)のChild Alignment
中央上部に設定しますChild Force Expand
- パネルに新しいコンポーネント
Content Size Fitter
を追加し、Vertical Fit
最小サイズに設定します
- プレハブとして保存する
(この時点で、Panelは行に縮小されます。これは正常です。このパネルは、子としてボタンを受け入れ、ボタンを垂直に整列し、サマリーコンテンツの高さに合わせて伸縮します)
サンプルボタンの作成
(このボタンは、コンテキストメニュー項目を表示するためにインスタンス化およびカスタマイズされます)
- 新しいUIボタンを作成
anchor
左上に設定
- ボタンに新しいコンポーネントを追加
Layout Element
設定し、Min Height
30にをPreferred Height
30に
- プレハブとして保存する
ContextMenu.csスクリプトの作成
(このスクリプトには、コンテキストメニューを作成して表示するメソッドがあります)
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[System.Serializable]
public class ContextMenuItem
{
// this class - just a box to some data
public string text; // text to display on button
public Button button; // sample button prefab
public Action<Image> action; // delegate to method that needs to be executed when button is clicked
public ContextMenuItem(string text, Button button, Action<Image> action)
{
this.text = text;
this.button = button;
this.action = action;
}
}
public class ContextMenu : MonoBehaviour
{
public Image contentPanel; // content panel prefab
public Canvas canvas; // link to main canvas, where will be Context Menu
private static ContextMenu instance; // some kind of singleton here
public static ContextMenu Instance
{
get
{
if(instance == null)
{
instance = FindObjectOfType(typeof(ContextMenu)) as ContextMenu;
if(instance == null)
{
instance = new ContextMenu();
}
}
return instance;
}
}
public void CreateContextMenu(List<ContextMenuItem> items, Vector2 position)
{
// here we are creating and displaying Context Menu
Image panel = Instantiate(contentPanel, new Vector3(position.x, position.y, 0), Quaternion.identity) as Image;
panel.transform.SetParent(canvas.transform);
panel.transform.SetAsLastSibling();
panel.rectTransform.anchoredPosition = position;
foreach(var item in items)
{
ContextMenuItem tempReference = item;
Button button = Instantiate(item.button) as Button;
Text buttonText = button.GetComponentInChildren(typeof(Text)) as Text;
buttonText.text = item.text;
button.onClick.AddListener(delegate { tempReference.action(panel); });
button.transform.SetParent(panel.transform);
}
}
}
- このスクリプトをCanvasに添付して、フィールドに入力します。
ContentPanel
プレハブを対応するスロットにドラッグアンドドロップし、Canvas自体をslotにドラッグしますCanvas
。
ItemController.csスクリプトの作成
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class ItemController : MonoBehaviour
{
public Button sampleButton; // sample button prefab
private List<ContextMenuItem> contextMenuItems; // list of items in menu
void Awake()
{
// Here we are creating and populating our future Context Menu.
// I do it in Awake once, but as you can see,
// it can be edited at runtime anywhere and anytime.
contextMenuItems = new List<ContextMenuItem>();
Action<Image> equip = new Action<Image>(EquipAction);
Action<Image> use = new Action<Image>(UseAction);
Action<Image> drop = new Action<Image>(DropAction);
contextMenuItems.Add(new ContextMenuItem("Equip", sampleButton, equip));
contextMenuItems.Add(new ContextMenuItem("Use", sampleButton, use));
contextMenuItems.Add(new ContextMenuItem("Drop", sampleButton, drop));
}
void OnMouseOver()
{
if(Input.GetMouseButtonDown(1))
{
Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
ContextMenu.Instance.CreateContextMenu(contextMenuItems, new Vector2(pos.x, pos.y));
}
}
void EquipAction(Image contextPanel)
{
Debug.Log("Equipped");
Destroy(contextPanel.gameObject);
}
void UseAction(Image contextPanel)
{
Debug.Log("Used");
Destroy(contextPanel.gameObject);
}
void DropAction(Image contextPanel)
{
Debug.Log("Dropped");
Destroy(contextPanel.gameObject);
}
}
- シーン内にサンプルオブジェクトを作成し(例:)、
Cube
カメラに見えるように配置し、このスクリプトをアタッチします。sampleButton
プレハブを対応するスロットにドラッグアンドドロップします。
今、それを実行してみてください。オブジェクトを右クリックすると、コンテキストメニューが表示され、作成したリストが表示されます。ボタンを押すと、コンソールにテキストが印刷され、コンテキストメニューが破棄されます。
可能な改善:
- さらに一般的です!
- メモリ管理の改善(ダーティリンク、パネルを破壊せず、無効化)
- いくつかの派手なもの
サンプルプロジェクト(Unity Personal 5.2.0、VisualStudioプラグイン): https ://drive.google.com/file/d/0B7iGjyVbWvFwUnRQRVVaOGdDc2M/view?usp=sharing