Skip to content
Merged
6 changes: 1 addition & 5 deletions arcade/pymunk_physics_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,14 @@ class PymunkException(Exception):
class PymunkPhysicsEngine:
"""An Arcade-specific adapter for Pymunk.

.. _Pymunk: https://www.pymunk.org/en/latest/index.html
.. _Chipmunk2D: https://chipmunk-physics.net/
.. _CONTRIBUTING.md: https://github.com/pythonarcade/arcade/blob/development/CONTRIBUTING.md

`Pymunk`_ is itself a Python adapter for the professional-grade
`Chipmunk2D`_ engine. However, Arcade's ``PymunkPhysicsEngine``
and its doc are currently in need of improvement.

.. note:: Arcade would welcome assistance with improving it.

If you are interested, please see Arcade's
`CONTRIBUTING.md`_.
`CONTRIBUTING.md <CONTRIBUTING.md: https://github.com/pythonarcade/arcade/blob/development/CONTRIBUTING.md>`_

Args:
gravity:
Expand Down
91 changes: 38 additions & 53 deletions arcade/sound.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class Sound:
please see:

* :ref:`sound-loading-modes-streaming`
* The py:class:`pyglet.media.codes.base.StreamingSource` class used
* The :py:class:`pyglet.media.codecs.base.StreamingSource` class used
internally

To learn about cross-platform loading and file format concerns,
Expand Down Expand Up @@ -90,18 +90,12 @@ def play(
loop: bool = False,
speed: float = 1.0,
) -> media.Player:
"""Try to play this :py:class:`Sound` and return a :py:class:`~pyglet.media.player.Player`.
"""Try to play this :py:class:`Sound` and return a |pyglet Player|.

.. important:: Any :py:class:`Sound` with ``streaming=True`` loses features!
.. important:: A :py:class:`Sound` with ``streaming=True`` loses features!

``loop`` will not work and simultaneous playbacks raise
a :py:class:`RuntimeError`.

See the following to learn more about the keywords and restrictions:

* :py:class:`Sound`
* :ref:`sound-advanced-playback-change-aspects-ongoing`
* :ref:`sound-advanced-playback-change-aspects-new`
Neither ``loop`` nor simultaneous playbacks will work. See
:py;class:`Sound` and :ref:`sound-loading-modes`.

Args:
volume: Volume (``0.0`` is silent, ``1.0`` is loudest).
Expand All @@ -110,6 +104,8 @@ def play(
loop: ``True`` attempts to restart playback after finishing.
speed: Change the speed (and pitch) of the sound. Default speed is
``1.0``.
Returns:
A |pyglet Player| for this playback.
"""
if isinstance(self.source, media.StreamingSource) and self.source.is_player_source:
raise RuntimeError(
Expand Down Expand Up @@ -151,14 +147,14 @@ def _on_player_eos():
return player

def stop(self, player: media.Player) -> None:
"""Permanently stop and :py:meth:`~pyglet.media.player.Player.delete` ``player``.
"""Stop and :py:meth:`~pyglet.media.player.Player.delete` ``player``.

All references in the :py:class:`pyglet.media.Source` player table
will be deleted.
All references to it in the internal table for
:py:class:`pyglet.media.Source` will be deleted.

Args:
player: A pyglet :py:class:`~pyglet.media.player.Player`
returned from :func:`play_sound` or :py:meth:`Sound.play`.
player: A pyglet |pyglet Player| from :func:`play_sound`
or :py:meth:`Sound.play`.
"""
player.pause()
player.delete()
Expand All @@ -179,9 +175,8 @@ def is_playing(self, player: media.Player) -> bool:
"""``True`` if ``player`` is currently playing, otherwise ``False``.

Args:
player: A pyglet :py:class:`~pyglet.media.player.Player`
returned from :py:meth:`Sound.play <.Sound.play>` or
:func:`play_sound`.
player: A |pyglet Player| from :func:`play_sound` or
:py:meth:`Sound.play`.

Returns:
``True`` if the passed pyglet player is playing.
Expand All @@ -192,9 +187,8 @@ def get_volume(self, player: media.Player) -> float:
"""Get the current volume.

Args:
player: A pyglet :py:class:`~pyglet.media.player.Player`
returned from :py:meth:`Sound.play <.Sound.play>` or
:func:`play_sound`.
player: A |pyglet Player| from :func:`play_sound` or
:py:meth:`Sound.play`.
Returns:
A volume between ``0.0`` (silent) and ``1.0`` (full volume).
"""
Expand All @@ -205,8 +199,8 @@ def set_volume(self, volume: float, player: media.Player) -> None:

Args:
volume: Floating point volume. 0 is silent, 1 is full.
player: A pyglet :py:class:`~pyglet.media.player.Player`
returned from :func:`play_sound` or :py:meth:`Sound.play`.
player: A |pyglet Player| from :func:`play_sound` or
:py:meth:`Sound.play`.
"""
player.volume = volume

Expand All @@ -215,18 +209,19 @@ def get_stream_position(self, player: media.Player) -> float:
zero when it is done playing.

Args:
player: Player returned from :func:`play_sound`.
player: A |pyglet Player| from :func:`play_sound` or
:py:meth:`Sound.play`.
"""
return player.time


def load_sound(path: str | Path, streaming: bool = False) -> Sound:
"""Load a file as a :py:class:`Sound` data object.

.. important:: Using ``streaming=True`` disables certain features!
.. important:: A :py:class:`Sound` with ``streaming=True`` loses features!

These include looping and multiple playbacks. Please
see :py:class:`Sound` to learn more.
Neither ``loop`` nor simultaneous playbacks will work. See
:py;class:`Sound` and :ref:`sound-loading-modes`.

Args:
path: a path which may be prefixed with a
Expand Down Expand Up @@ -261,18 +256,20 @@ def play_sound(
loop: bool = False,
speed: float = 1.0,
) -> media.Player | None:
"""Try to play the ``sound`` and return a :py:class:`~pyglet.media.player.Player`.
"""Try to play the ``sound`` and return a |pyglet Player|.

.. note:: The ``sound`` **must** be a :py:class:`Sound` object!
The ``sound`` must be a loaded :py:class:`Sound` object. If you
pass a path or :py:class:`str`, the function will raise a
:py:class:`TypeError.`

See the following to load audio from file paths:
.. important:: A :py:class:`Sound` with ``streaming=True`` loses features!

* :ref:`sound-basics-loading`
* :ref:`sound-loading-modes`
* :py:func:`load_sound`
* :py:class:`Sound`
Neither ``loop`` nor simultaneous playbacks will work. See
:py;class:`Sound` and :ref:`sound-loading-modes`.

The output and return value depend on whether playback succeeded:
.. # Note: substitutions don't really work inside tables, so the
.. # pyglet player below is left as a normal class cross-reference.

.. list-table::
:header-rows: 1
Expand All @@ -289,21 +286,11 @@ def play_sound(
- N/A
- A pyglet :py:class:`~pyglet.media.player.Player`

See the following to learn more:

* :ref:`sound-basics-sound_vs_player`
* :ref:`sound-advanced-playback`

.. important:: Any :py:class:`Sound` with ``streaming=True`` loses features!

``loop`` will not work and simultaneous playbacks raise
a :py:class:`RuntimeError`.

To learn more about the ``streaming`` keyword and restrictions, please see:

* :py:class:`Sound`
* :ref:`sound-advanced-playback-change-aspects-ongoing`
* :ref:`sound-advanced-playback-change-aspects-new`
* :ref:`sound-intermediate-playback-change-aspects-ongoing`
* :ref:`sound-intermediate-playback-change-aspects-new`

Args:
sound: A :py:class:`Sound` instance or ``None``.
Expand All @@ -315,9 +302,8 @@ def play_sound(
values higher than ``1.0`` raise the pitch.

Returns:
A :py:class:`pyglet.media.Player` instance for the playback or
A |pyglet Player| instance for this playback or
``None`` if playback failed.

"""
if sound is None:
logger.warning("Unable to play sound, no data passed in.")
Expand All @@ -338,12 +324,11 @@ def play_sound(


def stop_sound(player: media.Player) -> None:
"""Stop a pyglet player for a which is currently playing.
"""Stop and delete a |pyglet Player| which is currently playing.

Args:
player: A pyglet :py:class:`~pyglet.media.player.Player`
returned from :py:meth:`Sound.play <.Sound.play>` or
:func:`play_sound`.
player: A pyglet |pyglet Player| from :py:func:`play_sound`
or :py:meth:`Sound.play`.
"""

if not isinstance(player, media.Player):
Expand Down
13 changes: 13 additions & 0 deletions doc/conf.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python
"""Sphinx configuration file"""
from functools import cache
from textwrap import dedent
from typing import Any, NamedTuple
import docutils.nodes
import os
Expand Down Expand Up @@ -175,6 +176,18 @@
'pymunk': ('https://www.pymunk.org/en/latest/', None),
}


# These will be joined as one block and prepended to every source file.
# Substitutions for |version| and |release| are predefined by Sphinx.
rst_prolog = dedent(f"""
.. _Pymunk: https://www.pymunk.org/en/latest/index.html

.. _Chipmunk2D: https://chipmunk-physics.net/

.. |pyglet Player| replace:: pyglet :py:class:`~pyglet.media.player.Player`
""".strip())


def strip_init_return_typehint(app, what, name, obj, options, signature, return_annotation):
# Prevent a the `-> None` annotation from appearing after classes.
# This annotation comes from the `__init__`, but it renders on the class,
Expand Down
2 changes: 2 additions & 0 deletions doc/example_code/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,8 @@ Grid-Based Games
Advanced
--------

.. _example-code-pymunk:

Using PyMunk for Physics
^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading