182 lines
5.6 KiB
C#
182 lines
5.6 KiB
C#
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
using UnityEngine;
|
|
|
|
namespace Microsoft.MixedReality.Toolkit.Input
|
|
{
|
|
/// <summary>
|
|
/// A cursor that looks and acts more like the shell cursor.
|
|
/// A two part cursor with visual feedback for all cursor states
|
|
/// </summary>
|
|
[AddComponentMenu("Scripts/MRTK/SDK/InteractiveMeshCursor")]
|
|
public class InteractiveMeshCursor : BaseCursor
|
|
{
|
|
[SerializeField]
|
|
[Tooltip("The ring or outer element")]
|
|
private GameObject ring = null;
|
|
|
|
[SerializeField]
|
|
[Tooltip("Inner cursor element")]
|
|
private GameObject dot = null;
|
|
|
|
[SerializeField]
|
|
[Tooltip("The scale factor to soften the distance scaling, we want the cursor to scale in the distance, but not disappear.")]
|
|
private float distanceScaleFactor = 0.3f;
|
|
|
|
[SerializeField]
|
|
[Tooltip("The scale both elements will be at their default state")]
|
|
private float defaultScale = 0.75f;
|
|
|
|
[SerializeField]
|
|
[Tooltip("The scale both elements will when pressed")]
|
|
private float downScale = 0.5f;
|
|
|
|
[SerializeField]
|
|
[Tooltip("The scale both elements will a hand is visible")]
|
|
private float upScale = 1;
|
|
|
|
[SerializeField]
|
|
[Tooltip("Time to scale between states")]
|
|
private float scaleTime = 0.5f;
|
|
|
|
/// <summary>
|
|
/// internal state and element management
|
|
/// </summary>
|
|
private float timer = 0;
|
|
|
|
private bool isVisible = true;
|
|
private bool hasHover = false;
|
|
private bool hasHand = false;
|
|
private bool isDown = false;
|
|
|
|
private float ringDotTargetScale;
|
|
private Vector3 initialScale;
|
|
|
|
private void Awake()
|
|
{
|
|
initialScale = transform.localScale;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decide which element (ring or dot) should be visible and at what scale
|
|
/// </summary>
|
|
public override void OnCursorStateChange(CursorStateEnum state)
|
|
{
|
|
base.OnCursorStateChange(state);
|
|
|
|
// the cursor state has changed, reset the animation timer
|
|
if (hasHand != IsSourceDetected || isDown != IsPointerDown || hasHover != (TargetedObject != null))
|
|
{
|
|
timer = 0;
|
|
}
|
|
|
|
hasHand = IsSourceDetected;
|
|
isDown = IsPointerDown;
|
|
hasHover = TargetedObject != null;
|
|
|
|
ringDotTargetScale = defaultScale;
|
|
bool showRing = false;
|
|
|
|
switch (state)
|
|
{
|
|
case CursorStateEnum.None:
|
|
break;
|
|
case CursorStateEnum.Observe:
|
|
break;
|
|
case CursorStateEnum.ObserveHover:
|
|
showRing = true;
|
|
break;
|
|
case CursorStateEnum.Interact:
|
|
showRing = true;
|
|
ringDotTargetScale = downScale;
|
|
break;
|
|
case CursorStateEnum.InteractHover:
|
|
showRing = true;
|
|
ringDotTargetScale = upScale;
|
|
break;
|
|
case CursorStateEnum.Select:
|
|
ringDotTargetScale = upScale;
|
|
break;
|
|
case CursorStateEnum.Release:
|
|
break;
|
|
case CursorStateEnum.Contextual:
|
|
break;
|
|
}
|
|
|
|
if (!isVisible)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ring.SetActive(showRing);
|
|
dot.SetActive(!showRing);
|
|
|
|
// added observation of CursorModifier
|
|
if (Pointer.CursorModifier != null && hasHover)
|
|
{
|
|
ElementVisibility(!Pointer.CursorModifier.GetCursorVisibility());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// scale the cursor elements
|
|
/// </summary>
|
|
protected override void UpdateCursorTransform()
|
|
{
|
|
base.UpdateCursorTransform();
|
|
|
|
// animate scale of ring and dot
|
|
if (timer < scaleTime)
|
|
{
|
|
timer += Time.deltaTime;
|
|
if (timer > scaleTime)
|
|
{
|
|
timer = scaleTime;
|
|
}
|
|
|
|
Vector3 useScale = Vector3.one * Mathf.Lerp(defaultScale, ringDotTargetScale, timer / scaleTime);
|
|
ring.transform.localScale = useScale;
|
|
dot.transform.localScale = useScale;
|
|
}
|
|
|
|
// handle scale of main cursor go
|
|
float distance = Vector3.Distance(CoreServices.InputSystem.GazeProvider.GazeOrigin, transform.position);
|
|
float smoothScaling = 1 - DefaultCursorDistance * distanceScaleFactor;
|
|
transform.localScale = initialScale * (distance * distanceScaleFactor + smoothScaling);
|
|
}
|
|
|
|
/// <summary>
|
|
/// override the base class for custom visibility
|
|
/// </summary>
|
|
public override void SetVisibility(bool visible)
|
|
{
|
|
base.SetVisibility(visible);
|
|
|
|
isVisible = visible;
|
|
ElementVisibility(visible);
|
|
|
|
if (visible)
|
|
{
|
|
OnCursorStateChange(CursorState);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// controls the visibility of cursor elements in one place
|
|
/// </summary>
|
|
private void ElementVisibility(bool visible)
|
|
{
|
|
if (ring != null)
|
|
{
|
|
ring.SetActive(visible);
|
|
}
|
|
|
|
if (dot != null)
|
|
{
|
|
dot.SetActive(visible);
|
|
}
|
|
}
|
|
}
|
|
}
|