Skip to content

Commit 07f52ae

Browse files
committed
Fix doc build after adding to the quickindex file.
* Convert EasingFunction into a typing.Protocol so it gets picked up by doc build + explain why * Correct Sphinx style issues and broken cross-references * Explain how of pyglet.math Matrix types won't work with easing (matmul) * Add an __all__ to arcade.anim.easing
1 parent ac69888 commit 07f52ae

1 file changed

Lines changed: 135 additions & 15 deletions

File tree

arcade/anim/easing.py

Lines changed: 135 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,65 @@
1+
"""Core easing annotations and helper functions."""
12
from collections.abc import Callable
23
from math import cos, pi, sin, sqrt, tau
34
from typing import Protocol, TypeVar
45

56
T = TypeVar("T")
67

78

9+
# This needs to be a Protocol rather than an annotation
10+
# due to our build configuration being set to pick up
11+
# classes but not type annotations.
12+
class EasingFunction(Protocol):
13+
"""Any :py:func:`callable` object which maps linear completion to a curve.
14+
15+
.. tip:: See :py:class:`Easing` for the most common easings.
16+
17+
Pass them to :py:func:`.ease` via the ``func``
18+
keyword argument.
19+
20+
If the built-in easing curves are not enough, you can define
21+
your own. Functions should match this pattern:
22+
23+
.. code-block:: python
24+
25+
def f(t: float) -> t:
26+
...
27+
28+
For advanced users, any object with a matching :py:meth:`~object.__call__`
29+
method can be passed as an easing function.
30+
"""
31+
32+
def __call__(self, __t: float) -> float:
33+
...
34+
35+
36+
837
class Animatable(Protocol):
38+
"""Matches types with support for the following operations:
39+
40+
.. list-table::
41+
:header-rows: 1
42+
43+
* - Method
44+
- Summary
45+
46+
* - :py:meth:`~object.__mul__`
47+
- Multiplication by a scalar
48+
49+
* - :py:meth:`~object.__add__`
50+
- Addition
51+
52+
* - :py:meth:`~object.__sub__`
53+
- Subtraction
54+
55+
.. important:: The :py:mod:`pyglet.math` matrix types are currently unsupported.
56+
57+
Although vector types work, matrix multiplication is
58+
subtly different. It uses a separate :py:meth:`~object.__matmul__`
59+
operator for multiplication.
60+
"""
61+
62+
963
def __mul__(self: T, other: T | float, /) -> T: ...
1064

1165
def __add__(self: T, other: T | float, /) -> T: ...
@@ -30,7 +84,29 @@ def __sub__(self: T, other: T | float, /) -> T: ...
3084

3185

3286
class Easing:
33-
""":py:class:`.EasingFunction`s meant for passing into :py:meth:`.ease`."""
87+
"""Built-in easing functions as static methods.
88+
89+
Each takes the following form:
90+
91+
.. code-block:: python
92+
93+
def f(t: float) -> float:
94+
...
95+
96+
Pass them into :py:func:`.ease` via the ``func`` keyword
97+
argument:
98+
99+
.. code-block:: python
100+
101+
from arcade.anim import ease, Easing
102+
103+
value = ease(
104+
1.0, 2.0,
105+
2.0, 3.0,
106+
2.4,
107+
func=Easing.SINE_IN)
108+
109+
"""
34110

35111
# This is a bucket of staticmethods because typing.
36112
# Enum hates this, and they can't be classmethods.
@@ -259,23 +335,33 @@ def _clamp(x: float, low: float, high: float) -> float:
259335

260336

261337
def perc(x: float, start: float, end: float) -> float:
262-
"""
263-
Convert a value ``x`` to be a percentage of progression between
264-
``start`` and ``end``.
338+
"""Convert ``x`` to percent-like progress from ``start`` to ``end``.
339+
340+
Arguments:
341+
x: A value between ``start`` and ``end``.
342+
start: The start of the range.
343+
end: The end of the range.
344+
345+
Returns:
346+
A normalized percent-like completion as a :py:class:`float`.
265347
"""
266348
return (x - start) / (end - start)
267349

268350

269351
def lerp(x: float, minimum: A, maximum: A) -> A:
270-
"""
271-
Convert a percentage ``x`` to be the value when progressed
272-
that amount between ``minimum`` and ``maximum``.
352+
"""Get ``x`` of the way from ``minimum`` to ``maximum``.
353+
354+
Arguments:
355+
x: A percent-like progress measure from ``0`` to ``1.0``.
356+
minimum: The start value along the path.
357+
maximum: The maximum value along the path.
358+
359+
Returns:
360+
A value ``x`` of the way from ``minimum`` to ``maximum``.
273361
"""
274362
return minimum + ((maximum - minimum) * x)
275363

276364

277-
EasingFunction = Callable[[float], float]
278-
279365

280366
def ease(
281367
minimum: A,
@@ -286,21 +372,55 @@ def ease(
286372
func: EasingFunction = Easing.LINEAR,
287373
clamped: bool = True,
288374
) -> A:
289-
"""Ease a value according to a curve. Useful for animating properties over time.
375+
"""Ease a value according to a curve function passed as ``func``.
376+
377+
Override the default easing curve by passing any :py:class:`.Easing`
378+
or :py:class:`.EasingFunction` of your choice.
379+
380+
The ``maximum`` and ``minimum`` must be of compatible types.
381+
For example, these can include:
382+
383+
.. list-table::
384+
:header-rows: 1
385+
386+
* - Type
387+
- Value Example
388+
- Explanation
389+
390+
* - :py:class:`float`
391+
- ``0.5``
392+
- Numbers such as volume or brightness.
290393
291-
Args:
394+
* - :py:class:`~pyglet.math.Vec2`
395+
- ``Vec2(500.0, 200.0)``
396+
- A :py:mod:`pyglet.math` vector representing position.
397+
398+
Arguments:
292399
minimum: any math-like object (a position, scale, value...); the "start position."
293400
maximum: any math-like object (a position, scale, value...); the "end position."
294401
start: a :py:class:`float` defining where progression begins, the "start time."
295402
end: a :py:class:`float` defining where progression ends, the "end time."
296403
t: a :py:class:`float` defining the current progression, the "current time."
297-
func: a :py:class:`.EasingFunction` to modify the result with, typically an
298-
attribute of :py:class:`.Easing`. Defaults to :py:attr:`.Easing.LINEAR`.
299-
clamped: a :py:class:`bool`; whether or not to allow the animation to continue past
300-
the ``start`` and ``end`` "times". Defaults to ``True``.
404+
func: Defaults to :py:attr:`Easing.LINEAR`, but you can pass an
405+
:py:class:`Easing` or :py:class:`.EasingFunction` of your choice.
406+
clamped: Whether the value will be clamped to ``minimum`` and ``maximum``.
407+
408+
Returns:
409+
An eased value for the given time ``t``.
410+
301411
"""
302412
p = perc(t, start, end)
303413
if clamped:
304414
p = _clamp(p, 0.0, 1.0)
305415
new_p = func(p)
306416
return lerp(new_p, minimum, maximum)
417+
418+
__all__ = [
419+
"Animatable",
420+
"Easing",
421+
"EasingFunction",
422+
"ease",
423+
"perc",
424+
"lerp"
425+
]
426+

0 commit comments

Comments
 (0)