BallTeleport.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //***********************************************************
  2. // Filename: BallTeleport.cs
  3. // Author: Moritz Kolvenbach, Marco Fendrich
  4. // Last changes: Thursday, 9th of August 2018
  5. // Content: Teleportation with a thrown ball
  6. //***********************************************************
  7. using System.Collections.Generic;
  8. using UnityEngine;
  9. /// <summary>
  10. /// Ball teleport by throwing an instantiated object from the player's hand
  11. /// </summary>
  12. public class BallTeleport : MonoBehaviour, IButton
  13. {
  14. // general reference classes for access
  15. private GameObject gameManager;
  16. private Visualiser renderScript;
  17. private Teleport teleportScript;
  18. private ViveNavMesh navMesh;
  19. // list of points within parabola or line being shown to player as indicator for his teleportation
  20. protected List<Vector3> projectionPoints;
  21. // distance in meters between the single points of the optical representation
  22. protected float pointSpacing;
  23. // maximum number of points being calculated until parabola is being stopped
  24. protected int pointCount;
  25. // prefab to be thrown
  26. public GameObject ballPrefab;
  27. // instantiated object while throwing
  28. private GameObject ballObject;
  29. // current state of teleportation
  30. private BallState ballState;
  31. // additional information needed for calculations; details below
  32. private Vector3 lastPosition;
  33. private bool isBallAboveMesh;
  34. private Vector3 teleportDestination;
  35. private Vector3 normalVector;
  36. // reference to controller
  37. private SteamVR_Controller.Device controller;
  38. // for rendering only
  39. protected Vector3 normalisedVelocity = Vector3.down;
  40. protected Vector3 normalisedHitPoint = Vector3.up;
  41. void Start()
  42. {
  43. // get references for variables declared above
  44. gameManager = GameObject.FindWithTag("GameController");
  45. teleportScript = (Teleport)gameManager.GetComponent(typeof(Teleport));
  46. renderScript = (Visualiser)gameManager.GetComponent(typeof(Visualiser));
  47. navMesh = (ViveNavMesh)gameManager.GetComponent(typeof(ViveNavMesh));
  48. projectionPoints = new List<Vector3>(pointCount);
  49. pointSpacing = renderScript.PointSpacing;
  50. pointCount = renderScript.PointCount;
  51. }
  52. void Update()
  53. {
  54. // only running when ball is currently being thrown
  55. if (ballState != BallState.THROWING) return;
  56. // calculate a line downwards as preparation to show the current teleport target position
  57. UpdateProjectionPoints();
  58. // display the calculated points
  59. renderScript.updateRendering(isBallAboveMesh, projectionPoints, normalisedHitPoint, Vector3.down * 10.0F);
  60. }
  61. /// <summary>
  62. /// Function being called on press by player; checks the state the teleportation is in and either creates a new ball or
  63. /// destroys the old one. Teleports if the ball was above a valid destination
  64. /// </summary>
  65. /// <param name="controllerObject">gameObject of controller</param>
  66. /// <param name="controllerIdentificator">ID of controller currently using this function</param>
  67. public void OnButtonDown(GameObject controllerObject, int controllerIdentificator)
  68. {
  69. // if no ball is instantiated, create new one
  70. if (ballState == BallState.NONE)
  71. {
  72. // create ball at controller position
  73. controller = SteamVR_Controller.Input(controllerIdentificator);
  74. ballObject = Instantiate(ballPrefab, controllerObject.transform.position, controllerObject.transform.rotation);
  75. // set the ball to stay static at front of controller
  76. ballObject.GetComponent<Rigidbody>().isKinematic = true;
  77. ballObject.transform.SetParent(controllerObject.transform);
  78. // set ballstate to a ball being held
  79. ballState = BallState.HELD;
  80. }
  81. // if a ball is currently instantied and was thrown, destroy it and teleport if the position was valid
  82. else if (ballState == BallState.THROWING)
  83. {
  84. // check whether the ball was above a valid destination
  85. navMesh.Linecast(ballObject.transform.position, new Vector3(ballObject.transform.position.x, ballObject.transform.position.y - 5.0f, ballObject.transform.position.z), out isBallAboveMesh, out teleportDestination, out normalVector);
  86. // if so, teleport there
  87. if (isBallAboveMesh)
  88. {
  89. teleportScript.CallTeleport(teleportDestination);
  90. }
  91. // if not, give haptic feedback that input was registered as no other feedback would be given
  92. else
  93. {
  94. // vibrate controller
  95. }
  96. // destroy ball, stop rendering, reset ball state
  97. Destroy(ballObject);
  98. ballState = BallState.NONE;
  99. renderScript.enabled = false;
  100. }
  101. }
  102. /// <summary>
  103. /// Function being called on release of button by player; releases ball if one is currently being held
  104. /// </summary>
  105. public void OnButtonUp()
  106. {
  107. // check if an instantiated ball is being held
  108. if (ballState != BallState.HELD) return;
  109. // if so, decouple from controller
  110. ballObject.GetComponent<Rigidbody>().isKinematic = false;
  111. ballObject.transform.SetParent(null);
  112. // give the ball the controller's speed increased by factor
  113. ballObject.GetComponent<Rigidbody>().velocity = controller.velocity * 2.0F;
  114. // set ball state to throwing and start rendering position being targeted
  115. ballState = BallState.THROWING;
  116. renderScript.enabled = true;
  117. }
  118. /// <summary>
  119. /// Sample a bunch of points along a line until you hit gnd. At that point, cut off the parabola
  120. /// Entire calculation is analogue to <see class = "ParabolicTeleport"></see> except with downward velocity
  121. /// </summary>
  122. private void UpdateProjectionPoints()
  123. {
  124. // turn velocity to work straight down
  125. normalisedVelocity = transform.TransformDirection(Vector3.down);
  126. projectionPoints.Clear();
  127. projectionPoints.Add(ballObject.transform.position);
  128. Vector3 last = ballObject.transform.position;
  129. for (int i = 0; i < pointCount; i++)
  130. {
  131. Vector3 next = new Vector3(last.x, last.y - pointSpacing, last.z);
  132. Vector3 castHit;
  133. Vector3 norm;
  134. bool endOnNavmesh;
  135. if (navMesh.Linecast(last, next, out endOnNavmesh, out castHit, out norm))
  136. {
  137. projectionPoints.Add(castHit);
  138. normalisedHitPoint = norm;
  139. isBallAboveMesh = endOnNavmesh;
  140. return;
  141. }
  142. else
  143. {
  144. projectionPoints.Add(next);
  145. }
  146. last = next;
  147. }
  148. normalisedHitPoint = Vector3.up;
  149. isBallAboveMesh = false;
  150. }
  151. }
  152. /// <summary>
  153. /// Represents the player's current use of the ball teleport machanic.
  154. /// </summary>
  155. public enum BallState
  156. {
  157. // The player is not using teleportation right now
  158. NONE,
  159. // The player is holding an instance of the ball prefab
  160. HELD,
  161. // The ball is currently flying and therefore "selecting" a destination
  162. THROWING
  163. }