//***********************************************************
// 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;
}
}