123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- //***********************************************************
- // Filename: Visualiser.cs
- // Author: Marco Fendrich, Moritz Kolvenbach
- // Last changes: Thursday, 9th of August 2018
- // Content: A class to render the visual representation of the different teleportConditions
- //***********************************************************
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- /// <summary>
- /// Handles the rendering of the visual feedback for the different teleportMethods
- /// </summary>
- public class Visualiser : MonoBehaviour {
- [Header("Parabola Mesh Properties")]
- [Tooltip("Number of points on the parabola mesh. Greater point counts lead to a higher poly/smoother mesh.")]
- public int PointCount = 50;
- [Tooltip("Approximate spacing between each of the points on the parabola mesh.")]
- public float PointSpacing = 0.5f;
- [Tooltip("Thickness of the parabola mesh")]
- public float GraphicThickness = 0.05f;
- [Tooltip("Material to use to render the parabola mesh")]
- public Material GraphicMaterial;
- [Header("Selection Pad Properties")]
- [SerializeField]
- [Tooltip("Prefab to use as the selection pad when the player is pointing at a valid teleportable surface.")]
- private GameObject SelectionPadPrefab;
- [SerializeField]
- [Tooltip("Prefab to use as the selection pad when the player is pointing at an invalid teleportable surface.")]
- private GameObject InvalidPadPrefab;
- [SerializeField]
- [Tooltip("Prefab to use as the selection pad when using the turn teleport.")]
- private GameObject RotationPadPrefab;
- // The final point, where the player gets teleported to
- private Vector3 SelectedPoint;
- // The mesh used to check for collisions and validate whether the targetPoint is acutually teleportable
- private Mesh ParabolaMesh;
- private float rotation = float.NegativeInfinity;
- // Prefabs for the different kinds of goal markers
- private GameObject SelectionPadObject;
- private GameObject InvalidPadObject;
- private GameObject RotationPadObject;
-
- // Update values based on the information from the different teleportConditions
- public void updateRendering(bool PointOnNavMesh, List<Vector3> ParabolaPoints, Vector3 normal, Vector3 velocity, float rotation)
- {
- this.PointOnNavMesh = PointOnNavMesh;
- this.ParabolaPoints = ParabolaPoints;
- this.normal = normal;
- this.velocity = velocity;
- this.rotation = rotation;
- }
- public void updateRendering(bool PointOnNavMesh, List<Vector3> ParabolaPoints, Vector3 normal, Vector3 velocity)
- {
- this.PointOnNavMesh = PointOnNavMesh;
- this.ParabolaPoints = ParabolaPoints;
- this.normal = normal;
- this.velocity = velocity;
- }
- // True if the final point of parabolaPoints is at a teleportable location
- bool PointOnNavMesh;
- // Normal of selectedPoint
- Vector3 normal;
- Vector3 velocity;
- private List<Vector3> ParabolaPoints;
- void Update () {
- SelectedPoint = ParabolaPoints[ParabolaPoints.Count - 1];
-
- // check which marker to render for each frame
- if (SelectionPadObject != null && rotation == float.NegativeInfinity)
- {
- SelectionPadObject.SetActive(PointOnNavMesh);
- SelectionPadObject.transform.position = SelectedPoint + Vector3.one * 0.005f;
- if (PointOnNavMesh)
- {
- SelectionPadObject.transform.rotation = Quaternion.LookRotation(normal);
- SelectionPadObject.transform.Rotate(90, 0, 0);
- }
- }
- else if (RotationPadObject != null)
- {
- RotationPadObject.SetActive(PointOnNavMesh);
- RotationPadObject.transform.position = SelectedPoint + Vector3.one * 0.005f;
- if (PointOnNavMesh)
- {
- RotationPadObject.transform.rotation = Quaternion.LookRotation(normal);
- RotationPadObject.transform.Rotate(90, 0, 0);
- // rotate selection pad
- Vector2 parabolicVector = new Vector2(velocity.x, velocity.z);
- RotationPadObject.transform.Rotate(0, Vector2.SignedAngle(parabolicVector, Vector2.up) - 90.0F, 0);
- RotationPadObject.transform.Rotate(0, rotation, 0);
- }
- }
- if (InvalidPadObject != null)
- {
- InvalidPadObject.SetActive(!PointOnNavMesh);
- InvalidPadObject.transform.position = SelectedPoint + Vector3.one * 0.005f;
- if (!PointOnNavMesh)
- {
- InvalidPadObject.transform.rotation = Quaternion.LookRotation(normal);
- InvalidPadObject.transform.Rotate(90, 0, 0);
- }
- }
- // Draw parabola (BEFORE the outside faces of the selection pad, to avoid depth issues)
- GenerateMesh(ref ParabolaMesh, ParabolaPoints, velocity, Time.time % 1);
- Graphics.DrawMesh(ParabolaMesh, Matrix4x4.identity, GraphicMaterial, gameObject.layer);
- }
- void Start()
- {
- // populate initial mesh
- ParabolaMesh = new Mesh();
- ParabolaMesh.MarkDynamic();
- ParabolaMesh.name = "Parabolic Pointer";
- ParabolaMesh.vertices = new Vector3[0];
- ParabolaMesh.triangles = new int[0];
- // instantiate target marker prefabs
- if (SelectionPadPrefab != null)
- {
- SelectionPadObject = Instantiate<GameObject>(SelectionPadPrefab);
- SelectionPadObject.SetActive(false);
- }
- if (InvalidPadPrefab != null)
- {
- InvalidPadObject = Instantiate<GameObject>(InvalidPadPrefab);
- InvalidPadObject.SetActive(false);
- }
- if (RotationPadPrefab != null)
- {
- RotationPadObject = Instantiate<GameObject>(RotationPadPrefab);
- RotationPadObject.SetActive(false);
- }
- }
- void OnDisable()
- {
- if (SelectionPadObject != null)
- SelectionPadObject.SetActive(false);
- if (InvalidPadObject != null)
- InvalidPadObject.SetActive(false);
- if (RotationPadObject != null)
- RotationPadObject.SetActive(false);
- rotation = float.NegativeInfinity;
- }
- /// <summary>
- /// Updates the used mesh. Dependent on how the the points list to be visualized is populated
- /// </summary>
- /// <param name="m"> The mesh used for collision detection</param>
- /// <param name="points"> List of Vector3 representing the points to be visualized for the teleport</param>
- /// <param name="forwardVelocity"> Vector3 representing the velocity of the physical throw calculation</param>
- /// <param name="uvOffset"> Offset </param>
- private void GenerateMesh(ref Mesh m, List<Vector3> points, Vector3 forwardVelocity, float uvOffset)
- {
- Vector3[] verts = new Vector3[points.Count * 2];
- Vector2[] uv = new Vector2[points.Count * 2];
- Vector3 right = Vector3.Cross(forwardVelocity, Vector3.up).normalized;
- // calculate new vertices for the mesh
- for (int x = 0; x < points.Count; x++)
- {
- verts[2 * x] = points[x] - right * GraphicThickness / 2;
- verts[2 * x + 1] = points[x] + right * GraphicThickness / 2;
- float uvoffsetMod = uvOffset;
- if (x == points.Count - 1 && x > 1)
- {
- float distLast = (points[x - 2] - points[x - 1]).magnitude;
- float distCur = (points[x] - points[x - 1]).magnitude;
- uvoffsetMod += 1 - distCur / distLast;
- }
- uv[2 * x] = new Vector2(0, x - uvoffsetMod);
- uv[2 * x + 1] = new Vector2(1, x - uvoffsetMod);
- }
- // calculate new triangleArrays for mesh
- int[] indices = new int[2 * 3 * (verts.Length - 2)];
- for (int x = 0; x < verts.Length / 2 - 1; x++)
- {
- int p1 = 2 * x;
- int p2 = 2 * x + 1;
- int p3 = 2 * x + 2;
- int p4 = 2 * x + 3;
- indices[12 * x] = p1;
- indices[12 * x + 1] = p2;
- indices[12 * x + 2] = p3;
- indices[12 * x + 3] = p3;
- indices[12 * x + 4] = p2;
- indices[12 * x + 5] = p4;
- indices[12 * x + 6] = p3;
- indices[12 * x + 7] = p2;
- indices[12 * x + 8] = p1;
- indices[12 * x + 9] = p4;
- indices[12 * x + 10] = p2;
- indices[12 * x + 11] = p3;
- }
- // update mesh with new values
- m.Clear();
- m.vertices = verts;
- m.uv = uv;
- m.triangles = indices;
- m.RecalculateBounds();
- m.RecalculateNormals();
- }
- }
|