//*********************************************************** // Filename: ParabolicTeleport.cs // Author: Moritz Kolvenbach, Marco Fendrich // Last changes: Wednesday, 8th of August 2018 // Content: Class that calculates the parabola to be rendered and used to aim when preparing to teleport //*********************************************************** using UnityEngine; /// /// Child class of RenderableTeleport doing the actual calculations to aim the teleportation as a parabola /// public class ParabolicTeleport : RenderableTeleport { [Header("Parabola Trajectory")] [Tooltip("Initial velocity of the parabola, in local space.")] public Vector3 initialVelocity = Vector3.forward * 15f; [Tooltip("World-space \"acceleration\" of the parabola. This affects the falloff of the curve.")] public Vector3 acceleration = Vector3.up * -9.8f; /// /// Sample a bunch of points along a parabolic curve until you hit ground. At that point, cut off the parabola /// protected override void UpdateProjectionPoints() { // turn velocity to work into the direction of the controller normalisedVelocity = transform.TransformDirection(initialVelocity); // delete points from last calculation projectionPoints.Clear(); // add start point - the controller projectionPoints.Add(transform.position); // set point from which second point will be calculated to controller position Vector3 last = transform.position; float t = 0; // time for parabola calculation hasn't started yet // iterate through the maximum number of points being calculated for (int i = 0; i < pointCount; i++) { // increase t so that the next calculated point will have the distance set in editor t += pointSpacing / CalculateNewVelocity(normalisedVelocity, acceleration, t).magnitude; // calculate next point of line Vector3 next = CalculateNewPosition(transform.position, normalisedVelocity, acceleration, t); Vector3 castHit; // hit point of line if colliding at or before next calculated point Vector3 norm; // normal of hit point bool endOnNavmesh; // indicator of whether last point calculated ended on navmesh // check whether something is being hit if (navMesh.Linecast(last, next, out endOnNavmesh, out castHit, out norm)) { // if something is being hit, set last point in list to hit point projectionPoints.Add(castHit); // normal of hit point to be used when visualizing the currently selected target normalisedHitPoint = norm; // check whether point is on nav mesh and therefore teleportable pointOnNavMesh = endOnNavmesh; return; } else { // no collision, calculate next point projectionPoints.Add(next); } // set currently calculated point as base for the calculation of the new point last = next; } // if nothing is being hit and maximum number of points is reached, show unreachable target in midair with normal going upwards normalisedHitPoint = Vector3.up; pointOnNavMesh = false; } /// /// Parabolic motion equation applied to three dimensions /// /// Position from which the movement of the current update was started /// Velocity with which the parabola is being calculated /// Acceleration with which the parabola is being calculated /// Abstract time to be used to update point /// Next point of parabola protected Vector3 CalculateNewPosition(Vector3 p0, Vector3 v0, Vector3 a, float t) { Vector3 ret = new Vector3(); for (int i = 0; i < 3; i++) // Parabolic motion equation, d = p0 + v0*t + 1/2at^2 ret[i] = p0[i] + v0[i] * t + 0.5F * a[i] * t * t; return ret; } /// /// Parabolic motion derivative applied to three dimensions; therefore calculating current speed /// /// Initial velocity /// Acceleration /// Time since start of movement /// Current speed protected Vector3 CalculateNewVelocity(Vector3 v0, Vector3 a, float t) { Vector3 ret = new Vector3(); for (int i = 0; i < 3; i++) // Derivative of parabolic motion equation (calculation of total velocity) ret[i] = v0[i] + a[i] * t; return ret; } }