Skip to content

Instantly share code, notes, and snippets.

@sebtoun
Last active April 14, 2022 16:51
Show Gist options
  • Save sebtoun/60035fb1c9270a0a362a85f0f5bb6fb5 to your computer and use it in GitHub Desktop.
Save sebtoun/60035fb1c9270a0a362a85f0f5bb6fb5 to your computer and use it in GitHub Desktop.
Stretch With Velocity Animation for Unity
using UnityEngine;
public class StretchWithVelocity : MonoBehaviour
{
public float MaxVelocity = 10;
public float MaxSpeedStretch = 0.5f;
public bool CompensatePosition = true;
public float MinVelocity = 0.1f;
public float Smoothing = 0.1f;
private Vector2 _lastPosition;
private Transform _childTransform;
private Bounds _childBounds;
private float _currentStretchVelocity;
private float _targetStretch;
private float _currentStretch;
private Vector2 _currentDirection;
#if UNITY_EDITOR
// just for debugging purposes
[ SerializeField ]
#pragma warning disable 0414 // private field assigned but not used.
private Vector2 _percievedVelocity;
#endif
private void Awake()
{
_childTransform = transform.GetChild( 0 );
}
private void Start()
{
_childBounds = _childTransform.GetComponent<Renderer>().bounds;
_currentDirection = Vector2.right;
}
private void OnEnable()
{
_lastPosition = transform.position;
_currentStretch = 1;
}
private void OnDisable()
{
ResetStretch();
}
private void LateUpdate()
{
if ( Time.deltaTime <= 0 ) return;
var position = (Vector2) transform.position;
var velocity = ( position - _lastPosition ) / Time.deltaTime;
if ( velocity.sqrMagnitude >= MinVelocity * MinVelocity )
{
_currentDirection = velocity;
}
else
{
_currentDirection = Vector2.right;
}
#if UNITY_EDITOR
_percievedVelocity = velocity;
#endif
_lastPosition = position;
_targetStretch = 1 + Mathf.Lerp( 0, MaxSpeedStretch, Mathf.Clamp01( velocity.magnitude / MaxVelocity ) );
_currentStretch = Mathf.SmoothDamp( _currentStretch, _targetStretch, ref _currentStretchVelocity, Smoothing );
ApplyStretch( _currentDirection, _currentStretch );
}
private void ResetStretch()
{
transform.localScale = Vector3.one;
transform.localRotation = Quaternion.identity;
_childTransform.localRotation = Quaternion.identity;
_currentStretch = 1;
}
private void ApplyStretch( Vector2 direction, float stretch )
{
var parentScaleSign = Signs( transform.parent.lossyScale );
direction.Scale( parentScaleSign );
var angle = Mathf.Atan2( direction.y, direction.x ) * Mathf.Rad2Deg;
var scale = new Vector3( stretch, 1 / stretch, 1 );
var rotation = Quaternion.AngleAxis( angle, Vector3.forward );
transform.localScale = scale;
transform.localRotation = rotation;
_childTransform.localRotation = Quaternion.Inverse( rotation );
if ( CompensatePosition )
{
var offsetX = Mathf.Abs( Mathf.Cos( angle * Mathf.Deg2Rad ) ) * ( 1 - 1 / stretch ) * _childBounds.size.y *
0.5f;
var offsetY = Mathf.Sin( angle * Mathf.Deg2Rad ) * ( stretch - 1 ) * _childBounds.size.y * 0.5f;
var pos = transform.position;
pos.y -= offsetX;
pos.y -= offsetY;
_childTransform.position = pos;
}
}
public static Vector3 Signs( Vector3 v )
{
return new Vector3( Mathf.Sign( v.x ), Mathf.Sign( v.y ), Mathf.Sign( v.z ) );
}
}
@Kyanoxia
Copy link

Kyanoxia commented Apr 9, 2022

But how would you only stretch on the Y axis?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment