Visualiser.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. //***********************************************************
  2. // Filename: Visualiser.cs
  3. // Author: Marco Fendrich, Moritz Kolvenbach
  4. // Last changes: Thursday, 9th of August 2018
  5. // Content: A class to render the visual representation of the different teleportConditions
  6. //***********************************************************
  7. using System.Collections;
  8. using System.Collections.Generic;
  9. using UnityEngine;
  10. /// <summary>
  11. /// Handles the rendering of the visual feedback for the different teleportMethods
  12. /// </summary>
  13. public class Visualiser : MonoBehaviour {
  14. [Header("Parabola Mesh Properties")]
  15. [Tooltip("Number of points on the parabola mesh. Greater point counts lead to a higher poly/smoother mesh.")]
  16. public int PointCount = 50;
  17. [Tooltip("Approximate spacing between each of the points on the parabola mesh.")]
  18. public float PointSpacing = 0.5f;
  19. [Tooltip("Thickness of the parabola mesh")]
  20. public float GraphicThickness = 0.05f;
  21. [Tooltip("Material to use to render the parabola mesh")]
  22. public Material GraphicMaterial;
  23. [Header("Selection Pad Properties")]
  24. [SerializeField]
  25. [Tooltip("Prefab to use as the selection pad when the player is pointing at a valid teleportable surface.")]
  26. private GameObject SelectionPadPrefab;
  27. [SerializeField]
  28. [Tooltip("Prefab to use as the selection pad when the player is pointing at an invalid teleportable surface.")]
  29. private GameObject InvalidPadPrefab;
  30. [SerializeField]
  31. [Tooltip("Prefab to use as the selection pad when using the turn teleport.")]
  32. private GameObject RotationPadPrefab;
  33. // The final point, where the player gets teleported to
  34. private Vector3 SelectedPoint;
  35. // The mesh used to check for collisions and validate whether the targetPoint is acutually teleportable
  36. private Mesh ParabolaMesh;
  37. private float rotation = float.NegativeInfinity;
  38. // Prefabs for the different kinds of goal markers
  39. private GameObject SelectionPadObject;
  40. private GameObject InvalidPadObject;
  41. private GameObject RotationPadObject;
  42. // Update values based on the information from the different teleportConditions
  43. public void updateRendering(bool PointOnNavMesh, List<Vector3> ParabolaPoints, Vector3 normal, Vector3 velocity, float rotation)
  44. {
  45. this.PointOnNavMesh = PointOnNavMesh;
  46. this.ParabolaPoints = ParabolaPoints;
  47. this.normal = normal;
  48. this.velocity = velocity;
  49. this.rotation = rotation;
  50. }
  51. public void updateRendering(bool PointOnNavMesh, List<Vector3> ParabolaPoints, Vector3 normal, Vector3 velocity)
  52. {
  53. this.PointOnNavMesh = PointOnNavMesh;
  54. this.ParabolaPoints = ParabolaPoints;
  55. this.normal = normal;
  56. this.velocity = velocity;
  57. }
  58. // True if the final point of parabolaPoints is at a teleportable location
  59. bool PointOnNavMesh;
  60. // Normal of selectedPoint
  61. Vector3 normal;
  62. Vector3 velocity;
  63. private List<Vector3> ParabolaPoints;
  64. void Update () {
  65. SelectedPoint = ParabolaPoints[ParabolaPoints.Count - 1];
  66. // check which marker to render for each frame
  67. if (SelectionPadObject != null && rotation == float.NegativeInfinity)
  68. {
  69. SelectionPadObject.SetActive(PointOnNavMesh);
  70. SelectionPadObject.transform.position = SelectedPoint + Vector3.one * 0.005f;
  71. if (PointOnNavMesh)
  72. {
  73. SelectionPadObject.transform.rotation = Quaternion.LookRotation(normal);
  74. SelectionPadObject.transform.Rotate(90, 0, 0);
  75. }
  76. }
  77. else if (RotationPadObject != null)
  78. {
  79. RotationPadObject.SetActive(PointOnNavMesh);
  80. RotationPadObject.transform.position = SelectedPoint + Vector3.one * 0.005f;
  81. if (PointOnNavMesh)
  82. {
  83. RotationPadObject.transform.rotation = Quaternion.LookRotation(normal);
  84. RotationPadObject.transform.Rotate(90, 0, 0);
  85. // rotate selection pad
  86. Vector2 parabolicVector = new Vector2(velocity.x, velocity.z);
  87. RotationPadObject.transform.Rotate(0, Vector2.SignedAngle(parabolicVector, Vector2.up) - 90.0F, 0);
  88. RotationPadObject.transform.Rotate(0, rotation, 0);
  89. }
  90. }
  91. if (InvalidPadObject != null)
  92. {
  93. InvalidPadObject.SetActive(!PointOnNavMesh);
  94. InvalidPadObject.transform.position = SelectedPoint + Vector3.one * 0.005f;
  95. if (!PointOnNavMesh)
  96. {
  97. InvalidPadObject.transform.rotation = Quaternion.LookRotation(normal);
  98. InvalidPadObject.transform.Rotate(90, 0, 0);
  99. }
  100. }
  101. // Draw parabola (BEFORE the outside faces of the selection pad, to avoid depth issues)
  102. GenerateMesh(ref ParabolaMesh, ParabolaPoints, velocity, Time.time % 1);
  103. Graphics.DrawMesh(ParabolaMesh, Matrix4x4.identity, GraphicMaterial, gameObject.layer);
  104. }
  105. void Start()
  106. {
  107. // populate initial mesh
  108. ParabolaMesh = new Mesh();
  109. ParabolaMesh.MarkDynamic();
  110. ParabolaMesh.name = "Parabolic Pointer";
  111. ParabolaMesh.vertices = new Vector3[0];
  112. ParabolaMesh.triangles = new int[0];
  113. // instantiate target marker prefabs
  114. if (SelectionPadPrefab != null)
  115. {
  116. SelectionPadObject = Instantiate<GameObject>(SelectionPadPrefab);
  117. SelectionPadObject.SetActive(false);
  118. }
  119. if (InvalidPadPrefab != null)
  120. {
  121. InvalidPadObject = Instantiate<GameObject>(InvalidPadPrefab);
  122. InvalidPadObject.SetActive(false);
  123. }
  124. if (RotationPadPrefab != null)
  125. {
  126. RotationPadObject = Instantiate<GameObject>(RotationPadPrefab);
  127. RotationPadObject.SetActive(false);
  128. }
  129. }
  130. void OnDisable()
  131. {
  132. if (SelectionPadObject != null)
  133. SelectionPadObject.SetActive(false);
  134. if (InvalidPadObject != null)
  135. InvalidPadObject.SetActive(false);
  136. if (RotationPadObject != null)
  137. RotationPadObject.SetActive(false);
  138. rotation = float.NegativeInfinity;
  139. }
  140. /// <summary>
  141. /// Updates the used mesh. Dependent on how the the points list to be visualized is populated
  142. /// </summary>
  143. /// <param name="m"> The mesh used for collision detection</param>
  144. /// <param name="points"> List of Vector3 representing the points to be visualized for the teleport</param>
  145. /// <param name="forwardVelocity"> Vector3 representing the velocity of the physical throw calculation</param>
  146. /// <param name="uvOffset"> Offset </param>
  147. private void GenerateMesh(ref Mesh m, List<Vector3> points, Vector3 forwardVelocity, float uvOffset)
  148. {
  149. Vector3[] verts = new Vector3[points.Count * 2];
  150. Vector2[] uv = new Vector2[points.Count * 2];
  151. Vector3 right = Vector3.Cross(forwardVelocity, Vector3.up).normalized;
  152. // calculate new vertices for the mesh
  153. for (int x = 0; x < points.Count; x++)
  154. {
  155. verts[2 * x] = points[x] - right * GraphicThickness / 2;
  156. verts[2 * x + 1] = points[x] + right * GraphicThickness / 2;
  157. float uvoffsetMod = uvOffset;
  158. if (x == points.Count - 1 && x > 1)
  159. {
  160. float distLast = (points[x - 2] - points[x - 1]).magnitude;
  161. float distCur = (points[x] - points[x - 1]).magnitude;
  162. uvoffsetMod += 1 - distCur / distLast;
  163. }
  164. uv[2 * x] = new Vector2(0, x - uvoffsetMod);
  165. uv[2 * x + 1] = new Vector2(1, x - uvoffsetMod);
  166. }
  167. // calculate new triangleArrays for mesh
  168. int[] indices = new int[2 * 3 * (verts.Length - 2)];
  169. for (int x = 0; x < verts.Length / 2 - 1; x++)
  170. {
  171. int p1 = 2 * x;
  172. int p2 = 2 * x + 1;
  173. int p3 = 2 * x + 2;
  174. int p4 = 2 * x + 3;
  175. indices[12 * x] = p1;
  176. indices[12 * x + 1] = p2;
  177. indices[12 * x + 2] = p3;
  178. indices[12 * x + 3] = p3;
  179. indices[12 * x + 4] = p2;
  180. indices[12 * x + 5] = p4;
  181. indices[12 * x + 6] = p3;
  182. indices[12 * x + 7] = p2;
  183. indices[12 * x + 8] = p1;
  184. indices[12 * x + 9] = p4;
  185. indices[12 * x + 10] = p2;
  186. indices[12 * x + 11] = p3;
  187. }
  188. // update mesh with new values
  189. m.Clear();
  190. m.vertices = verts;
  191. m.uv = uv;
  192. m.triangles = indices;
  193. m.RecalculateBounds();
  194. m.RecalculateNormals();
  195. }
  196. }