Skip to content

Instantly share code, notes, and snippets.

@Juansero29
Created October 10, 2021 18:07
Show Gist options
  • Save Juansero29/f3f5a0a7e6c68588dd97ea1fe5d9b59e to your computer and use it in GitHub Desktop.
Save Juansero29/f3f5a0a7e6c68588dd97ea1fe5d9b59e to your computer and use it in GitHub Desktop.
Basketball Launch Arc Renderer
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(LineRenderer))]
public class LaunchArcRenderer : MonoBehaviour
{
/*
* SUVAT EQUATIONS
* S | horizontal distance traveled
* U | initial velocity
* Ux | initial horizontal velocity
* Uy | initial vertical velocity
* V | final velocity
* A | standard acceleration due to gravity on the surface of the earth (≈ 9.807 m/s^2)
* T | travel time
* h | initial height
* hmax | maximum height
* α | release angle relative to horizontal
*
*
* When h = 0:
*
* Ux = U * cos(α)
* Uy = U * sin(α)
* T = 2 * Uy / A
* hmax = (v^2 sin^2(α))/(2 * A)
* hmax = Uy^2 / (2 * A)
* S = (v^2 sin(2 α))/A (old)
* S = 2 * Ux * Uy / A
*
* S = Ux * T
* Ux = S/T
* Uy = (hmax/T + (1/2)) * A * T
* T = (2 v sin(α))/A
*
* When h != 0:
*
* Ux = U * cos(α)
* Uy = U * sin(α)
* t = (Uy + sqrt(Uy^2 + 2 * A * h)) / A
* S = Ux * [Uy + sqrt(Uy^2 + 2 * A * h)] / A
* hmax = (h + Uy²) / (2 * A)
* Uy = sqrt( (hmax - h) / (2*A))
* U = sqrt(V - 2A * hmax)
*/
#region Private Fields
private float _maximumDistance;
private float _initialVelocity;
private Vector3 _initialVelocityVector;
private float _finalVelocity = 0.0f;
private float _gravity;
private float _initialHeight;
private float _maximumHeight;
private float _angleInDegrees;
private float _angleInRadians;
private Vector3 _mouseWorldPosition;
private float _distanceBetweenObjectAndMouse;
private Vector3 _ArcOriginPoint;
private Rigidbody _RigidBody;
private Plane _launchArcPlane;
private Vector3 _mouseDirection;
private LineRenderer _LineRenderer;
#endregion
#region Public Fields
/// <summary>
/// How many segments the arc is going to have (smoothness vs. sharpness)
/// </summary>
public int NumberOfSegments;
private bool _hasShot;
private Vector3[] _arcPositions;
#endregion
private void Awake()
{
_ArcOriginPoint = transform.position;
_RigidBody = GetComponent<Rigidbody>();
_LineRenderer = GetComponent<LineRenderer>();
_gravity = Math.Abs(Physics2D.gravity.y);
CreatePlaneThatCutsBallInTwoVertically();
void CreatePlaneThatCutsBallInTwoVertically()
{
_launchArcPlane = new Plane(transform.forward, transform.position);
}
}
private void Update()
{
if (_LineRenderer == null || !Application.isPlaying) return;
_initialHeight = transform.position.y;
_angleInDegrees = GetAngleInDegreesBetweenMouseAndObject2();
_angleInRadians = GetAngleInRadiansFromAngleInDegrees();
_maximumHeight = GetMaximumHeightForObject();
CalculateInitialVelocityUsingFinalVelocityMaximumHeightAndAngle();
// CalculateInitialVelocityUsingMaximumHeightAndAngle();
//CalculateInitialVelocityUsingGravityAndMaximumHeight();
// SetVelocityUsingDistanceBetweenObjectAndMouse();
CalculateVelocityVectorUsingInitialVelocityAndAngle();
//CalculateVelocityAndVectorUsingMouseWorldPosition();
//CalculateVelocityAndVectorUsingMousePositionAndObjectPosition();
// _maximumDistance = GetMaximumDistanceUsingVelocityGravityAndAngle();
_maximumDistance = GetMaximumDistanceUsingVelocityVectorInitalHeightAndGravity();
Debug.Log($"_angleInDegrees: {_angleInDegrees} " +
$" _maximumHeight: {_maximumHeight}" +
$"_initialVelocity: {_initialVelocity}" +
$"_initialVelocityVector: {_initialVelocityVector}");
if (Input.GetMouseButtonDown(0))
{
SetVelocityAndGravityForObject();
}
if (!_hasShot)
{
_arcPositions = CalculateArcArrayPositions();
SetLineRendererPositions();
}
}
#region Formulas
#region Maximum Height
private float GetMaximumHeightForObject()
{
return _mouseWorldPosition.y - transform.position.y;
}
#endregion
#region Velocity
private void CalculateVelocityVector()
{
CalculateInitialVelocityUsingGravityAndMaximumHeight();
// SetVelocityUsingDistanceBetweenObjectAndMouse();
CalculateVelocityVectorUsingInitialVelocityAndAngle();
}
#region Velocity
private void CalculateInitialVelocityUsingGravityAndMaximumHeight()
{
// the object should travel _initialVelocity distance units in 1 second
_initialVelocity = Mathf.Sqrt(2) * Mathf.Sqrt(_gravity) * Mathf.Sqrt(_maximumHeight);
}
private void SetVelocityUsingDistanceBetweenObjectAndMouse()
{
_initialVelocity = _distanceBetweenObjectAndMouse * 1.2F;
}
private void CalculateInitialVelocityUsingMaximumHeightAndAngle()
{
_initialVelocity = Mathf.Sqrt((2 * _gravity * _maximumHeight) / (Mathf.Sin(_angleInRadians) * Mathf.Sin(_angleInRadians)));
}
private void CalculateInitialVelocityUsingFinalVelocityMaximumHeightAndAngle()
{
_initialVelocity = Mathf.Sqrt(2 * _gravity * _maximumHeight) / Mathf.Sin(_angleInRadians);
}
#endregion
#region Velocity Vector
private void CalculateVelocityVectorUsingInitialVelocityAndAngle()
{
_initialVelocityVector = new Vector3(_initialVelocity * Mathf.Cos(_angleInDegrees * Mathf.Deg2Rad), _initialVelocity * Mathf.Sin(_angleInDegrees * Mathf.Deg2Rad), 0);
}
private void CalculateVelocityAndVectorUsingMouseWorldPosition()
{
_initialVelocityVector = _mouseWorldPosition - transform.position;
_initialVelocity = Mathf.Sqrt(Mathf.Pow(_initialVelocityVector.x, 2) + Mathf.Pow(_initialVelocityVector.y, 2));
}
private void CalculateVelocityAndVectorUsingMousePositionAndObjectPosition()
{
_initialVelocityVector = (_mouseWorldPosition - transform.position);
_initialVelocity = Mathf.Sqrt(Mathf.Pow(_initialVelocityVector.x, 2) + Mathf.Pow(_initialVelocityVector.y, 2));
}
#endregion
#endregion
#region Maximum Distance
private float GetMaximumDistanceUsingVelocityGravityAndAngle()
{
return (Mathf.Sin(_angleInRadians * 2) * Mathf.Pow(_initialVelocity, 2)) / _gravity;
}
private float GetMaximumDistanceUsingVelocityVectorInitalHeightAndGravity()
{
return _initialVelocityVector.x * (_initialVelocityVector.y + Mathf.Sqrt(Mathf.Pow(_initialVelocityVector.y, 2) + 2 * _gravity * _initialHeight)) / _gravity;
}
#endregion
#region Angle
float GetAngleInRadiansFromAngleInDegrees()
{
return Mathf.Deg2Rad * _angleInDegrees;
}
private float GetAngleInDegreesBetweenMouseAndObject()
{
_mouseWorldPosition = GetMousePositionFrom3DWorld();
_mouseWorldPosition.z = transform.position.z;
_distanceBetweenObjectAndMouse = Vector3.Distance(transform.position, _mouseWorldPosition);
_mouseDirection = _mouseWorldPosition - transform.position;
var angle = Vector3.Angle(_mouseDirection, transform.right);
Debug.Log($"angle: {angle}");
return angle;
}
private float GetAngleInDegreesBetweenMouseAndObject2()
{
_mouseWorldPosition = GetMousePositionFrom3DWorld();
_mouseWorldPosition.z = transform.position.z;
_distanceBetweenObjectAndMouse = Vector3.Distance(transform.position, _mouseWorldPosition);
_mouseDirection = _mouseWorldPosition - transform.position;
var angle = Vector2.SignedAngle(Vector2.left, _mouseDirection);
Debug.Log($"angle: {angle}");
return angle;
}
#endregion
#endregion
#region Interactions
private Vector3 GetMousePositionFrom3DWorld()
{
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (_launchArcPlane.Raycast(ray, out float distance))
{
return ray.GetPoint(distance);
}
return transform.position;
}
private void SetVelocityAndGravityForObject()
{
_hasShot = true;
_RigidBody.useGravity = true;
_RigidBody.velocity = _initialVelocityVector;
}
#endregion
#region Arc
private void SetLineRendererPositions()
{
_LineRenderer.positionCount = NumberOfSegments + 1;
_LineRenderer.SetPositions(_arcPositions);
}
private Vector3[] CalculateArcArrayPositions()
{
var positionArray = CreatePositionsArray();
for (int i = 0; i <= NumberOfSegments; i++)
{
var normalizedProgress = (float)i / (float)NumberOfSegments;
positionArray[i] = CalculateArcPoint(normalizedProgress, _maximumDistance) + _ArcOriginPoint;
}
return positionArray;
Vector3[] CreatePositionsArray()
{
return new Vector3[NumberOfSegments + 1];
}
}
private Vector3 CalculateArcPoint(float normalizedProgress, float maximumDistance)
{
var x = (normalizedProgress * maximumDistance);
var y = x * Mathf.Tan(_angleInRadians) - (_gravity * Mathf.Pow(x, 2) / (2 * Mathf.Pow(_initialVelocity, 2) * Mathf.Pow(Mathf.Cos(_angleInRadians), 2)));
return new Vector3(x, y);
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment