Assignment for RMIT Mixed Reality in 2020
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.

191 lines
6.3 KiB

  1. /************************************************************************************
  2. Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
  3. See SampleFramework license.txt for license terms. Unless required by applicable law
  4. or agreed to in writing, the sample code is provided AS IS WITHOUT WARRANTIES OR
  5. CONDITIONS OF ANY KIND, either express or implied. See the license for specific
  6. language governing permissions and limitations under the license.
  7. ************************************************************************************/
  8. using System.Collections;
  9. using UnityEngine;
  10. using UnityEngine.Assertions;
  11. namespace OculusSampleFramework
  12. {
  13. /// <summary>
  14. /// An example visual controller for a button intended for the train sample scene.
  15. /// </summary>
  16. public class TrainButtonVisualController : MonoBehaviour
  17. {
  18. private const float LERP_TO_OLD_POS_DURATION = 1.0f;
  19. private const float LOCAL_SIZE_HALVED = 0.5f;
  20. [SerializeField] private MeshRenderer _meshRenderer = null;
  21. [SerializeField] private MeshRenderer _glowRenderer = null;
  22. [SerializeField] private ButtonController _buttonController = null;
  23. [SerializeField] private Color _buttonContactColor = new Color(0.51f, 0.78f, 0.92f, 1.0f);
  24. [SerializeField] private Color _buttonActionColor = new Color(0.24f, 0.72f, 0.98f, 1.0f);
  25. [SerializeField] private AudioSource _audioSource = null;
  26. [SerializeField] private AudioClip _actionSoundEffect = null;
  27. [SerializeField] private Transform _buttonContactTransform = null;
  28. [SerializeField] private float _contactMaxDisplacementDistance = 0.0141f;
  29. private Material _buttonMaterial;
  30. private Color _buttonDefaultColor;
  31. private int _materialColorId;
  32. private bool _buttonInContactOrActionStates = false;
  33. private Coroutine _lerpToOldPositionCr = null;
  34. private Vector3 _oldPosition;
  35. private void Awake()
  36. {
  37. Assert.IsNotNull(_meshRenderer);
  38. Assert.IsNotNull(_glowRenderer);
  39. Assert.IsNotNull(_buttonController);
  40. Assert.IsNotNull(_audioSource);
  41. Assert.IsNotNull(_actionSoundEffect);
  42. Assert.IsNotNull(_buttonContactTransform);
  43. _materialColorId = Shader.PropertyToID("_Color");
  44. _buttonMaterial = _meshRenderer.material;
  45. _buttonDefaultColor = _buttonMaterial.GetColor(_materialColorId);
  46. _oldPosition = transform.localPosition;
  47. }
  48. private void OnDestroy()
  49. {
  50. if (_buttonMaterial != null)
  51. {
  52. Destroy(_buttonMaterial);
  53. }
  54. }
  55. private void OnEnable()
  56. {
  57. _buttonController.InteractableStateChanged.AddListener(InteractableStateChanged);
  58. _buttonController.ContactZoneEvent += ActionOrInContactZoneStayEvent;
  59. _buttonController.ActionZoneEvent += ActionOrInContactZoneStayEvent;
  60. _buttonInContactOrActionStates = false;
  61. }
  62. private void OnDisable()
  63. {
  64. if (_buttonController != null)
  65. {
  66. _buttonController.InteractableStateChanged.RemoveListener(InteractableStateChanged);
  67. _buttonController.ContactZoneEvent -= ActionOrInContactZoneStayEvent;
  68. _buttonController.ActionZoneEvent -= ActionOrInContactZoneStayEvent;
  69. }
  70. }
  71. private void ActionOrInContactZoneStayEvent(ColliderZoneArgs collisionArgs)
  72. {
  73. if (!_buttonInContactOrActionStates || collisionArgs.CollidingTool.IsFarFieldTool)
  74. {
  75. return;
  76. }
  77. // calculate how much the button should be pushed inwards. based on contact zone.
  78. // assume collider is uniform 1x1x1 cube, and all scaling, etc is done on transform component
  79. // another way to test distances is to measure distance to plane that represents where
  80. // button translation must stop
  81. Vector3 buttonScale = _buttonContactTransform.localScale;
  82. Vector3 interactionPosition = collisionArgs.CollidingTool.InteractionPosition;
  83. Vector3 localSpacePosition = _buttonContactTransform.InverseTransformPoint(
  84. interactionPosition);
  85. // calculate offset in local space. so bias coordinates from 0.5,-0.5 to 0, -1.
  86. // 0 is no offset, 1.0 in local space is max offset pushing inwards
  87. Vector3 offsetVector = localSpacePosition - LOCAL_SIZE_HALVED * Vector3.one;
  88. // affect offset by button scale. only care about y (since y goes inwards)
  89. float scaledLocalSpaceOffset = offsetVector.y * buttonScale.y;
  90. // restrict button movement. can only go so far in negative direction, and cannot
  91. // be positive (which would cause the button to "stick out")
  92. if (scaledLocalSpaceOffset > -_contactMaxDisplacementDistance && scaledLocalSpaceOffset
  93. <= 0.0f)
  94. {
  95. transform.localPosition = new Vector3(_oldPosition.x, _oldPosition.y +
  96. scaledLocalSpaceOffset, _oldPosition.z);
  97. }
  98. }
  99. private void InteractableStateChanged(InteractableStateArgs obj)
  100. {
  101. _buttonInContactOrActionStates = false;
  102. _glowRenderer.gameObject.SetActive(obj.NewInteractableState >
  103. InteractableState.Default);
  104. switch (obj.NewInteractableState)
  105. {
  106. case InteractableState.ContactState:
  107. StopResetLerping();
  108. _buttonMaterial.SetColor(_materialColorId, _buttonContactColor);
  109. _buttonInContactOrActionStates = true;
  110. break;
  111. case InteractableState.ProximityState:
  112. _buttonMaterial.SetColor(_materialColorId, _buttonDefaultColor);
  113. LerpToOldPosition();
  114. break;
  115. case InteractableState.ActionState:
  116. StopResetLerping();
  117. _buttonMaterial.SetColor(_materialColorId, _buttonActionColor);
  118. PlaySound(_actionSoundEffect);
  119. _buttonInContactOrActionStates = true;
  120. break;
  121. default:
  122. _buttonMaterial.SetColor(_materialColorId, _buttonDefaultColor);
  123. LerpToOldPosition();
  124. break;
  125. }
  126. }
  127. private void PlaySound(AudioClip clip)
  128. {
  129. _audioSource.timeSamples = 0;
  130. _audioSource.clip = clip;
  131. _audioSource.Play();
  132. }
  133. private void StopResetLerping()
  134. {
  135. if (_lerpToOldPositionCr != null)
  136. {
  137. StopCoroutine(_lerpToOldPositionCr);
  138. }
  139. }
  140. private void LerpToOldPosition()
  141. {
  142. if ((transform.localPosition - _oldPosition).sqrMagnitude < Mathf.Epsilon)
  143. {
  144. return;
  145. }
  146. StopResetLerping();
  147. _lerpToOldPositionCr = StartCoroutine(ResetPosition());
  148. }
  149. private IEnumerator ResetPosition()
  150. {
  151. var startTime = Time.time;
  152. var endTime = Time.time + LERP_TO_OLD_POS_DURATION;
  153. while (Time.time < endTime)
  154. {
  155. transform.localPosition = Vector3.Lerp(transform.localPosition, _oldPosition,
  156. (Time.time - startTime) / LERP_TO_OLD_POS_DURATION);
  157. yield return null;
  158. }
  159. transform.localPosition = _oldPosition;
  160. _lerpToOldPositionCr = null;
  161. }
  162. }
  163. }