You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中如何点击GameObject创建类似Windows右键的悬浮菜单?

Got it, let's fix this context menu issue for your agent GameObject. The problem with your initial approach is likely a mix of incorrect input timing, missing collider setup, or mishandling GUI coordinates. Here's a complete, working solution—first with IMGUI (since you started with OnGUI) and then a better UGUI approach for modern Unity projects:

IMGUI Solution (Using OnGUI/OnMouseOver)

First, make sure your agent GameObject has a non-trigger Collider (like BoxCollider or SphereCollider) attached—OnMouseOver only works if there's a collider to detect the mouse hover. Then use this script:

using UnityEngine;

public class AgentContextMenu : MonoBehaviour
{
    private bool _isMouseOverAgent;
    private bool _showContextMenu;
    private Vector2 _menuPosition;

    private void OnMouseOver()
    {
        _isMouseOverAgent = true;
        
        // Trigger menu on left (0) or right (1) mouse button press
        if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1))
        {
            _showContextMenu = true;
            // Convert screen mouse position to GUI coordinates (Y-axis is flipped)
            _menuPosition = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y);
        }
    }

    private void OnMouseExit()
    {
        _isMouseOverAgent = false;
        _showContextMenu = false; // Close menu when mouse leaves the agent
    }

    private void OnGUI()
    {
        if (_showContextMenu)
        {
            // Draw the menu window—adjust size/title as needed
            _menuPosition = GUI.Window(0, new Rect(_menuPosition.x, _menuPosition.y, 150, 110), DrawMenuItems, "Agent Actions");
        }
    }

    private void DrawMenuItems(int windowId)
    {
        // Add your menu options here
        if (GUILayout.Button("Move to Position"))
        {
            Debug.Log("Move command executed!");
            _showContextMenu = false;
        }

        if (GUILayout.Button("Attack Target"))
        {
            Debug.Log("Attack command executed!");
            _showContextMenu = false;
        }

        GUILayout.FlexibleSpace(); // Push cancel button to bottom
        if (GUILayout.Button("Cancel"))
        {
            _showContextMenu = false;
        }

        GUI.DragWindow(); // Allow dragging the menu (optional)
    }

    // Close menu when clicking outside of it
    private void Update()
    {
        if (_showContextMenu && Input.GetMouseButtonDown(0) && !_isMouseOverAgent)
        {
            _showContextMenu = false;
        }
    }
}

Key Fixes & Notes:

  • Collider Requirement: Without a non-trigger collider, OnMouseOver won't fire—this is probably the most common oversight.
  • Coordinate Conversion: Input.mousePosition uses a bottom-origin Y-axis, while GUI uses top-origin. The conversion ensures the menu pops up where your mouse is.
  • Input Timing: GetMouseButtonDown detects the exact press moment, so you don't get repeated menu triggers if you hold the button.
  • Close Logic: The menu closes when you leave the agent, click a menu item, or click outside the menu.

IMGUI is functional but limited for styling/animation. If you're using Unity's UGUI system, this approach is more flexible:

  1. Set Up the Menu Prefab:

    • Create a Canvas, add a Panel (style it like a context menu: add a background image, round corners, etc.).
    • Add Button components inside the Panel for your menu options (e.g., "Move", "Attack").
    • Disable the Panel initially (toggle the active checkbox in the Inspector).
    • Save this as a prefab.
  2. Attach This Script to Your Agent:

using UnityEngine;
using UnityEngine.UI;

public class AgentUGUIContMenu : MonoBehaviour
{
    [SerializeField] private GameObject _contextMenuPrefab; // Assign your prefab here
    private GameObject _activeMenu;
    private bool _isMouseOverAgent;

    private void OnMouseOver()
    {
        _isMouseOverAgent = true;
        
        if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1))
        {
            // Clean up existing menu if it exists
            if (_activeMenu != null) Destroy(_activeMenu);
            
            // Spawn the menu under the canvas
            _activeMenu = Instantiate(_contextMenuPrefab, FindObjectOfType<Canvas>().transform);
            
            // Position the menu at the mouse location
            RectTransform menuRect = _activeMenu.GetComponent<RectTransform>();
            Vector2 screenPos = Input.mousePosition;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                FindObjectOfType<Canvas>().transform as RectTransform,
                screenPos,
                Camera.main,
                out Vector2 localPos
            );
            
            menuRect.localPosition = localPos;
            
            // Bind actions to buttons (adjust names to match your prefab's buttons)
            _activeMenu.transform.Find("MoveBtn").GetComponent<Button>().onClick.AddListener(() =>
            {
                Debug.Log("Move via UGUI menu!");
                Destroy(_activeMenu);
            });
            
            _activeMenu.transform.Find("AttackBtn").GetComponent<Button>().onClick.AddListener(() =>
            {
                Debug.Log("Attack via UGUI menu!");
                Destroy(_activeMenu);
            });
        }
    }

    private void OnMouseExit()
    {
        _isMouseOverAgent = false;
        if (_activeMenu != null) Destroy(_activeMenu);
    }

    // Close menu when clicking outside of it
    private void Update()
    {
        if (_activeMenu == null) return;
        
        if (Input.GetMouseButtonDown(0) && !_isMouseOverAgent)
        {
            // Check if the click is outside the menu bounds
            if (!RectTransformUtility.RectangleContainsScreenPoint(
                _activeMenu.GetComponent<RectTransform>(),
                Input.mousePosition,
                Camera.main))
            {
                Destroy(_activeMenu);
            }
        }
    }
}

Why UGUI is Better:

  • You can fully customize the menu's look (colors, fonts, animations) using Unity's UI system.
  • It supports responsive design and works better with other UI elements in your project.
  • Easier to add complex interactions (like hover effects on buttons).

Common Mistakes You Might Have Made

  1. Missing Collider: No collider = OnMouseOver never triggers.
  2. Incorrect Coordinates: Forgetting to flip the Y-axis leads to the menu appearing at the bottom of the screen.
  3. Bad Input Detection: Using Input.GetMouseButton (continuous press) instead of GetMouseButtonDown (single press) causes the menu to toggle repeatedly.
  4. No Close Logic: Not handling menu closure when clicking outside or leaving the agent leads to stuck menus.

内容的提问来源于stack exchange,提问作者AmyLiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:43:09