2016-11-07 2 views
2

В эти дни в Unity вы очень легко обнаружить прикосновение объектов с помощью raycaster ...Unity3D, имеют ли BOTH 3D и UI Raycaster одновременно реагировать на прикосновение?

public class DragThreeDee:MonoBehaviour,IPointerDownHandler 
     IPointerUpHandler, IBeginDragHandler, 
     IDragHandler, IEndDragHandler 
     { 
     public void OnPointerDown (PointerEventData data) 
      { etc 

Таким образом, относительно вашего слоя пользовательского интерфейса, он правильно игнорирует контакт на уровне пользовательского интерфейса и так далее.

Что делать, если вы хотите следующее произойдет,

вы хотите собрать (одновременно, в том же кадре, и другое) прикосновение, которое заканчивается как 3D-объект, а элемент пользовательского интерфейса?

(Представьте, что на экране есть несколько прозрачных кнопок пользовательского интерфейса, у вас также есть обычные 3D-роботы. Пользователь нажимает на точку на экране, где есть кнопка пользовательского интерфейса, и «снизу», робот . ОБА сценарий робота, как указано выше, и кнопка, должны ответить.)

Как вы это сделаете? Я много раз пробовал использовать отдельные камеры, отдельно EventSystem, настраивая слои, блокируя маски и т. Д. Я не могу найти способ сделать это.

Как это сделать в единстве?

+0

Я боюсь, что это встроено в функции StandaloneInputModule. Кажется, что если какой-либо из графических рекапистов вернет хит, а PhysicalRaycaster не будет проверен. Вы можете попробовать переопределить StandaloneInuputModule, я думаю:/ –

+0

Hi @NikaKasradze - - - Увлекательно, похоже, что вы ударили ноготь по голове. Очень интересно ... – Fattie

+0

Пожалуйста, напишите ответ, если найдете решение –

ответ

2

Выглядит сложным, но может быть сделано.

. Извлеките данные из PointerEventData во все компоненты пользовательского интерфейса, которые вы хотите разблокировать 3D GameObjects raycast.

. Получите все экземпляры PhysicsRaycaster с FindObjectsOfType<PhysicsRaycaster>(). Что касается производительности, имеет смысл кэшировать это.

.Запустите Raycast с PhysicsRaycaster.Raycast, который будет возвращать все GameObjects с коллайдером, присоединенные к нему.

.Использование ExecuteEvents.Execute послать соответствующее событие к результату, хранящегося в RaycastResult.

RaycastForwarder сценарий:

public class RaycastForwarder : MonoBehaviour 
{ 
    List<PhysicsRaycaster> rayCast3D = new List<PhysicsRaycaster>(); 
    List<RaycastResult> rayCast3DResult = new List<RaycastResult>(); 

    private static RaycastForwarder localInstance; 
    public static RaycastForwarder Instance { get { return localInstance; } } 


    private void Awake() 
    { 
     if (localInstance != null && localInstance != this) 
     { 
      Destroy(this.gameObject); 
     } 
     else 
     { 
      localInstance = this; 
     } 
    } 

    public void notifyPointerDown(PointerEventData eventData) 
    { 
     findColliders(eventData, PointerEventType.Down); 
    } 

    public void notifyPointerUp(PointerEventData eventData) 
    { 
     findColliders(eventData, PointerEventType.Up); 
    } 

    public void notifyPointerDrag(PointerEventData eventData) 
    { 
     findColliders(eventData, PointerEventType.Drag); 
    } 

    private void findColliders(PointerEventData eventData, PointerEventType evType) 
    { 
     UpdateRaycaster(); 

     //Loop Through All Normal Collider(3D/Mesh Renderer) and throw Raycast to each one 
     for (int i = 0; i < rayCast3D.Count; i++) 
     { 
      //Send Raycast to all GameObject with 3D Collider 
      rayCast3D[i].Raycast(eventData, rayCast3DResult); 
      sendRayCast(eventData, evType); 
     } 
     //Reset Result 
     rayCast3DResult.Clear(); 
    } 

    private void sendRayCast(PointerEventData eventData, PointerEventType evType) 
    { 
     //Loop over the RaycastResult and simulate the pointer event 
     for (int i = 0; i < rayCast3DResult.Count; i++) 
     { 
      GameObject target = rayCast3DResult[i].gameObject; 
      PointerEventData evData = createEventData(rayCast3DResult[i]); 

      if (evType == PointerEventType.Drag) 
      { 
       ExecuteEvents.Execute<IDragHandler>(target, 
             evData, 
             ExecuteEvents.dragHandler); 
      } 

      if (evType == PointerEventType.Down) 
      { 
       ExecuteEvents.Execute<IPointerDownHandler>(target, 
           evData, 
           ExecuteEvents.pointerDownHandler); 
      } 

      if (evType == PointerEventType.Up) 
      { 
       ExecuteEvents.Execute<IPointerUpHandler>(target, 
        evData, 
        ExecuteEvents.pointerUpHandler); 
      } 
     } 
    } 

    private PointerEventData createEventData(RaycastResult rayResult) 
    { 
     PointerEventData evData = new PointerEventData(EventSystem.current); 
     evData.pointerCurrentRaycast = rayResult; 
     return evData; 
    } 

    //Get all PhysicsRaycaster in the scene 
    private void UpdateRaycaster() 
    { 
     convertToList(FindObjectsOfType<PhysicsRaycaster>(), rayCast3D); 
    } 

    private void convertToList(PhysicsRaycaster[] fromComponent, List<PhysicsRaycaster> toComponent) 
    { 
     //Clear and copy new Data 
     toComponent.Clear(); 
     for (int i = 0; i < fromComponent.Length; i++) 
     { 
      toComponent.Add(fromComponent[i]); 
     } 
    } 

    public enum PointerEventType 
    { 
     Drag, Down, Up 
    } 
} 

RayCastRouter сценарий:

public class RayCastRouter : MonoBehaviour, IPointerDownHandler, 
     IPointerUpHandler, 
     IDragHandler 
{ 
    public void OnDrag(PointerEventData eventData) 
    { 
     RaycastForwarder.Instance.notifyPointerDrag(eventData); 
    } 

    public void OnPointerDown(PointerEventData eventData) 
    { 
     RaycastForwarder.Instance.notifyPointerDown(eventData); 
    } 

    public void OnPointerUp(PointerEventData eventData) 
    { 
     RaycastForwarder.Instance.notifyPointerUp(eventData); 
    } 
} 

Использование:

.Attach RaycastForwarder в пустой GameObject.

B .Attach RayCastRouter для любого компонента пользовательского интерфейса, такого как изображение, которое вы не хотите блокировать 3D GameObject. Вот и все. Любой компонент пользовательского интерфейса с прикрепленным к нему RayCastRouter будет иметь возможность разрешить 3D GameObject за ним получать raycast.

события теперь будет отправлен в 3D объект, который имеет скрипт, который реализует функцию из IPointerDownHandler, IPointerUpHandler и IDragHandler интерфейса.

Не забудьте прикрепить Physics Raycaster к камере.

+0

Wow - проверьте это! – Fattie

+0

Почти все ответы, которые я задал в вашем вопросе несколько часов назад, требуют пересылки событий. Я тестировал это более одного дня, и у этого, похоже, нет ошибки. Дайте мне знать, если вы заметите ошибку. – Programmer

Смежные вопросы