взаимодействовать с игровыми объектами в Unity - PullRequest
0 голосов
/ 29 сентября 2018

Я хочу взаимодействовать с игровыми объектами в 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
    }
}

Когда дело доходит до скрипта, который проверяет, является ли что-то взаимодействующим, я создал скрипт, который создает raycast, который проверяет наличие интерактивности.(Я прикрепляю этот скрипт к моей камере 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 запускает по одному на кадр.Есть ли другой способ достижения интерактивности?

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

Альтернативный метод заключается в размещении сферического триггера на интерактивных элементах , затем вы можете контролировать диапазон с помощью 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.
        }
    }
}
0 голосов
/ 29 сентября 2018

Да, радиопередача "дорогая", и называть ее каждый кадр совсем не круто, и есть много способов избежать этого.В вашем случае вы можете просто реструктурировать код следующим образом:

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();      
          }
      }
  }
}

Также хорошей идеей будет получить логику игрового процесса в отдельном методе, чтобы потом было проще ее изменить и избежать спаггети 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()
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...