【问题标题】:Interactive objects in Unity VR with OnOver and OnOut (C#)Unity VR 中的交互式对象与 OnOver 和 OnOut (C#)
【发布时间】:2019-06-29 11:51:05
【问题描述】:

Printscreen from Unity 我正在 Unity 中为 Oculus Go 创建一个 VR 应用。 当激光指针悬停在某些游戏对象上时,我想在精灵上显示一些文本,并在没有时消失。我试图通过创建一个数组来做到这一点,该数组应该在激光指针悬停在特定对象上时显示特定的游戏对象组件(textmesh + sprite)。在这个阶段,无论激光指针悬停在哪个游戏对象上,都只会显示列表中的最后一个对象 text+sprite。

using System;
using UnityEngine;
using VRStandardAssets.Utils;

public class ObjectManager : MonoBehaviour
{

[SerializeField] VRInteractiveItem[] InteractiveObjects;
[SerializeField] Transform reticleTransform;

private VRInteractiveItem currentObject;

void Start()
{

    foreach (VRInteractiveItem t in InteractiveObjects)
    {

        foreach (MeshRenderer renderer in t.GetComponentsInChildren<MeshRenderer>())
        {
            renderer.enabled = false;
        }


        foreach (SpriteRenderer renderer in t.GetComponentsInChildren<SpriteRenderer>())
        {
            renderer.enabled = false;
        }
    }

}


void OnEnable()
{
    foreach (VRInteractiveItem t in InteractiveObjects)
    {
        currentObject = t;
        currentObject.OnOver += Popup;
    }
}


void Popup()
{
        foreach (MeshRenderer renderer in currentObject.GetComponentsInChildren<MeshRenderer>())
        {
            renderer.enabled = true;
        }

        foreach (SpriteRenderer renderer in currentObject.GetComponentsInChildren<SpriteRenderer>())
        {
            renderer.enabled = true;
        }

        currentObject.OnOut += Popdown;
}


void Popdown()
{ 
        foreach (MeshRenderer renderer in currentObject.GetComponentsInChildren<MeshRenderer>())
        {
            renderer.enabled = false;
        }

        foreach (SpriteRenderer renderer in currentObject.GetComponentsInChildren<SpriteRenderer>())
        {
            renderer.enabled = false;
        }

}

}

如何让激光指示器知道我正在与哪个特定游戏对象进行交互并使其仅显示该对象的组件?我已经尝试使用 ID 找到解决方案,但还没有让它在 VR 中工作。

【问题讨论】:

  • 你看到unity3d.com/de/learn/tutorials/topics/virtual-reality/…了吗?我想说更好的解决方案是让每个组件自己处理它,而不是试图从一个管理器组件中完成所有事情。
  • 是的,我看过了。我开始思考这个问题 - 我一直在努力让这个解决方案发挥作用,所以我想看看是否有其他人能告诉我是否遗漏了什么。
  • 问题是回调没有得到关于它被调用的对象的信息......所以最好在对象本身上有回调,这样你就不必“知道" 在哪一个上调用它。

标签: c# unity3d interactive virtual-reality oculus


【解决方案1】:

如前所述,我实际上宁愿建议让每个VRInteractiveItem 自己处理OnOver,而不是从一个管理器组件中全部完成。


您可以做的一件事(尽管我不推荐)是使用带有 for 循环的 lambda 表达式而不是 foreach 作为回调而不是像这样的方法

void OnEnable()
{
    for(var i= 0; i < InteractiveObjects.Length; i++)
    {
        var index = i;
        InteractiveObjects[index].OnOver += () => {
            foreach (MeshRenderer renderer in InteractiveObjects[index].GetComponentsInChildren<MeshRenderer>())
            {
                renderer.enabled = true;
            }

            foreach (SpriteRenderer renderer in InteractiveObjects[index].GetComponentsInChildren<SpriteRenderer>())
            {
                renderer.enabled = true;
            }

            InteractiveObjects[index].OnOut += () => {
                foreach (MeshRenderer renderer in InteractiveObjects[index].GetComponentsInChildren<MeshRenderer>())
                {
                    renderer.enabled = false;
                }

                foreach (SpriteRenderer renderer in InteractiveObjects[index].GetComponentsInChildren<SpriteRenderer>())
                {
                    renderer.enabled = false;
                }
            };
        };
    }
}

一个问题是您不能像使用方法那样删除这些回调 (InteractiveObjects[index].OnOut -= XYZ)。

因此,您实际上不应该在每次悬停对象时添加InteractiveObjects[index].OnOut +=,因为您最终可能会多次执行禁用代码。您可能宁愿将其添加到OnEnable 以及像

void OnEnable()
{
    for(var i= 0; i < InteractiveObjects.Length; i++)
    {
        var index = i;
        InteractiveObjects[index].OnOver += () => {
            foreach (MeshRenderer renderer in InteractiveObjects[index].GetComponentsInChildren<MeshRenderer>())
            {
                renderer.enabled = true;
            }

            foreach (SpriteRenderer renderer in InteractiveObjects[index].GetComponentsInChildren<SpriteRenderer>())
            {
                renderer.enabled = true;
            }
        };

        InteractiveObjects[index].OnOut += () => {
            foreach (MeshRenderer renderer in InteractiveObjects[index].GetComponentsInChildren<MeshRenderer>())
            {
                renderer.enabled = false;
            }

            foreach (SpriteRenderer renderer in InteractiveObjects[index].GetComponentsInChildren<SpriteRenderer>())
            {
                renderer.enabled = false;
            }
        };
    }
}

【讨论】:

  • 感谢您的帮助!不过,我还是让每个组件自己处理脚本,这似乎是最简单的方法。
最近更新 更多