【问题标题】:Why would supposedly different two event methods be called by the same object? (Mouse Click-Drag-Unclick)为什么同一个对象会调用不同的两个事件方法? (鼠标点击-拖动-取消点击)
【发布时间】:2015-04-01 07:33:54
【问题描述】:

版本: Unity3D 4.6.2f1

我有一个瓷砖网格(立方体 GameObjects 附有 Tile 脚本)。它们位于索引位置[x][y] = (x, y, z=0) World Coordinates

我正在尝试实现类似于扫雷的行为:释放左键时,除非有右键单击,否则释放鼠标的图块会显露出来。下面,我尝试获取释放鼠标左键的图块的坐标。

进入代码之前:

  • OnMouseDown() - 当用户在 GUIElement 或 Collider 上按下鼠标按钮时调用 OnMouseDown。
  • OnMouseUp() - OnMouseUp 在用户释放鼠标按钮时调用。

基于这些定义,我假设(错误?)OnMouseUp() 将被其上方的对象调用,鼠标左键被释放。

Tile 脚本上,我有以下内容:

public class Tile : MonoBehaviour
{
    // variables
    private Vector2 _gridPosition = Vector2.zero;

    public Vector2 GridPosition
    {
        get { return _gridPosition; }
        set { _gridPosition = value; }
    }

    // functions
    string Vec2toText(Vector2 v)
    {
        return String.Format("(" + v.x + ", " + v.y + ")");
    }

    void OnMouseDown()
    {
        Debug.Log("TILE:: ON_MOUSE_DOWN:: " + Vec2toText(_gridPosition));
    }

    void OnMouseUp()
    {
        Debug.Log("TILE:: ON_MOUSE_UP:: " + Vec2toText(_gridPosition));
    }

    void OnMouseEnter()
    {
        Debug.Log("TILE:: MOUSE_ENTER: " + Vec2toText(_gridPosition));
    }

    void OnMouseExit()
    {
        Debug.Log("TILE:: MOUSE_EXIT: " + Vec2toText(_gridPosition));
    }
}

here 是输出:

TILE:: MOUSE_ENTER: (15, 15)
TILE:: MOUSE_DOWN: (15, 15)
TILE:: MOUSE_EXIT: (15, 15)
TILE:: MOUSE_ENTER: (14, 15)
TILE:: MOUSE_UP: (15, 15)    %% This line
TILE:: MOUSE_EXIT: (14, 15)

如果我可以在OnMouseUp() 函数上获得(14,15),我会直接找到要显示的图块,但显然我不能。我认为我的目标的解决方法是保留static bool _isDragging 并在if 块中的OnMouseEnter() 中使用它来分配要正确显示的图块。这是 - 即使我按下左键单击某个对象并将其释放到另一个对象上,也通过同一个对象调用两个函数? - 故意的?这种情况有更好的解决方法吗?

【问题讨论】:

    标签: c# events unity3d callback


    【解决方案1】:

    OnMouseDown 仅针对鼠标左键发出。所以你必须自己实现右键。

    一种选择是在您按下按钮时检查光线投射。

    void Update()
    {
        if (Input.GetMouseButtonDown(1))
        {
            var ray = camera.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitInfo;
            if (Physics.Raycast(ray, out hitInfo))
            {
                var myObject = hitInfo.collider.GetComponent<MyScriptOrSomething>();
                // Do something here
            }
        }
    }
    

    另一个选项是使用 OnMouseEnter 检查右键单击。比如:

    void OnMouseOver()
    {
        if (Input.GetMouseButtonDown(1))
        {
            // Do something here
        }
    }
    

    编辑:

    OnMouseUp 调用您单击的磁贴的原因很简单。大多数情况下,这种行为是最安全和更令人期待的方式。将游戏对象的鼠标事件想象为“用户点击了我”和“用户点击了我后松开了按钮”。

    假设在释放鼠标按钮时为光标下的对象调用 OnMouseUp。考虑一个从鼠标单击开始并在鼠标按钮释放时完成的操作(如拖放)。然后您会痛苦地发现,如果鼠标不再指向您最初单击的对象,则不会调用 OnMouseUp。您将无法完成操作。您必须自己捕捉鼠标释放事件。

    就您而言,仅 OnMouseUp 和 OnMouseDown 无法满足您的需求。您正在尝试做的事情对您的应用程序来说太具体了。不幸的是,Unity 的输入系统默认不包含这种交互。幸运的是,Unity 足够灵活,可以轻松实现这一点。

    【讨论】:

    • 问题不在于现在右键单击。看,问题就在这里:说 Tile1(15,15) 和 Tile2(14,15)。我左键单击 Tile1,将鼠标拖动到 Tile2,然后释放左键单击 Tile2,但是即使释放左键时鼠标悬停在 Tile2 上,也会为 Tile1 调用 OnMouseUp() 函数。右键还没有什么。问题出在左键上。
    • 抱歉,我不清楚我想说什么。我现在会更新答案。
    • 谢谢,你的答案现在更清楚了。由于 Unity 的灵活性,我保留了一个静态变量并优雅地处理事情:)
    • 另外,还有一个事件叫OnMouseUpAsButton。也许你想看看(docs.unity3d.com/ScriptReference/…
    • 欢迎您。旅途愉快 :) 如果您来安卡拉,请访问我们 :)
    【解决方案2】:

    作为一种更好的解决方法,不要使用static bool _isDragging,而是使用void OnMouseOver() 函数:

    void OnMouseOver()
    {
        if(Input.GetMouseButtonUp(0))  // left click released
            RevealTile();
        if(Input.GetMouseButtonUp(1))  // right click released
            FlagTile();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-17
      • 1970-01-01
      • 2017-05-16
      • 1970-01-01
      • 2018-09-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多