BellyMenu.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. /// <summary>
  5. /// Keeps its position at the same as a given transform, and it's Y rotation too, both with deadzones.
  6. /// Movements aren't instant, to avoid motion sickness and add realism.
  7. /// Used to make the 'belly menu' near the user in the MR calibration scene, which is enabled if they
  8. /// only have one controller available (because the other is used to anchor the ZED).
  9. /// </summary>
  10. [RequireComponent(typeof(Rigidbody))]
  11. public class BellyMenu : MonoBehaviour
  12. {
  13. /// <summary>
  14. /// Transform that this object will follow. Should be set to the main VR camera.
  15. /// </summary>
  16. [Tooltip("Transform that this object will follow. Should be set to the main VR camera. ")]
  17. public Transform followTransform;
  18. /// <summary>
  19. /// How far the follow transform has to be before this transform starts moving toward it.
  20. /// </summary>
  21. [Tooltip("How far the follow transform has to be before this transform starts moving toward it.")]
  22. public float moveDeadzoneMeters = 0.2f;
  23. /// <summary>
  24. /// How much of an angle the follow transform has to be before this transform starts rotating toward it.
  25. /// </summary>
  26. [Tooltip("How much of an angle the follow transform has to be before this transform starts rotating toward it.")]
  27. public float turnDeadzoneDegrees = 40f;
  28. /// <summary>
  29. /// Maximum force used to translate this object, when using physics.
  30. /// </summary>
  31. [Tooltip("Maximum force used to translate this object, when using physics. ")]
  32. public float maxMoveForce = 0.3f;
  33. /// <summary>
  34. /// The fastest this transform will rotate to keep up with the follow transform.
  35. /// </summary>
  36. [Tooltip("The fastest this transform will rotate to keep up with the follow transform. ")]
  37. public float maxDegreesPerSecond = 60f;
  38. /// <summary>
  39. /// If true, translates gradually to keep up with the follow transform. Otherwise, movement is instant.
  40. /// </summary>
  41. [Tooltip("If true, translates gradually to keep up with the follow transform. Otherwise, movement is instant. ")]
  42. public bool gradualMove = false;
  43. /// <summary>
  44. /// If true, rotates gradually to keep up with the follow transform. Otherwise, rotation is instant.
  45. /// </summary>
  46. [Tooltip("If true, rotates gradually to keep up with the follow transform. Otherwise, rotation is instant. ")]
  47. public bool gradualTurn = true;
  48. /// <summary>
  49. /// What multiple of the HMD's height should the object move toward. For instance, 0.5 will go to 100cm on a 200cm person.
  50. /// This is designed for following a Camera for a person in a VR headset.
  51. /// </summary>
  52. [Tooltip("What multiple of the HMD's height should the object move toward. For instance, 0.5 will go to 100cm on a 200cm person. " +
  53. "This is designed for following a Camera for a person in a VR headset.")]
  54. public float waistHeightMultiple = 0.65f;
  55. private Rigidbody _rb;
  56. // Use this for initialization
  57. void Awake ()
  58. {
  59. _rb = GetComponent<Rigidbody>();
  60. _rb.useGravity = false;
  61. if(!followTransform)
  62. {
  63. followTransform = Camera.main.transform;
  64. }
  65. }
  66. // Update is called once per frame
  67. void FixedUpdate ()
  68. {
  69. //First, position.
  70. if (gradualMove)
  71. {
  72. Vector3 targetarea = followTransform.position;
  73. targetarea.y = followTransform.position.y * waistHeightMultiple; //So it'll be around their waste.
  74. Vector3 posdiff = targetarea - transform.position;
  75. if (posdiff.magnitude > moveDeadzoneMeters) //Too far away.
  76. {
  77. _rb.AddForce(posdiff.normalized * maxMoveForce);
  78. }
  79. else if (posdiff.magnitude < moveDeadzoneMeters / 2f) //Too close. Slow down extra fast.
  80. {
  81. _rb.velocity *= 0.9f;
  82. if (_rb.velocity.magnitude < 0.05f) _rb.velocity = Vector3.zero;
  83. }
  84. }
  85. else //Not gradual move.
  86. {
  87. Vector3 targetarea = followTransform.position;
  88. targetarea.y = followTransform.position.y * waistHeightMultiple; //So it'll be around their waste.
  89. transform.position = targetarea;
  90. }
  91. //Now rotation.
  92. if (gradualTurn)
  93. {
  94. Vector3 thisforward = transform.forward;
  95. thisforward.y = 0f;
  96. Vector3 followforward = followTransform.forward;
  97. followforward.y = 0f;
  98. float angle = Vector3.SignedAngle(thisforward, followforward, Vector3.up);
  99. if (Mathf.Abs(angle) > turnDeadzoneDegrees / 2f)
  100. {
  101. float speed = Mathf.InverseLerp(turnDeadzoneDegrees / 2f, turnDeadzoneDegrees, Mathf.Abs(angle));
  102. Vector3 newforward = Vector3.RotateTowards(thisforward, followforward, maxDegreesPerSecond * speed * Time.fixedDeltaTime * Mathf.Deg2Rad, 0f);
  103. transform.rotation = Quaternion.LookRotation(newforward, Vector3.up);
  104. }
  105. }
  106. else
  107. {
  108. //Vector3 targetrot = new Vector3(0, followTransform.eulerAngles.y, 0);
  109. transform.eulerAngles = new Vector3(0, followTransform.eulerAngles.y, 0);
  110. }
  111. }
  112. }