ดังนั้นไมค์ฮันท์คำถามของคุณจึงสนใจฉันฉันตัดสินใจที่จะใช้โซลูชั่นเต็มรูปแบบ หลังจากลองสิ่งที่แตกต่างกันสามชั่วโมงฉันลงเอยด้วยวิธีแก้ปัญหาทีละขั้นตอนนี้:
(โปรดทราบว่านี่ไม่ใช่รหัสที่ดีมากดังนั้นฉันจะยอมรับการแก้ไขใด ๆ )
การสร้างแผงเนื้อหา
(พาเนลนี้จะเป็นคอนเทนเนอร์สำหรับปุ่มเมนูบริบทของเรา)
- สร้างใหม่
UI Panel
- ตั้งค่า
anchor
เป็นซ้ายล่าง
- ชุด
width
เป็น 300 (ตามที่คุณต้องการ)
- เพิ่มองค์ประกอบใหม่
Vertical Layout Group
และตั้งค่าไปยังพาเนลChild Alignment
เป็นกึ่งกลางส่วนบนChild Force Expand
เป็นความกว้าง (ไม่ใช่ความสูง)
- เพิ่มองค์ประกอบใหม่ลงในพาเนล
Content Size Fitter
และตั้งค่าVertical Fit
เป็นขนาดต่ำสุด
- บันทึกเป็นรูปแบบสำเร็จรูป
(ณ จุดนี้พาเนลของเราจะลดขนาดลงมาเป็นบรรทัดมันเป็นเรื่องปกติแผงนี้จะยอมรับปุ่มเป็นเด็ก ๆ จัดแนวพวกมันในแนวตั้งและยืดความสูงของเนื้อหาสรุป)
การสร้างปุ่มตัวอย่าง
(ปุ่มนี้จะถูกสร้างและปรับแต่งเพื่อแสดงรายการเมนูบริบท)
- สร้างปุ่ม 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 และเติมฟิลด์ ลาก n หล่นสำเร็จรูปในช่วงที่สอดคล้องกันและลากตัวเองไปผ้าใบสล็อต
ContentPanel
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
) วางกล้องให้สามารถมองเห็นได้และแนบสคริปต์นี้เข้ากับมัน ลาก -n-drop sampleButton
prefab ไปยังช่องเสียบที่เกี่ยวข้อง
ตอนนี้พยายามเรียกใช้ เมื่อคุณคลิกขวาที่วัตถุเมนูบริบทจะปรากฏขึ้นบรรจุด้วยรายการที่เราทำ ข้อความที่กดปุ่มจะพิมพ์ลงในคอนโซลข้อความบางส่วนและเมนูบริบทจะถูกทำลาย
การปรับปรุงที่เป็นไปได้:
- ทั่วไปมากยิ่งขึ้น!
- การจัดการหน่วยความจำที่ดีขึ้น (ลิงค์สกปรกไม่ทำลายแผงปิดการใช้งาน)
- บางสิ่งที่แฟนซี
ตัวอย่างโครงการ (Unity Personal 5.2.0, ปลั๊กอิน VisualStudio):
https://drive.google.com/file/d/0B7iGjyVbWvFwUnRQRVVaOGdDc2M/view?usp=sharing