Как я могу решить, какие объекты должны быть обнаружены и что следует игнорировать с помощью raycast и как? - PullRequest
0 голосов
/ 27 мая 2019

У меня есть две основные проблемы в этом случае:

  1. NAVI является дочерним элементом игрока (FPSController), поэтому NAVI движется вместе с игроком. Но NAVI также находится немного впереди игрока, и в результате лучевая трансляция впервые попадает в NAVI, а не в объект Interactable.

  2. Если между игроком и каким-нибудь интерактивным объектом есть дверь, он обнаружит этот объект. Но если между игроком и интерактивными объектами есть дверь и другие объекты, она не должна их обнаруживать. Игрок их не видит, но обнаруживает.

Этот скрипт прикреплен к плахеру (FPSController):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class DetectInteractable : UnityEngine.MonoBehaviour
{
    public Camera cam;
    public float distanceToSee;
    public string objectHit;
    public bool interactableObject = false;
    public Transform parentToSearch;
    public Scaling scaling;
    public int spinX = 0;
    public int spinY = 0;
    public int spinZ = 0;
    public GameObject navi;
    public GameObject itemsDescriptionCanvas;
    public Text itemsDescriptionText;

    private RaycastHit whatObjectHit;
    private Transform[] childrenToSearhc;

    private void Start()
    {
        childrenToSearhc = parentToSearch.GetComponentsInChildren<Transform>();
    }

    private void Update()
    {
        if (cam.enabled == true)
        {
            if (Input.GetMouseButtonDown(0) && !scaling.scaleUp)
            {
                if (whatObjectHit.collider != null)
                    ExecuteActions(whatObjectHit.collider.gameObject);
            }

            Debug.DrawRay(cam.transform.position, cam.transform.forward * distanceToSee, Color.magenta);
            if (Physics.Raycast(cam.transform.position, cam.transform.forward, out whatObjectHit, distanceToSee))
            {
                objectHit = whatObjectHit.collider.gameObject.name;
                interactableObject = true;
                print("Hit ! " + whatObjectHit.collider.gameObject.name);

                if (scaling.objectToScale.transform.localScale == scaling.minSize)
                {
                    scaling.objectToScale.transform.Rotate(spinX, spinY, spinZ);
                }
                ProcessItemsDescripations();
                itemsDescriptionCanvas.SetActive(true);
            }
            else
            {
                if (scaling.objectToScale.transform.localScale == scaling.minSize)
                {
                    navi.transform.rotation = new Quaternion(0, 0, 0, 0);
                }
                itemsDescriptionCanvas.SetActive(false);
                print("Not Hit !");
            }
        }
    }

    private void ExecuteActions(GameObject go)
    {
        var ia = go.GetComponent<ItemAction>();
        if (ia != null)
        {
            ia.ItemMove();
        }
    }

    void ProcessItemsDescripations()
    {
        foreach (Transform child in childrenToSearhc)
        {
            if (child.GetComponent<ItemInformation>() != null)
            {
                ItemInformation iteminformation = child.GetComponent<ItemInformation>();
                if (child.name == objectHit)
                {
                    itemsDescriptionText.text = iteminformation.description;
                }
            }
        }
    }

    public class ViewableObject : UnityEngine.MonoBehaviour
    {
        public string displayText;
        public bool isInteractable;
    }
}

И этот небольшой скрипт прикреплен к каждому объекту Interactable:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ItemInformation : UnityEngine.MonoBehaviour
{
    [TextArea]
    public string description;
}

Это скриншот настроек инспектора плеера (FPSController):

Player Hierarchy and Inspector

Этот снимок экрана - NAVI, являющийся дочерним элементом проигрывателя: Вы можете увидеть NAVI в левом окне игры и окне сцены:

Navi

Это пример скриншота окна. Окно должно быть Взаимодействующим объектом и должно быть обнаружено raycast:

Для тега окна установлено значение Untagged, а для слоя установлен значение по умолчанию

Windows Interactable object example

Это скриншот, когда в игре работает ситуация, когда игрок стоит за дверью, с другой стороны двери есть комната с интерактивным окном. Ничто не помешает радиопередаче пройти через дверь и обнаружить окно. И это не логика. Игрок не может видеть окно. Таким образом, окно не должно быть обнаружено:

Слева вверху пурпурный цвет raycast проходит через дверь к окну. Слева внизу игрок стоит за дверью и вообще видит окно, но обнаруживает окно:

Detect

Но когда вы используете точку останова, вы можете видеть, что действительно ударил NAVI, не дверь, не окно, а NAVI, поскольку NAVI всегда стоит перед игроком:

What was hit ? NAVI

Прежде всего я пытался использовать слой маски raycast в своем скрипте, а затем изменил слой окна на Interactable, а затем я увидел, что он обнаруживает через дверь.

В конце основной целью является:

Для обнаружения Взаимодействующих объектов в игре, но не для обнаружения NAVI, он не является Взаимодействующим объектом, поэтому каким-то образом сделать так, чтобы NAVI не блокировал лучевую трансляцию!

И чтобы иметь возможность обнаруживать объекты только при наличии логического представления игрока об объектах. И не обнаруживать предметы из-за дверей или стен или других предметов.

1 Ответ

2 голосов
/ 27 мая 2019

Вы можете использовать дополнительный необязательный параметр layerMask из Physics.Raycast

A Слой Используемая маскавыборочно игнорировать коллайдеры при наведении луча.

Я бы рекомендовал использовать LayerMask

public LayerMask targetLayer;

для настройки требуемых слоев с помощью инспектора Unity (выберите каждый слой, который вы хотитеударить) и, наконец, передать его в Raycast, как

<code>if(Physics.Raycast(
    cam.transform.position, 
    cam.transform.forward, 
    out whatObjectHit, 
    distanceToSee, 
    <b>targetLayer.value</b>))
{
    ...
}

В примере Unity непосредственно использует битовую маску (кстати, вочень неэффективный способ в Update):

// Bit shift the index of the layer (8) to get a bit mask
int layerMask = 1 << 8;

// This would cast rays only against colliders in layer 8.
// But instead we want to collide against everything except layer 8. The ~ operator does this, it inverts a bitmask.
layerMask = ~layerMask;

, как я уже сказал, мне не нравится этот способ его жесткого кодирования.Кроме того, теперь вы только исключаете слой 8, но нажимаете все остальное .

Чтобы включить только один конкретный слой, удалите строку

layerMask = ~layerMask;

, чтобы вы только ударить по слою 8 .

В любом случае, использование моего предыдущего пути более гибко, и вы предпочитаете выбирать те слои, на которые вы действительно хотите попасть, вместо исключения одного.И использовать LayerMask гораздо проще, чем кодировать некоторые операции битовой маски для создания требуемой маски слоя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...