HumanoidControl_Free/Runtime/Tools/Scripts/InteractionPointer.cs

806 lines
35 KiB
C#

using UnityEngine;
using UnityEngine.EventSystems;
namespace Passer {
/// <summary>A generic pointer to interact with objects in the scene using the Unity Event system. </summary>
/// The interaction pointer is a generic pointer to interact with objects in the scene using the
/// Unity Event system or InteractionEvents. The objects can receive and react on these interactions
/// when an Unity Event Trigger component has been added to them. The Teleporter is an specific
/// implementation of an Interaction Pointer.
///
/// Setup
/// =====
/// An interaction pointer can be added to any object.
/// The objects Transform determines the starting position of the pointer and the pointer
/// will always point in the direction of the Transform Forward.
///
/// Configuration
/// =============
/// \image html InteractionPointerInspector.png
/// \image rtf InteractionPointerInspector.png
///
/// * \ref InteractionPointer::active "Active"
/// * \ref InteractionPointer::timedClick "Timed Click"
/// * \ref InteractionPointer::focusPointObj "Focus Point Object"
/// * \ref InteractionPointer::objectInFocus "Object in Focus"
/// * \ref InteractionPointer::rayType "Mode"
///
/// Straight Cast
/// ------------
/// The straight mode will cast a ray from the Transform position
/// in the forward direction until it hits an object.
///
/// Bezier Cast
/// ----------
/// In bezier mode, a curve will be cast from the Transform position in the forward direction.
/// The distance reached by this curve is limited. The curve is determine by the following parameters:
///
/// * \ref InteractionPointer::maxDistance "Maximum Distance":
/// this determines the maximum distance in units you can reach with the curve
/// * \ref InteractionPointer::resolution "Resolution":
/// the number of segments in the curve. Higher gives a smoother curve but requires more performance.
///
/// Gravity Cast
/// -----------
/// In gravity mode, a curve will be cast from the Transform position in the forward direction.
/// This curve follows a gravity path as if an object is launched.
/// The curve can be configured with the following parameters:
///
/// * \ref InteractionPointer::maxDistance "Maximum Distance":
/// the maximum length of the curve in units.
/// * \ref InteractionPointer::resolution "Resolution":
/// the number of segments of the curve. Higher gives are smoother curve but requires more performance.
/// * \ref InteractionPointer::speed "Speed":
/// the horizontal speed determining the curve. A higher value can reach further positions.
///
/// Sphere Cast
/// -----------
/// Is similar to the Straight mode, but casts a sphere instead of a ray.
/// It has the following configuration parameters:
///
/// * \ref InteractionPointer::maxDistance "Maximum Distance":
/// the distance the sphere is case.
/// * \ref InteractionPointer::radius "Radius":
/// the radius of the sphere.
///
/// Focus Point Object
/// ------------------
/// The Focus Point Object is disabled or enabled automatically
/// when the Interaction Pointer is activated or deactivated.
/// The Transform of the target point object will be updated based on the ray curve to match
/// the focus point of the Interaction Pointer. It will be aligned with the normal of the surface.
/// This object can be used to show the focus point of the interaction pointer in the way you like.
///
/// Line Renderer
/// -------------
/// When an line renderer is attached to the Focus Point Object,
/// it will automatically be updated to show the line ray casting curve.
/// You can change this line render to your likings.
/// Only the positions will be overwritten when the Interaction Pointer is active.
///
/// Events
/// ======
/// * \ref InteractionPointer::activeEvent "Active Event"
/// * \ref InteractionPointer::clickEvent "Click Event"
/// * \ref InteractionPointer::focusEvent "Focus Event"
///
/// Event System Compatibility
/// ==========================
/// The following event of the
/// <a href="https://docs.unity3d.com/Manual/SupportedEvents.html">Event System</a>
/// are currently supported:
/// * PointerDown: is sent to the object in focus when the click starts
/// * PointerUp: is sent to the object in focus when the click ends
/// * PointerClick: is sent to the object when a click has been completed
/// * PointerEnter: is sent to an object when it comes into focus of the Interaction Pointer
/// * PointerExit: is sent to an object when it no longer is in focus of the Interaction Pointer
/// * BeginDrag: is sent to the object in focus when a click has started and the focus point starts to move
/// * Drag: is sent to the object in focus while the focus point changes during a click
/// * EndDrag: is sent to the object in focus when the click ends after the focus point started to move
[HelpURLAttribute("https://passervr.com/apis/HumanoidControl/Unity/class_passer_1_1_interaction_pointer.html")]
public class InteractionPointer : MonoBehaviour {
protected static void DebugLog(string s) {
#if UNITY_EDITOR
//Debug.Log(s);
#endif
}
/// <summary>Is the interaction pointer active?</summary>
/// When an interaction pointer is active, it will actively point to objects.
/// The objectInFocus will be updated based on the pointer.
/// When a focusPointObj is set, this object will be set active.
/// When a Line Renderer is set, the line renderer will be updated
/// according to the properties of the pointer.
public bool active = true;
/// <summary>Automatically initiates a click when the objectInFocus does not change for the set amount of seconds.</summary>
/// The value 0 disables this function.
public float timedClick;
protected bool hasClicked = false;
/// <summary>The GameObject which represents the focus point of the Interaction Pointer when it is active.</summary>
/// If this is set and the pointer is active, the object will be objected based on the pointer's properties
/// This GameObject will be disabled when the pointer is not active.
public GameObject focusPointObj;
/// <summary>The object to which the Interaction Pointer is pointing at.</summary>
/// This is updated at runtime while the pointer is active.
/// The value is null when the pointer is not reaching any object.
public GameObject objectInFocus;
/// <summary>
/// Distance to the objectInFocus
/// </summary>
/// This is float.infintiy when no object is in focus
public float focusDistance;
//protected new EventSystem eventSystem;
//protected PointerEventData data;
protected InteractionModule interactionModule;
protected int interactionID;
protected InteractionModule.InteractionPointer interactionPointer;
/// <summary>The LineRender for this pointer when available.</summary>
protected LineRenderer lineRenderer;
/// <summary>The ray modes for interaction pointers.</summary>
public enum RayType {
Straight, //< The straight mode will cast a ray from the Transform position in the forward direction until it hits an object.
Bezier, //< In bezier mode, a bezier curve will be cast from the Transform position in the forward direction.
Gravity, //< In gravity mode, a curve will be cast from the Transform position in the forward direction. This curve follows a gravity path as if an object is launched.
SphereCast, //< Is similar to the Straight mode, but casts a sphere instead of a ray.
}
/// <summary>The ray mode for this interaction pointer.</summary>
public RayType rayType = RayType.Straight;
/// <summary>The maximum length of the curve in units(meters)</summary>
/// This value is used for Straight, SphereCast and Bezier RayTypes
public float maxDistance = 10;
/// <summary>The size of a segment in the curve</summary>
/// Lower values will give a smoother curve, but requires more performance
/// This value is used for Bezier and Gravity RayTypes
public float resolution = 0.2F;
private int nCurveSegments;
private Vector3[] curvePoints;
/// <summary>The type of interaction pointer</summary>
public enum PointerType {
FocusPoint, //< will not use a linerender, but a focuspoint mesh
Ray //< will use a linerendere, but not a focuspoint mesh
}
/// <summary>Adds a default InteractionPointer to the transform</summary>
/// <param name="parentTransform">The transform to which the Teleporter will be added</param>
/// <param name="pointerType">The interaction pointer type for the Teleporter.</param>
public static InteractionPointer Add(Transform parentTransform, PointerType pointerType = PointerType.Ray) {
GameObject pointerObj = new GameObject("Interaction Pointer");
pointerObj.transform.SetParent(parentTransform);
pointerObj.transform.localPosition = Vector3.zero;
pointerObj.transform.localRotation = Quaternion.identity;
GameObject focusPointObj = new GameObject("FocusPoint");
focusPointObj.transform.SetParent(pointerObj.transform);
focusPointObj.transform.localPosition = Vector3.zero;
focusPointObj.transform.localRotation = Quaternion.identity;
if (pointerType == PointerType.FocusPoint) {
GameObject focusPointSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
focusPointSphere.transform.SetParent(focusPointObj.transform);
focusPointSphere.transform.localPosition = Vector3.zero;
focusPointSphere.transform.localRotation = Quaternion.identity;
focusPointSphere.transform.localScale = Vector3.one * 0.1F;
Collider collider = focusPointSphere.GetComponent<Collider>();
DestroyImmediate(collider, true);
}
else {
LineRenderer pointerRay = focusPointObj.AddComponent<LineRenderer>();
pointerRay.startWidth = 0.01F;
pointerRay.endWidth = 0.01F;
pointerRay.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
pointerRay.receiveShadows = false;
pointerRay.useWorldSpace = false;
#if UNITY_EDITOR
string[] foldersToSearch = new string[] { "Assets/Passer" };
string[] oranges = UnityEditor.AssetDatabase.FindAssets("OrangeUnlit t:Material", foldersToSearch);
if (oranges.Length > 0) {
string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(oranges[0]);
Material orange = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(assetPath);
pointerRay.material = orange;
}
#endif
}
InteractionPointer pointer = pointerObj.AddComponent<InteractionPointer>();
pointer.focusPointObj = focusPointObj;
pointer.rayType = RayType.Straight;
return pointer;
}
#region Init
protected virtual void Awake() {
Transform rootTransform = this.transform.root;
interactionModule = FindObjectOfType<InteractionModule>();
if (interactionModule == null)
interactionModule = CreateInteractionModule();
EventSystem eventSystem = interactionModule.GetComponent<EventSystem>();
interactionID = interactionModule.CreateNewInteraction(transform, timedClick, eventSystem);
//EventSystem eventSystem = FindObjectOfType<EventSystem>();
//if (eventSystem == null) {
// eventSystem = CreateEventSystem();
//}
//data = new PointerEventData(eventSystem);
if (focusPointObj == null) {
focusPointObj = new GameObject("Focus Point");
focusPointObj.transform.parent = transform;
}
lineRenderer = focusPointObj.GetComponent<LineRenderer>();
if (lineRenderer != null) {
lineRenderer.useWorldSpace = false;
lineRenderer.SetPosition(1, Vector3.zero);
}
}
protected virtual InteractionModule CreateInteractionModule() {
Humanoid.HumanoidControl humanoid = GetComponentInParent<Humanoid.HumanoidControl>();
if (humanoid != null) {
InteractionModule humanoidInteractionModule = humanoid.gameObject.AddComponent<InteractionModule>();
return humanoidInteractionModule;
}
GameObject interactionModuleObj = new GameObject("InteractionModule");
InteractionModule interactionModule = interactionModuleObj.AddComponent<InteractionModule>();
return interactionModule;
}
protected virtual EventSystem CreateEventSystem() {
Humanoid.HumanoidControl humanoid = GetComponentInParent<Humanoid.HumanoidControl>();
if (humanoid != null) {
EventSystem humanoidEventSystem = humanoid.gameObject.AddComponent<EventSystem>();
return humanoidEventSystem;
}
GameObject eventSystemObject = new GameObject("EventSystem");
EventSystem eventSystem = eventSystemObject.AddComponent<EventSystem>();
return eventSystem;
}
protected virtual void Start() {
nCurveSegments = Mathf.CeilToInt(maxDistance / resolution);
curvePoints = new Vector3[nCurveSegments + 1];
}
#endregion
#region Update
protected float focusTimeToTouch = 0;
protected float focusStart = 0;
protected virtual void Update() {
if (focusPointObj == null)
return;
if (maxDistance < 0)
maxDistance = 0;
if (active) {
focusPointObj.SetActive(true);
if (rayType == RayType.SphereCast) {
UpdateSpherecast();
}
else {
if (lineRenderer != null)
lineRenderer.enabled = true;
switch (rayType) {
case RayType.Straight:
UpdateStraight();
break;
case RayType.Bezier:
UpdateBezier();
break;
case RayType.Gravity:
UpdateGravity();
break;
}
if (objectInFocus != null) {
Rigidbody rigidbodyInFocus = objectInFocus.GetComponentInParent<Rigidbody>();
if (rigidbodyInFocus != null)
objectInFocus = rigidbodyInFocus.gameObject;
}
if (timedClick != 0) {
if (!hasClicked && focusTimeToTouch != 0 && focusStart > 0 &&
Time.time - focusStart > focusTimeToTouch) {
Click(true);
hasClicked = true;
Click(false);
}
}
}
UpdateFocus();
UpdateFocusPoint();
}
else {
focusPointObj.SetActive(false);
focusPointObj.transform.position = transform.position;
objectInFocus = null;
focusDistance = float.PositiveInfinity;
hasClicked = false;
}
}
#region Straight
protected virtual void UpdateStraight() {
Vector3 focusPosition = transform.position + transform.forward * maxDistance;
Quaternion focusRotation = Quaternion.LookRotation(-transform.forward);
Debug.DrawRay(transform.position, transform.forward, Color.white);
RaycastHit hit;
bool raycastHit = Physics.Raycast(transform.position, transform.forward, out hit, maxDistance);
if (raycastHit) {
focusPosition = hit.point;
focusRotation = Quaternion.LookRotation(hit.normal);
objectInFocus = hit.transform.gameObject;
focusDistance = hit.distance;
}
else {
objectInFocus = null;
focusDistance = float.PositiveInfinity;
}
focusPointObj.transform.position = focusPosition;
focusPointObj.transform.rotation = focusRotation;
Vector3 endPosition = focusPointObj.transform.InverseTransformPoint(transform.position);
if (lineRenderer != null) {
lineRenderer.positionCount = 2;
lineRenderer.SetPosition(0, endPosition);
}
}
#endregion
#region Bezier
protected virtual void UpdateBezier() {
Vector3 normal;
GameObject focusObject = null;
Vector3[] bezierPositions = UpdateBezierCurve(transform, maxDistance, out normal, out focusObject);
Vector3 focusPosition = bezierPositions[bezierPositions.Length - 1];
Quaternion focusRotation = Quaternion.LookRotation(normal, transform.forward);
focusPointObj.transform.position = focusPosition; // bezierPositions[bezierPositions.Length - 1];
focusPointObj.transform.rotation = focusRotation; // Quaternion.LookRotation(normal, transform.forward);
for (int i = 0; i < bezierPositions.Length; i++)
bezierPositions[i] = focusPointObj.transform.InverseTransformPoint(bezierPositions[i]);
if (lineRenderer != null) {
lineRenderer.positionCount = bezierPositions.Length;
lineRenderer.SetPositions(bezierPositions);
}
}
protected float heightLimitAngle = 100f;
protected Vector3 startPosition = Vector3.zero;
protected Vector3 intermediatePosition;
protected Vector3 endPosition;
protected virtual Vector3[] UpdateBezierCurve(Transform transform, float maxDistance, out Vector3 normal, out GameObject focusObject) {
float distance = maxDistance;
float attachedRotation = Vector3.Dot(Vector3.up, transform.forward);
if ((attachedRotation * 100f) > heightLimitAngle) {
float controllerRotationOffset = 1f - (attachedRotation - (heightLimitAngle / 100f));
distance = (maxDistance * controllerRotationOffset) * controllerRotationOffset;
}
intermediatePosition = Vector3.forward * distance;
//Debug.DrawLine(this.transform.position, transform.TransformPoint(intermediatePosition));
RaycastHit rayHit;
if (Physics.Raycast(transform.TransformPoint(intermediatePosition), Vector3.down, out rayHit)) {
normal = rayHit.normal;
focusObject = rayHit.transform.gameObject;
focusDistance = Vector3.Distance(transform.position, rayHit.point);
endPosition = transform.InverseTransformPoint(rayHit.point);
for (int i = 0; i <= nCurveSegments; i++)
curvePoints[i] = GetPoint(i / (float)nCurveSegments, transform);
}
else {
normal = Vector3.up;
focusObject = null;
focusDistance = float.PositiveInfinity;
}
return curvePoints;
}
protected Vector3 GetPoint(float t, Transform transform) {
Vector3 localPoint = GetBezierPoint(startPosition, intermediatePosition, endPosition, t);
return transform.TransformPoint(localPoint);
}
protected Vector3 GetVelocity(float t, Transform transform) {
Vector3 localVelocity = GetBezierFirstDerivative(startPosition, intermediatePosition, endPosition, t);
return transform.TransformPoint(localVelocity) - transform.position;
}
private static Vector3 GetBezierPoint(Vector3 p0, Vector3 p1, Vector3 p2, float t) {
t = Mathf.Clamp01(t);
float oneMinusT = 1f - t;
return
oneMinusT * oneMinusT * p0 +
2f * oneMinusT * t * p1 +
t * t * p2;
}
private static Vector3 GetBezierFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, float t) {
return
2f * (1f - t) * (p1 - p0) +
2f * t * (p2 - p1);
}
#endregion
#region Gravity
/// <summary>The horizontal speed for a gravity curve.</summary>
/// A higher speed will reach further positions.
public float speed = 3;
protected virtual void UpdateGravity() {
Vector3 normal;
GameObject focusObject = null;
UpdateGravityCurve(transform, speed, out normal, out focusObject);
Vector3 focusPosition = curvePoints[curvePoints.Length - 1];
Quaternion focusRotation = Quaternion.LookRotation(normal, transform.forward);
focusPointObj.transform.position = focusPosition;
focusPointObj.transform.rotation = focusRotation;
for (int i = 0; i < curvePoints.Length; i++)
curvePoints[i] = focusPointObj.transform.InverseTransformPoint(curvePoints[i]);
if (lineRenderer != null) {
lineRenderer.positionCount = curvePoints.Length;
lineRenderer.SetPositions(curvePoints);
}
}
protected virtual void UpdateGravityCurve(Transform transform, float forwardSpeed, out Vector3 normal, out GameObject hitObject) {
curvePoints[0] = transform.position;
Vector3 segVelocity = transform.forward * forwardSpeed;
normal = Vector3.up;
hitObject = null;
focusDistance = float.PositiveInfinity;
for (int i = 1; i < nCurveSegments + 1; i++) {
if (hitObject != null) {
curvePoints[i] = curvePoints[i - 1];
continue;
}
// Time it takes to traverse one segment of length segScale (careful if velocity is zero)
float segTime = (segVelocity.sqrMagnitude != 0) ? resolution / segVelocity.magnitude : 0;
// Add velocity from gravity for this segment's timestep
segVelocity = segVelocity + Physics.gravity * segTime;
// Check to see if we're going to hit a physics object
RaycastHit hit;
if (Physics.Raycast(curvePoints[i - 1], segVelocity.normalized, out hit, resolution)) {
normal = hit.normal;
hitObject = hit.transform.gameObject;
focusDistance = Vector3.Distance(transform.position, hit.point);
// set next position to the position where we hit the physics object
curvePoints[i] = curvePoints[i - 1] + segVelocity.normalized * hit.distance;
}
// If our raycast hit no objects, then set the next position to the last one plus v*t
else {
curvePoints[i] = curvePoints[i - 1] + segVelocity * segTime;
}
}
}
#endregion
#region Spherecast
/// <summary>The radius of the sphere in a SphereCast</summary>
public float radius = 0.1F;
protected virtual void UpdateSpherecast() {
RaycastHit hit;
if (Physics.SphereCast(transform.position, radius, transform.forward, out hit, maxDistance)) {
objectInFocus = hit.transform.gameObject;
focusDistance = hit.distance;
focusPointObj.transform.position = hit.point;
focusPointObj.transform.rotation = Quaternion.LookRotation(hit.normal, transform.forward);
}
else {
objectInFocus = null;
focusDistance = float.PositiveInfinity;
focusPointObj.transform.position = transform.position + transform.forward * maxDistance;
focusPointObj.transform.rotation = Quaternion.identity;
}
}
#endregion
#endregion
#region API
public void PointTo(GameObject obj) {
Quaternion currentRotation = this.transform.rotation;
Vector3 lookDirection = this.transform.InverseTransformPoint(obj.transform.position);
Quaternion lookRotation = Quaternion.LookRotation(lookDirection, this.transform.up);
Quaternion rotation = Quaternion.Inverse(currentRotation) * lookRotation;
Rigidbody rigidbody = GetComponentInParent<Rigidbody>();
if (rigidbody != null)
rigidbody.transform.rotation *= rotation;
else
this.transform.rotation *= rotation;
}
public void SetDirection(Vector3 lookDirection) {
Quaternion currentRotation = this.transform.rotation;
Quaternion lookRotation = Quaternion.LookRotation(lookDirection, this.transform.up);
Quaternion rotation = Quaternion.Inverse(currentRotation) * lookRotation;
Rigidbody rigidbody = GetComponentInParent<Rigidbody>();
if (rigidbody != null)
rigidbody.transform.rotation *= rotation;
else
this.transform.rotation *= rotation;
}
public void LaunchRigidbody(Rigidbody rigidbody) {
// Only gravity rays are supported
if (rayType != RayType.Gravity)
return;
rigidbody.velocity = transform.forward * speed;
}
public void LaunchPrefab(GameObject prefab) {
GameObject gameObject = Instantiate(prefab, transform.position, transform.rotation);
Rigidbody rigidbody = gameObject.GetComponent<Rigidbody>();
if (rigidbody == null)
rigidbody = gameObject.AddComponent<Rigidbody>();
LaunchRigidbody(rigidbody);
}
/// <summary>
/// Spawns a prefab as a child of the objectInFocus
/// </summary>
/// <param name="prefab">The prefab to spawn</param>
/// The spawn position and rotation will match the focusPoint transform.
/// When the objectInFocus is null, the prefab will be spawned as a root transform.
public void SpawnOnObjectInFocus(GameObject prefab) {
GameObject spawnedObject = Spawner.Spawn(prefab, focusPointObj.transform.position, focusPointObj.transform.rotation);
if (objectInFocus != null)
spawnedObject.transform.SetParent(objectInFocus.transform, true);
}
public void ApplyForce(float magnitude) {
if (objectInFocus == null)
return;
Rigidbody objRigidbody = objectInFocus.GetComponent<Rigidbody>();
if (objRigidbody == null)
return;
// needs to use hitDirection in the future
Vector3 direction = Vector3.Normalize(focusPointObj.transform.position - transform.position);
objRigidbody.AddForceAtPosition(direction * magnitude, focusPointObj.transform.position);
}
#endregion API
#region Events
#region Focus
/// <summary>Event based on the current focus.</summary>
/// This event is generated from the objectInFocus.
/// It has the objectInFocus as parameter. It can be used to execute functions when the focus changes between objects.
public GameObjectEventHandlers focusEvent = new GameObjectEventHandlers() {
label = "Focus Event",
tooltip =
"Call functions using the current focus\n" +
"Parameter: the Object in Focus"
};
protected GameObject previousObjectInFocus;
protected virtual void UpdateFocus() {
focusEvent.value = objectInFocus;
if (objectInFocus != previousObjectInFocus) {
DebugLog("Focus Change " + objectInFocus);
InteractionEventHandler eventHandler;
if (previousObjectInFocus != null) {
eventHandler = previousObjectInFocus.GetComponent<InteractionEventHandler>();
if (eventHandler != null) {
eventHandler.focusHandlers.value = false;
eventHandler.clickHandlers.value = false;
}
}
if (objectInFocus != null) {
eventHandler = objectInFocus.GetComponent<InteractionEventHandler>();
if (eventHandler != null)
eventHandler.focusHandlers.value = true;
}
PointerEventData data = interactionModule.pointers[interactionID].data;
if (previousObjectInFocus != null) {
ExecuteEvents.ExecuteHierarchy(previousObjectInFocus, data, ExecuteEvents.pointerExitHandler);
ExecuteEvents.ExecuteHierarchy(previousObjectInFocus, data, ExecuteEvents.deselectHandler);
}
ExecuteEvents.ExecuteHierarchy(objectInFocus, data, ExecuteEvents.pointerEnterHandler);
ExecuteEvents.ExecuteHierarchy(objectInFocus, data, ExecuteEvents.selectHandler);
previousObjectInFocus = objectInFocus;
}
}
#endregion
#region FocusPoint
/// <summary>Event based on the current focus.</summary>
/// This event is generated from the objectInFocus.
/// It has the objectInFocus as parameter. It can be used to execute functions when the focus changes between objects.
public Vector3EventList focusPointEvent = new Vector3EventList() {
label = "Focus Point Event",
tooltip =
"Call functions using the current focus point\n" +
"Parameter: the position of the focus point"
};
protected void UpdateFocusPoint() {
focusPointEvent.value = focusPointObj.transform.position;
}
#endregion
#region Click
/// <summary>Event based on the clicking status</summary>
/// This event is generated from the clicking boolean.
/// It has the objectInFocus as parameter. It can be used to exectue functions when the user has clicked on an object.
public GameObjectEventHandlers clickEvent = new GameObjectEventHandlers() {
label = "Click Event",
tooltip =
"Call functions using the clicking status\n" +
"Parameter: the Object in Focus when clicking"
};
/// <summary>Click on the objectInFocus</summary>
/// This function will do a full click: a button down followed by a button up.
public void FullClick() {
Click(true);
hasClicked = true;
Click(false);
}
/// <summary>Change the click status on the objectInFocus</summary>
/// <param name="clicking">Indicates if the button is down</param>
public virtual void Click(bool clicking = true) {
if (!this.enabled || !this.gameObject.activeInHierarchy)
return;
if (clicking)
clickEvent.value = objectInFocus;
else
clickEvent.value = null;
if (objectInFocus != null) {
PointerEventData data = interactionModule.pointers[interactionID].data;
RaycastResult raycastResult = new RaycastResult() {
worldPosition = focusPointObj.transform.position,
worldNormal = focusPointObj.transform.forward,
distance = (focusPointObj.transform.position - this.transform.position).magnitude,
gameObject = focusPointObj
};
data.pointerCurrentRaycast = raycastResult;
if (clicking) {
ExecuteEvents.ExecuteHierarchy(objectInFocus, data, ExecuteEvents.pointerDownHandler);
}
else {
ExecuteEvents.ExecuteHierarchy(objectInFocus, data, ExecuteEvents.pointerUpHandler);
ExecuteEvents.ExecuteHierarchy(objectInFocus, data, ExecuteEvents.pointerClickHandler);
}
InteractionEventHandler eventHandler = objectInFocus.GetComponent<InteractionEventHandler>();
if (eventHandler != null) {
eventHandler.clickHandlers.value = clicking;
} else {
TeleportTarget teleportTarget = objectInFocus.GetComponentInParent<TeleportTarget>();
if (teleportTarget != null) {
Humanoid.HumanoidControl humanoid = GetComponentInParent<Humanoid.HumanoidControl>();
if (humanoid != null)
teleportTarget.TeleportToHere(humanoid);
else
teleportTarget.TeleportToHere(this.transform);
}
}
}
}
#endregion
#region Active
/// <summary>Event based on the active status</summary>
/// This event is genereated from the active boolean
/// Is has the active boolean as parameter. It can be used to execute functions when the interaction pointer is activated.
public BoolEvent activeEvent = new BoolEvent();
/// <summary>Change the active status of the InteractionPointer</summary>
/// <param name="_active">Indicates if the InteractionPointer is active</param>
public virtual void Activation(bool _active) {
active = _active;
activeEvent.value = _active;
}
#endregion
public virtual void ActivateClick(bool _active) {
if (active && !_active) {
Click();
Activation(false);
}
else if (!active && _active) {
Activation(true);
}
}
#endregion
#region Gizmos
protected virtual void OnDrawGizmosSelected() {
if (rayType == RayType.SphereCast) {
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(transform.position, radius);
Gizmos.DrawRay(transform.position + transform.up * radius, transform.forward * maxDistance);
Gizmos.DrawRay(transform.position - transform.up * radius, transform.forward * maxDistance);
Gizmos.DrawRay(transform.position + transform.right * radius, transform.forward * maxDistance);
Gizmos.DrawRay(transform.position - transform.right * radius, transform.forward * maxDistance);
Gizmos.DrawWireSphere(transform.position + transform.forward * maxDistance, radius);
}
}
#endregion
}
}