【问题标题】:interact with gameobjects in Unity在 Unity 中与游戏对象交互
【发布时间】:2018-09-30 06:03:21
【问题描述】:

我想在 Unity 中与游戏对象进行交互。这些对象可能是钥匙、门、箱子……

假设桌子上有一把钥匙。当玩家靠近它时,它应该被着色器勾勒出来,并且会出现一个文本“拾取键”。

我为可交互的游戏对象创建了一个界面。

public interface IInteractable
{
    string InteractabilityInfo { get; }

    void ShowInteractability();

    void Interact();
}

通过这样做,我可以将界面组件添加到我的Key 脚本中

public class Key : MonoBehaviour, IInteractable
{
    public string InteractabilityInfo { get { return "some text here"; } }

    public void ShowInteractability()
    {
        // Outline Shader maybe?
    }

    public void Interact()
    {
        // Do something with the key
    }
}

当涉及到检查某些东西是否可交互的脚本时,我创建了一个脚本,该脚本创建了一个用于检查可交互对象的光线投射。 (我将此脚本附加到我的 FPS 相机)

public class InteractabilityCheck : MonoBehaviour
{
    private const int RANGE = 3;

    private void Update()
    {
        RaycastHit hit;
        if (Physics.Raycast(transform.position, transform.forward, out hit, RANGE))
        {
            IInteractable interactable = hit.collider.GetComponent<IInteractable>();

            if (interactable != null)
            {
                interactable.ShowInteractability();

                if (Input.GetKeyDown(KeyCode.E))
                {
                    interactable.Interact();
                }
            }
        }
    }
}

此脚本尝试获取接口组件并在它不为空时调用其中的方法。

这段代码运行良好,但我不喜欢 Raycast 每帧触发一个。还有其他实现交互性的方法吗?

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

    是的,光线投射是“昂贵的”,并且在每一帧都调用它一点也不酷,有很多方法可以避免这种情况。在您的情况下,您可以像这样简单地重组代码:

    private void Update()
    {
    
        if (Input.GetKeyDown(KeyCode.E))
        {
          RaycastHit hit;
          if (Physics.Raycast(transform.position, transform.forward, out hit, RANGE))
          {
              IInteractable interactable = hit.collider.GetComponent<IInteractable>();
    
              if (interactable != null)
              {
                  interactable.ShowInteractability();
                  interactable.Interact();      
              }
          }
      }
    }
    

    另外一个好主意是在一个单独的方法中获取游戏逻辑,这样您以后可以更轻松地修改它并避免 spaggeti xaxa。像这样:

    public void interactWithYourObject()
    {
        RaycastHit hit;
        if (Physics.Raycast(transform.position, transform.forward, out hit, RANGE))
          {
              IInteractable interactable = hit.collider.GetComponent<IInteractable>();
    
              if (interactable != null)
              {
                  interactable.ShowInteractability();
                  interactable.Interact();      
              }
          }
    }
    

    然后在你的更新中调用它,如果你的条件是这样的话:

    private void Update()
    {
       RaycastHit hit;
       if (Physics.Raycast(transform.position, transform.forward, out hit, RANGE))
       {
          interactWithYourObject()
       }
    }
    

    【讨论】:

    • 抱歉,我必须撤消接受,因为此解决方案不起作用。当某些东西被光线投射击中时,我必须打电话给interactable.ShowInteractability();,而不是仅在 KeyPress 上
    【解决方案2】:

    另一种方法是在可交互对象上放置一个球形触发器,然后您可以通过球形触发器的radius 控制范围。 这与我刚刚回答的另一个问题相似,因此我刚刚重新编写了代码。

    using UnityEngine;
    
    [RequireComponent(typeof(SphereCollider))]
    internal abstract class CollisionTrigger : MonoBehaviour
    {
        private bool _isPlayerInsideTrigger = false;
    
        private void Awake()
        {
            if(!GetComponent<SphereCollider>().isTrigger)
            {
                Debug.LogError("Please set the sphere collider to a trigger.");
                enabled = false;
                return;
            }
        }
    
        private void Update()
        {
            if(_isPlayerInsideTrigger)
            {
                FakeOnTriggerStay();
            }
        }
    
        private void OnTriggerEnter(Collider collider)
        {
            if(!collider.CompareTag("Player")) return;
            _isPlayerInsideTrigger = true;
        }
    
        public abstract void FakeOnTriggerStay();
    
        private void OnTriggerExit(Collider collider)
        {
            if(!collider.CompareTag("Player")) return;
            _isPlayerInsideTrigger = false;
        }
    }
    

    这是一个示例,用于演示使用上面提供的类您的 Key 类会是什么样子。

    internal class Key : CollisionTrigger
    {
        public override void FakeOnTriggerStay()
        {
            // Show the user they can now interact with it.
            // Outline Shader maybe?
    
            if(Input.GetKeyDown(KeyCode.E))
            {
                // Do something with the key.
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-01-28
      • 1970-01-01
      • 2017-12-13
      • 1970-01-01
      • 2016-02-05
      • 1970-01-01
      • 1970-01-01
      • 2011-06-02
      • 1970-01-01
      相关资源
      最近更新 更多