Source code for arcade.easing

"""
Functions used to support easing
"""
from math import pi, sin, cos
from dataclasses import dataclass
from typing import Callable, Tuple
from .geometry_generic import get_distance


[docs]@dataclass class EasingData: """ Data class for holding information about easing. """ start_period: float cur_period: float end_period: float start_value: float end_value: float ease_function: Callable def reset(self): self.cur_period = self.start_period
[docs]def linear(percent: float) -> float: """ Function for linear easing. """ return percent
def _flip(percent: float) -> float: return 1.0 - percent
[docs]def smoothstep(percent: float) -> float: """ Function for smoothstep easing. """ percent = percent * percent * (3.0 - 2.0 * percent) return percent
[docs]def ease_in(percent: float) -> float: """ Function for quadratic ease-in easing. """ return percent * percent
[docs]def ease_out(percent: float) -> float: """ Function for quadratic ease-out easing. """ return _flip(_flip(percent) * _flip(percent))
[docs]def ease_in_out(percent: float) -> float: """ Function for quadratic easing in and out. """ return 2 * percent**2 if percent < 0.5 else 1 - (-2 * percent + 2)**2 / 2
[docs]def ease_out_elastic(percent: float) -> float: """ Function for elastic ease-out easing. """ c4 = 2 * pi / 3 result = 0.0 if percent == 1: result = 1 elif percent > 0: result = (2 ** (-10 * percent)) * sin((percent * 10 - 0.75) * c4) + 1 return result
[docs]def ease_out_bounce(percent: float) -> float: """ Function for a bouncy ease-out easing. """ n1 = 7.5625 d1 = 2.75 if percent < 1 / d1: return n1 * percent * percent elif percent < 2 / d1: percent_modified = percent - 1.5 / d1 return n1 * percent_modified * percent_modified + 0.75 elif percent < 2.5 / d1: percent_modified = percent - 2.25 / d1 return n1 * percent_modified * percent_modified + 0.9375 else: percent_modified = percent - 2.625 / d1 return n1 * percent_modified * percent_modified + 0.984375
[docs]def ease_in_back(percent: float) -> float: """ Function for ease_in easing which moves back before moving forward. """ c1 = 1.70158 c3 = c1 + 1 return c3 * percent * percent * percent - c1 * percent * percent
[docs]def ease_out_back(percent: float) -> float: """ Function for ease_out easing which moves back before moving forward. """ c1 = 1.70158 c3 = c1 + 1 return 1 + c3 * pow(percent - 1, 3) + c1 * pow(percent - 1, 2)
[docs]def ease_in_sin(percent: float) -> float: """ Function for ease_in easing using a sin wave """ return 1 - cos((percent * pi) / 2)
[docs]def ease_out_sin(percent: float) -> float: """ Function for ease_out easing using a sin wave """ return sin((percent * pi) / 2)
[docs]def ease_in_out_sin(percent: float) -> float: """ Function for easing in and out using a sin wave """ return -cos(percent * pi) * 0.5 + 0.5
[docs]def easing(percent: float, easing_data: EasingData) -> float: """ Function for calculating return value for easing, given percent and easing data. """ return easing_data.start_value + (easing_data.end_value - easing_data.start_value) * \ easing_data.ease_function(percent)
[docs]def ease_angle(start_angle, end_angle, *, time=None, rate=None, ease_function=linear): """ Set up easing for angles. """ while start_angle - end_angle > 180: end_angle += 360 while start_angle - end_angle < -180: end_angle -= 360 diff = abs(start_angle - end_angle) if diff == 0: return None if rate is not None: time = diff / rate easing_data = EasingData(start_value=start_angle, end_value=end_angle, start_period=0, cur_period=0, end_period=time, ease_function=ease_function) return easing_data
[docs]def ease_angle_update(easing_data: EasingData, delta_time: float) -> Tuple: """ Update angle easing. """ done = False easing_data.cur_period += delta_time if easing_data.cur_period >= easing_data.end_period: easing_data.cur_period = easing_data.end_period percent = easing_data.cur_period / easing_data.end_period angle = easing(percent, easing_data) if percent >= 1.0: done = True while angle > 360: angle -= 360 while angle < 0: angle += 360 return done, angle
[docs]def ease_value(start_value, end_value, *, time=None, rate=None, ease_function=linear): """ Get an easing value """ if rate is not None: diff = abs(start_value - end_value) time = diff / rate easing_data = EasingData(start_value=start_value, end_value=end_value, start_period=0, cur_period=0, end_period=time, ease_function=ease_function) return easing_data
[docs]def ease_position(start_position, end_position, *, time=None, rate=None, ease_function=linear): """ Get an easing position """ distance = get_distance(start_position[0], start_position[1], end_position[0], end_position[1]) if rate is not None: time = distance / rate easing_data_x = ease_value(start_position[0], end_position[0], time=time, ease_function=ease_function) easing_data_y = ease_value(start_position[1], end_position[1], time=time, ease_function=ease_function) return easing_data_x, easing_data_y
[docs]def ease_update(easing_data: EasingData, delta_time: float) -> Tuple: """ Update easing between two values/ """ done = False easing_data.cur_period += delta_time if easing_data.cur_period >= easing_data.end_period: easing_data.cur_period = easing_data.end_period if easing_data.end_period == 0: percent = 1.0 value = easing_data.end_value else: percent = easing_data.cur_period / easing_data.end_period value = easing(percent, easing_data) if percent >= 1.0: done = True return done, value