Mike Hunt, sorunuz beni çok ilgilendirdi, tam bir çözüm uygulamaya karar verdim. Üç saat farklı şeyler denedikten sonra, bu adım adım çözümü buldum:
(Bu çok iyi bir kod DEĞİLDİR, bu yüzden herhangi bir düzenlemeyi kabul edeceğimizi lütfen unutmayın)
İçerik Paneli Oluşturma
(Bu panel, içerik menüsü düğmelerimiz için bir kap olacaktır)
- Yeni oluşturmak
UI Panel
anchor
Sol alta ayarla
width
300 olarak ayarlayın (istediğiniz gibi)
- Panele yeni bir bileşen ekleyin
Vertical Layout Group
ve Child Alignment
üst merkeze, Child Force Expand
genişliğe (yükseklik değil) ayarlayın
- Panele yeni bir bileşen ekleyin
Content Size Fitter
ve Vertical Fit
Min Size olarak ayarlayın
- Prefabrik olarak kaydet
(Bu noktada Panelimiz bir satıra daralır. Normaldir. Bu panel düğmeleri çocuk olarak kabul eder, dikey olarak hizalar ve özet içerik yüksekliğine kadar uzanır)
Örnek Düğmesi Oluşturma
(Bu düğme, içerik menüsü öğelerini göstermek için örneklenecek ve özelleştirilecektir)
- Yeni kullanıcı arayüzü oluştur düğmesi
- Ayarlamak
anchor
Sol üste
- Düğmeye 30'a
Layout Element
ayarlanmış yeni bir bileşen ekleyin Min Height
,Preferred Height
ekleme
- Prefabrik olarak kaydet
ContextMenu.cs betiği oluşturma
(Bu komut dosyasının İçerik Menüsünü oluşturan ve gösteren bir yöntemi vardır)
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);
}
}
}
- Bu komut dosyasını bir Kanvas'a ekleyin ve alanları doldurun. Sürükle-bırak
ContentPanel
yuvası tekabül eden prefabrik ve yuvaya sürükleme Tuval kendisi Canvas
.
ItemController.cs betiği oluşturma
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);
}
}
- Sahnede örnek nesne oluşturun (yani
Cube
), kamera tarafından görülebilecek şekilde yerleştirin ve bu komut dosyasını ona ekleyin. Sürükle-bırak sampleButton
yöntemini ilgili yuvaya sürükleyin .
Şimdi çalıştırmayı deneyin. Nesneyi sağ tıklattığınızda, yaptığımız listeyle doldurulmuş içerik menüsü görünmelidir. Düğmelere basıldığında konsolda bazı metinler yazdırılır ve içerik menüsü yok edilir.
Olası iyileştirmeler:
- daha da genel!
- daha iyi bellek yönetimi (kirli bağlantılar, paneli yok etmeme, devre dışı bırakma)
- bazı süslü şeyler
Örnek proje (Unity Personal 5.2.0, VisualStudio Eklentisi):
https://drive.google.com/file/d/0B7iGjyVbWvFwUnRQRVVaOGdDc2M/view?usp=sharing