123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- //***********************************************************
- // Filename: BallTeleport.cs
- // Author: Moritz Kolvenbach, Marco Fendrich
- // Last changes: Thursday, 9th of August 2018
- // Content: Teleportation with a thrown ball
- //***********************************************************
- using System.Collections.Generic;
- using UnityEngine;
- /// <summary>
- /// Ball teleport by throwing an instantiated object from the player's hand
- /// </summary>
- public class BallTeleport : MonoBehaviour, IButton
- {
- // general reference classes for access
- private GameObject gameManager;
- private Visualiser renderScript;
- private Teleport teleportScript;
- private ViveNavMesh navMesh;
- // list of points within parabola or line being shown to player as indicator for his teleportation
- protected List<Vector3> projectionPoints;
- // distance in meters between the single points of the optical representation
- protected float pointSpacing;
- // maximum number of points being calculated until parabola is being stopped
- protected int pointCount;
- // prefab to be thrown
- public GameObject ballPrefab;
- // instantiated object while throwing
- private GameObject ballObject;
- // current state of teleportation
- private BallState ballState;
- // additional information needed for calculations; details below
- private Vector3 lastPosition;
- private bool isBallAboveMesh;
- private Vector3 teleportDestination;
- private Vector3 normalVector;
- // reference to controller
- private SteamVR_Controller.Device controller;
- // for rendering only
- protected Vector3 normalisedVelocity = Vector3.down;
- protected Vector3 normalisedHitPoint = Vector3.up;
- void Start()
- {
- // get references for variables declared above
- gameManager = GameObject.FindWithTag("GameController");
- teleportScript = (Teleport)gameManager.GetComponent(typeof(Teleport));
- renderScript = (Visualiser)gameManager.GetComponent(typeof(Visualiser));
- navMesh = (ViveNavMesh)gameManager.GetComponent(typeof(ViveNavMesh));
- projectionPoints = new List<Vector3>(pointCount);
- pointSpacing = renderScript.PointSpacing;
- pointCount = renderScript.PointCount;
- }
- void Update()
- {
- // only running when ball is currently being thrown
- if (ballState != BallState.THROWING) return;
- // calculate a line downwards as preparation to show the current teleport target position
- UpdateProjectionPoints();
- // display the calculated points
- renderScript.updateRendering(isBallAboveMesh, projectionPoints, normalisedHitPoint, Vector3.down * 10.0F);
- }
- /// <summary>
- /// Function being called on press by player; checks the state the teleportation is in and either creates a new ball or
- /// destroys the old one. Teleports if the ball was above a valid destination
- /// </summary>
- /// <param name="controllerObject">gameObject of controller</param>
- /// <param name="controllerIdentificator">ID of controller currently using this function</param>
- public void OnButtonDown(GameObject controllerObject, int controllerIdentificator)
- {
- // if no ball is instantiated, create new one
- if (ballState == BallState.NONE)
- {
- // create ball at controller position
- controller = SteamVR_Controller.Input(controllerIdentificator);
- ballObject = Instantiate(ballPrefab, controllerObject.transform.position, controllerObject.transform.rotation);
- // set the ball to stay static at front of controller
- ballObject.GetComponent<Rigidbody>().isKinematic = true;
- ballObject.transform.SetParent(controllerObject.transform);
- // set ballstate to a ball being held
- ballState = BallState.HELD;
- }
- // if a ball is currently instantied and was thrown, destroy it and teleport if the position was valid
- else if (ballState == BallState.THROWING)
- {
- // check whether the ball was above a valid destination
- 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);
- // if so, teleport there
- if (isBallAboveMesh)
- {
- teleportScript.CallTeleport(teleportDestination);
- }
- // if not, give haptic feedback that input was registered as no other feedback would be given
- else
- {
- // vibrate controller
- }
- // destroy ball, stop rendering, reset ball state
- Destroy(ballObject);
- ballState = BallState.NONE;
- renderScript.enabled = false;
- }
- }
- /// <summary>
- /// Function being called on release of button by player; releases ball if one is currently being held
- /// </summary>
- public void OnButtonUp()
- {
- // check if an instantiated ball is being held
- if (ballState != BallState.HELD) return;
- // if so, decouple from controller
- ballObject.GetComponent<Rigidbody>().isKinematic = false;
- ballObject.transform.SetParent(null);
- // give the ball the controller's speed increased by factor
- ballObject.GetComponent<Rigidbody>().velocity = controller.velocity * 2.0F;
- // set ball state to throwing and start rendering position being targeted
- ballState = BallState.THROWING;
- renderScript.enabled = true;
- }
- /// <summary>
- /// Sample a bunch of points along a line until you hit gnd. At that point, cut off the parabola
- /// Entire calculation is analogue to <see class = "ParabolicTeleport"></see> except with downward velocity
- /// </summary>
- private void UpdateProjectionPoints()
- {
- // turn velocity to work straight down
- normalisedVelocity = transform.TransformDirection(Vector3.down);
- projectionPoints.Clear();
- projectionPoints.Add(ballObject.transform.position);
- Vector3 last = ballObject.transform.position;
- for (int i = 0; i < pointCount; i++)
- {
- Vector3 next = new Vector3(last.x, last.y - pointSpacing, last.z);
- Vector3 castHit;
- Vector3 norm;
- bool endOnNavmesh;
- if (navMesh.Linecast(last, next, out endOnNavmesh, out castHit, out norm))
- {
- projectionPoints.Add(castHit);
- normalisedHitPoint = norm;
- isBallAboveMesh = endOnNavmesh;
- return;
- }
- else
- {
- projectionPoints.Add(next);
- }
- last = next;
- }
- normalisedHitPoint = Vector3.up;
- isBallAboveMesh = false;
- }
- }
- /// <summary>
- /// Represents the player's current use of the ball teleport machanic.
- /// </summary>
- public enum BallState
- {
- // The player is not using teleportation right now
- NONE,
- // The player is holding an instance of the ball prefab
- HELD,
- // The ball is currently flying and therefore "selecting" a destination
- THROWING
- }
|