【问题标题】:OnGUI and Coroutine moving an object: really strange behaviorOnGUI 和 Coroutine 移动对象:非常奇怪的行为
【发布时间】:2019-05-15 22:59:42
【问题描述】:

在标题中以最佳方式总结这种行为并不容易。 我有一个编辑器和一个在 [ExecuteInEditMode] 中执行的 Monobehaviour。 我需要通过用鼠标选择对象来移动它们。我认为我在使用角色和精灵执行此操作时没有遇到任何困难。但是我错了。当我选择一个 3D 对象(不是角色)时,我可以选择并拖动它,但如果我按住鼠标按钮而不移动它,它往往会滑开,就好像它正在下降一样,但在 Y 轴和 Z 轴上。如果我取消选择它的对撞机,问题就不会发生,但显然对撞机对我的操作是必要的。 我已经从代码中删除了所有不必要的行,希望能解决问题,但它仍然存在。

    void OnGUI() {
    if (moveChar) {
        StartCoroutine("WaitChar");
    } else if (moveSpot) {
        StartCoroutine("WaitSpot");
    }
    Event e = Event.current;
    Vector3 mousePosition = e.mousePosition;
    mousePosition.y = Screen.height - mousePosition.y;
    Ray ray = cam.ScreenPointToRay(mousePosition);
    RaycastHit hitInfo;
    if (Physics.Raycast(ray, out hitInfo)) {
        mousePositionWorld = hitInfo.point;
        if (e.rawType == EventType.MouseDown) {
            switch (e.button) {
                case 0: 
                    if (isSelectedSphere) {
                        moveSpot = true;
                    } 
                    break;
                case 1:
                    if (isSelectedChar) {
                        moveChar = true;
                    } 
                    break;
            }
        } else if (e.rawType == EventType.MouseUp) {
            switch (e.button) {
                case 0: 
                    if (moveSpot) {
                        moveSpot = false;
                    } 
                    break;
                case 1:
                    if (moveChar) {
                        moveChar = false;
                    }
                    break;
            }
        }
    }
}

public IEnumerator WaitChar() {
    character.transform.position = mousePositionWorld;
    yield return new WaitForSeconds(0.1f);
}

public IEnumerator WaitSpot() {
    MoveSpot.transform.position = mousePositionWorld;
    MoveSpot.transform.localScale = Vector3.one * ((new Plane(cam.transform.forward, 
                                                    cam.transform.position).GetDistanceToPoint(
                                                    MoveSpot.transform.position)) / radiusPoint);
    yield return new WaitForSeconds(0.1f);
}

我用两个公共变量简化了一切,以选择要移动的对象。 我所做的很简单,我不明白为什么会出现这种行为。对于角色我没有问题(即使是精灵,我暂时从代码中删除)。当我用鼠标右键单击时,我运行将字符移动到光标坐标的协程并继续这样直到我释放按钮。没问题,字符随着光标移动没有问题。 但是,如果我对 Sphere、Cylinder、Cube 等 3D 对象执行相同的操作(左键),它会跟随鼠标移动,但如果我不移动光标并且不释放按钮,则对象会随着 Y 滑开和负增加的 Z 轴。正如我所说,如果我停用对撞机,对象将保持在光标位置。 问题是球体不能通过公共变量选择,而是直接从脚本中选择,所以我需要对撞机。 我可能不太了解 Unity,无法知道这种行为的原因。 你能帮我澄清一下吗?

【问题讨论】:

  • 这个问题可以用 MoveSpot.GetComponent ().enabled = false;在 MouseDown 中启动协程并在 MouseUp 中重新激活对撞机之前。但这是一种解决方法吗?可以做得更好吗?

标签: c# unity3d


【解决方案1】:

OnGui 不好(让我解释一下)

首先,OnGui 是 Unity 的 IMGui 系统(代表 IMmediate Gui)的一部分,并且已经被大量贬值以支持 uGui,由于多种原因,它更容易使用。其中一个原因是......

OnGui 每帧调用不止一次

因为OnGui每帧被调用多次,这意味着Event.current没有改变,意味着moveChar没有改变,意味着你的协程被启动了不止一次。

而且没有真正的解决方法。使用 OnGui 几乎不可能做你想做的事。它从来没有打算处理这种逻辑。

您所拥有的一切都应该在 Update() 内完成,并用他们的 Input 亲戚替换像 e.rawType == EventType.MouseDown 这样的东西,例如。 Input.GetMouseDown(0).

【讨论】:

  • 谢谢。首先它是在运行时更新下的(不过只是字符和精灵)。我将代码移至 OnGUI 以在编辑模式下工作,我发现它运行良好。问题出现在球体上。在使用 OnGUI 之前,我尝试了几天让 Update 在编辑模式下工作,在论坛中搜索了数小时,但无事可做。我也对 OnGUI 犹豫不决,但似乎它仍然是编辑器工作的最佳解决方案。但是,即使每帧调用 OnGUI 多次,如果我不移动鼠标,mousePositionWorld 变量也应该始终相同。为什么会自己改变?
  • 我不知道你为什么需要它在编辑模式下运行。大概是这样您可以更轻松地对其进行调试,但是我认为这引入了比您解决的问题更多的问题。至于鼠标,我不能说。你应该使用Input.mousePosition,我从来没有遇到过问题。
  • 我想在编辑模式下工作,因为我创建了网格,我移动和调整对象的大小,离开播放模式我失去了所有的变化。要么我尝试序列化所有内容(如果可能的话),要么我将所有数据保存在文件中并通过进入编辑模式来重建它们(就像我现在正在做的那样)。
  • Monobehaviour 一直处于 [ExecuteInEditMode] 以获取附加功能,但这不允许存储来自播放模式的更改。在编辑模式下使用它,不会经常调用更新,这就是我使用 OnGUI 的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-24
  • 2016-03-13
  • 2011-03-01
  • 2012-12-10
  • 2015-04-20
  • 2020-12-02
  • 1970-01-01
相关资源
最近更新 更多