You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
431 lines
16 KiB
431 lines
16 KiB
//========= Copyright 2016-2018, HTC Corporation. All rights reserved. =========== |
|
|
|
using HTC.UnityPlugin.Utility; |
|
using System.Collections.Generic; |
|
using UnityEngine; |
|
using UnityEngine.EventSystems; |
|
|
|
namespace HTC.UnityPlugin.ColliderEvent |
|
{ |
|
public interface IColliderEventCaster |
|
{ |
|
GameObject gameObject { get; } |
|
Transform transform { get; } |
|
MonoBehaviour monoBehaviour { get; } |
|
|
|
Rigidbody rigid { get; } |
|
} |
|
|
|
[RequireComponent(typeof(Rigidbody))] |
|
public class ColliderEventCaster : MonoBehaviour, IColliderEventCaster |
|
{ |
|
private static HashSet<int> s_gos = new HashSet<int>(); |
|
|
|
private bool isUpdating; |
|
private bool isDisabled; |
|
|
|
private IndexedSet<Collider> stayingColliders = new IndexedSet<Collider>(); |
|
private IndexedSet<GameObject> hoveredObjects = new IndexedSet<GameObject>(); |
|
|
|
private Rigidbody m_rigid; |
|
private ColliderHoverEventData hoverEventData; |
|
|
|
protected readonly List<ColliderButtonEventData> buttonEventDataList = new List<ColliderButtonEventData>(); |
|
protected readonly List<ColliderAxisEventData> axisEventDataList = new List<ColliderAxisEventData>(); |
|
|
|
private List<GameObject> hoverEnterHandlers = new List<GameObject>(); |
|
private List<GameObject> hoverExitHandlers = new List<GameObject>(); |
|
|
|
protected class ButtonHandlers |
|
{ |
|
public List<GameObject> pressEnterHandlers = new List<GameObject>(); |
|
public List<GameObject> pressExitHandlers = new List<GameObject>(); |
|
public List<GameObject> pressDownHandlers = new List<GameObject>(); |
|
public List<GameObject> pressUpHandlers = new List<GameObject>(); |
|
public List<GameObject> clickHandlers = new List<GameObject>(); |
|
public List<GameObject> dragStartHandlers = new List<GameObject>(); |
|
public List<GameObject> dragFixedUpdateHandlers = new List<GameObject>(); |
|
public List<GameObject> dragUpdateHandlers = new List<GameObject>(); |
|
public List<GameObject> dragEndHandlers = new List<GameObject>(); |
|
public List<GameObject> dropHandlers = new List<GameObject>(); |
|
} |
|
|
|
protected class AxisHandlers |
|
{ |
|
public List<GameObject> axisChangedHandlers = new List<GameObject>(); |
|
} |
|
|
|
private List<ButtonHandlers> buttonEventHandlerList = new List<ButtonHandlers>(); |
|
private List<AxisHandlers> axisEventHanderList = new List<AxisHandlers>(); |
|
|
|
public MonoBehaviour monoBehaviour |
|
{ |
|
get { return this; } |
|
} |
|
|
|
public Rigidbody rigid |
|
{ |
|
get { return m_rigid ?? (m_rigid = GetComponent<Rigidbody>()); } |
|
} |
|
|
|
public ColliderHoverEventData HoverEventData |
|
{ |
|
get { return hoverEventData ?? (hoverEventData = new ColliderHoverEventData(this)); } |
|
protected set { hoverEventData = value; } |
|
} |
|
|
|
private bool CannotHandlerDragAnymore(GameObject handler) |
|
{ |
|
return !ExecuteEvents.CanHandleEvent<IColliderEventDragStartHandler>(handler); |
|
} |
|
|
|
protected virtual void OnEnable() |
|
{ |
|
isDisabled = false; |
|
} |
|
|
|
protected virtual void FixedUpdate() |
|
{ |
|
isUpdating = true; |
|
|
|
// fixed dragging |
|
for (int i = 0, imax = buttonEventDataList.Count; i < imax; ++i) |
|
{ |
|
var eventData = buttonEventDataList[i]; |
|
var handlers = GetButtonHandlers(i); |
|
|
|
eventData.draggingHandlers.RemoveAll(CannotHandlerDragAnymore); |
|
|
|
if (!eventData.isPressed) { continue; } |
|
|
|
for (int j = eventData.draggingHandlers.Count - 1; j >= 0; --j) |
|
{ |
|
handlers.dragFixedUpdateHandlers.Add(eventData.draggingHandlers[j]); |
|
} |
|
} |
|
|
|
ExecuteAllEvents(); |
|
|
|
if (isDisabled) |
|
{ |
|
CleanUp(); |
|
} |
|
|
|
stayingColliders.Clear(); |
|
|
|
isUpdating = false; |
|
} |
|
|
|
protected virtual void OnTriggerStay(Collider other) |
|
{ |
|
stayingColliders.AddUnique(other); |
|
} |
|
|
|
protected virtual void Update() |
|
{ |
|
isUpdating = true; |
|
|
|
// process enter |
|
var hoveredObjectsPrev = hoveredObjects; |
|
hoveredObjects = IndexedSetPool<GameObject>.Get(); |
|
|
|
for (int i = stayingColliders.Count - 1; i >= 0; --i) |
|
{ |
|
var collider = stayingColliders[i]; |
|
|
|
if (collider == null) { continue; } |
|
|
|
// travel from collider's gameObject to its root |
|
for (var tr = collider.transform; !ReferenceEquals(tr, null); tr = tr.parent) |
|
{ |
|
var go = tr.gameObject; |
|
|
|
if (!hoveredObjects.AddUnique(go)) { break; } // hit traveled gameObject, break and travel from the next collider |
|
|
|
if (hoveredObjectsPrev.Remove(go)) { continue; } // gameObject already existed in last frame, no need to execute enter event |
|
|
|
hoverEnterHandlers.Add(go); |
|
} |
|
} |
|
|
|
// process leave |
|
for (int i = hoveredObjectsPrev.Count - 1; i >= 0; --i) |
|
{ |
|
hoverExitHandlers.Add(hoveredObjectsPrev[i]); |
|
} |
|
|
|
IndexedSetPool<GameObject>.Release(hoveredObjectsPrev); |
|
|
|
// process button events |
|
for (int i = 0, imax = buttonEventDataList.Count; i < imax; ++i) |
|
{ |
|
var eventData = buttonEventDataList[i]; |
|
var handlers = GetButtonHandlers(i); |
|
|
|
eventData.draggingHandlers.RemoveAll(CannotHandlerDragAnymore); |
|
|
|
// process button press |
|
if (!eventData.isPressed) |
|
{ |
|
if (eventData.GetPress()) |
|
{ |
|
ProcessPressDown(eventData, handlers); |
|
ProcessPressing(eventData, handlers); |
|
} |
|
} |
|
else |
|
{ |
|
if (eventData.GetPress()) |
|
{ |
|
ProcessPressing(eventData, handlers); |
|
} |
|
else |
|
{ |
|
ProcessPressUp(eventData, handlers); |
|
} |
|
} |
|
|
|
// process pressed button enter/exit |
|
if (eventData.isPressed) |
|
{ |
|
var pressEnteredObjectsPrev = eventData.pressEnteredObjects; |
|
eventData.pressEnteredObjects = IndexedSetPool<GameObject>.Get(); |
|
|
|
for (int j = hoveredObjects.Count - 1; j >= 0; --j) |
|
{ |
|
eventData.pressEnteredObjects.Add(hoveredObjects[j]); |
|
|
|
if (pressEnteredObjectsPrev.Remove(hoveredObjects[j])) { continue; } // gameObject already existed in last frame, no need to execute enter event |
|
|
|
handlers.pressEnterHandlers.Add(hoveredObjects[j]); |
|
} |
|
|
|
for (int j = pressEnteredObjectsPrev.Count - 1; j >= 0; --j) |
|
{ |
|
eventData.clickingHandlers.Remove(pressEnteredObjectsPrev[j]); // remove the obj from clicking obj if it leaved |
|
|
|
handlers.pressExitHandlers.Add(pressEnteredObjectsPrev[j]); |
|
} |
|
|
|
IndexedSetPool<GameObject>.Release(pressEnteredObjectsPrev); |
|
} |
|
else |
|
{ |
|
for (int j = eventData.pressEnteredObjects.Count - 1; j >= 0; --j) |
|
{ |
|
handlers.pressExitHandlers.Add(eventData.pressEnteredObjects[j]); |
|
} |
|
|
|
eventData.pressEnteredObjects.Clear(); |
|
} |
|
} |
|
|
|
// process axis events |
|
for (int i = 0, imax = axisEventDataList.Count; i < imax; ++i) |
|
{ |
|
var eventData = axisEventDataList[i]; |
|
|
|
if ((eventData.v4 = eventData.GetDelta()) == Vector4.zero) { continue; } |
|
|
|
var handlers = GetAxisHandlers(i); |
|
|
|
GetEventHandlersFromHoveredColliders<IColliderEventAxisChangedHandler>(handlers.axisChangedHandlers); |
|
} |
|
|
|
ExecuteAllEvents(); |
|
|
|
if (isDisabled) |
|
{ |
|
CleanUp(); |
|
} |
|
|
|
isUpdating = false; |
|
} |
|
|
|
protected void ProcessPressDown(ColliderButtonEventData eventData, ButtonHandlers handlers) |
|
{ |
|
eventData.isPressed = true; |
|
eventData.pressPosition = transform.position; |
|
eventData.pressRotation = transform.rotation; |
|
|
|
// click start |
|
GetEventHandlersFromHoveredColliders<IColliderEventClickHandler>(eventData.clickingHandlers); |
|
// press down |
|
GetEventHandlersFromHoveredColliders<IColliderEventPressDownHandler>(handlers.pressDownHandlers); |
|
// drag start |
|
GetEventHandlersFromHoveredColliders<IColliderEventDragStartHandler>(eventData.draggingHandlers, handlers.dragStartHandlers); |
|
} |
|
|
|
protected void ProcessPressing(ColliderButtonEventData eventData, ButtonHandlers handlers) |
|
{ |
|
// dragging |
|
for (int i = eventData.draggingHandlers.Count - 1; i >= 0; --i) |
|
{ |
|
handlers.dragUpdateHandlers.Add(eventData.draggingHandlers[i]); |
|
} |
|
} |
|
|
|
protected void ProcessPressUp(ColliderButtonEventData eventData, ButtonHandlers handlers) |
|
{ |
|
eventData.isPressed = false; |
|
|
|
// press up |
|
GetEventHandlersFromHoveredColliders<IColliderEventPressUpHandler>(handlers.pressUpHandlers); |
|
// drag end |
|
for (int i = eventData.draggingHandlers.Count - 1; i >= 0; --i) |
|
{ |
|
handlers.dragEndHandlers.Add(eventData.draggingHandlers[i]); |
|
} |
|
// drop |
|
if (eventData.draggingHandlers.Count > 0) |
|
{ |
|
GetEventHandlersFromHoveredColliders<IColliderEventDropHandler>(handlers.dropHandlers); |
|
} |
|
// click end (execute only if pressDown handler and pressUp handler are the same) |
|
|
|
for (int i = stayingColliders.Count - 1; i >= 0; --i) |
|
{ |
|
var collider = stayingColliders[i]; |
|
|
|
if (collider == null) { continue; } |
|
|
|
var handler = ExecuteEvents.GetEventHandler<IColliderEventClickHandler>(collider.gameObject); |
|
|
|
if (ReferenceEquals(handler, null)) { continue; } |
|
|
|
if (!eventData.clickingHandlers.Remove(handler)) { continue; } |
|
|
|
handlers.clickHandlers.Add(handler); |
|
} |
|
|
|
eventData.clickingHandlers.Clear(); |
|
eventData.draggingHandlers.Clear(); |
|
} |
|
|
|
protected virtual void OnDisable() |
|
{ |
|
isDisabled = true; |
|
|
|
if (!isUpdating) |
|
{ |
|
CleanUp(); |
|
} |
|
} |
|
|
|
private void CleanUp() |
|
{ |
|
// release all |
|
for (int i = 0, imax = buttonEventDataList.Count; i < imax; ++i) |
|
{ |
|
var eventData = buttonEventDataList[i]; |
|
var handlers = GetButtonHandlers(i); |
|
|
|
eventData.draggingHandlers.RemoveAll(CannotHandlerDragAnymore); |
|
|
|
if (eventData.isPressed) |
|
{ |
|
ProcessPressUp(eventData, handlers); |
|
} |
|
|
|
for (int j = eventData.pressEnteredObjects.Count - 1; j >= 0; --j) |
|
{ |
|
handlers.pressExitHandlers.Add(eventData.pressEnteredObjects[j]); |
|
} |
|
|
|
eventData.clickingHandlers.Clear(); |
|
eventData.draggingHandlers.Clear(); |
|
eventData.pressEnteredObjects.Clear(); |
|
} |
|
|
|
// exit all |
|
for (int i = hoveredObjects.Count - 1; i >= 0; --i) |
|
{ |
|
hoverExitHandlers.Add(hoveredObjects[i]); |
|
} |
|
|
|
hoveredObjects.Clear(); |
|
|
|
stayingColliders.Clear(); |
|
|
|
ExecuteAllEvents(); |
|
} |
|
|
|
private ButtonHandlers GetButtonHandlers(int i) |
|
{ |
|
while (i >= buttonEventHandlerList.Count) { buttonEventHandlerList.Add(null); } |
|
return buttonEventHandlerList[i] ?? (buttonEventHandlerList[i] = new ButtonHandlers()); |
|
} |
|
|
|
private AxisHandlers GetAxisHandlers(int i) |
|
{ |
|
while (i >= axisEventHanderList.Count) { axisEventHanderList.Add(null); } |
|
return axisEventHanderList[i] ?? (axisEventHanderList[i] = new AxisHandlers()); |
|
} |
|
|
|
private void GetEventHandlersFromHoveredColliders<T>(params IList<GameObject>[] appendHandlers) where T : IEventSystemHandler |
|
{ |
|
for (int i = stayingColliders.Count - 1; i >= 0; --i) |
|
{ |
|
var collider = stayingColliders[i]; |
|
|
|
if (collider == null) { continue; } |
|
|
|
var handler = ExecuteEvents.GetEventHandler<T>(collider.gameObject); |
|
|
|
if (ReferenceEquals(handler, null)) { continue; } |
|
|
|
if (!s_gos.Add(handler.GetInstanceID())) { continue; } |
|
|
|
foreach (var handlers in appendHandlers) |
|
{ |
|
handlers.Add(handler); |
|
} |
|
} |
|
|
|
s_gos.Clear(); |
|
} |
|
|
|
private void ExecuteAllEvents() |
|
{ |
|
ExcuteHandlersEvents(hoverEnterHandlers, HoverEventData, ExecuteColliderEvents.HoverEnterHandler); |
|
|
|
for (int i = buttonEventHandlerList.Count - 1; i >= 0; --i) |
|
{ |
|
if (buttonEventHandlerList[i] == null) { continue; } |
|
|
|
ExcuteHandlersEvents(buttonEventHandlerList[i].pressEnterHandlers, buttonEventDataList[i], ExecuteColliderEvents.PressEnterHandler); |
|
|
|
ExcuteHandlersEvents(buttonEventHandlerList[i].pressDownHandlers, buttonEventDataList[i], ExecuteColliderEvents.PressDownHandler); |
|
ExcuteHandlersEvents(buttonEventHandlerList[i].pressUpHandlers, buttonEventDataList[i], ExecuteColliderEvents.PressUpHandler); |
|
ExcuteHandlersEvents(buttonEventHandlerList[i].dragStartHandlers, buttonEventDataList[i], ExecuteColliderEvents.DragStartHandler); |
|
ExcuteHandlersEvents(buttonEventHandlerList[i].dragFixedUpdateHandlers, buttonEventDataList[i], ExecuteColliderEvents.DragFixedUpdateHandler); |
|
ExcuteHandlersEvents(buttonEventHandlerList[i].dragUpdateHandlers, buttonEventDataList[i], ExecuteColliderEvents.DragUpdateHandler); |
|
ExcuteHandlersEvents(buttonEventHandlerList[i].dragEndHandlers, buttonEventDataList[i], ExecuteColliderEvents.DragEndHandler); |
|
|
|
ExcuteHandlersEvents(buttonEventHandlerList[i].dropHandlers, buttonEventDataList[i], ExecuteColliderEvents.DropHandler); |
|
ExcuteHandlersEvents(buttonEventHandlerList[i].clickHandlers, buttonEventDataList[i], ExecuteColliderEvents.ClickHandler); |
|
|
|
ExcuteHandlersEvents(buttonEventHandlerList[i].pressExitHandlers, buttonEventDataList[i], ExecuteColliderEvents.PressExitHandler); |
|
} |
|
|
|
for (int i = axisEventHanderList.Count - 1; i >= 0; --i) |
|
{ |
|
if (axisEventHanderList[i] == null) { continue; } |
|
|
|
ExcuteHandlersEvents(axisEventHanderList[i].axisChangedHandlers, axisEventDataList[i], ExecuteColliderEvents.AxisChangedHandler); |
|
} |
|
|
|
ExcuteHandlersEvents(hoverExitHandlers, HoverEventData, ExecuteColliderEvents.HoverExitHandler); |
|
} |
|
|
|
private void ExcuteHandlersEvents<T>(List<GameObject> handlers, BaseEventData eventData, ExecuteEvents.EventFunction<T> functor) where T : IEventSystemHandler |
|
{ |
|
for (int i = handlers.Count - 1; i >= 0; --i) |
|
{ |
|
ExecuteEvents.Execute(handlers[i], eventData, functor); |
|
} |
|
|
|
handlers.Clear(); |
|
} |
|
} |
|
} |