diff --git a/arcade/application.py b/arcade/application.py index d45073892..9134a44b5 100644 --- a/arcade/application.py +++ b/arcade/application.py @@ -89,24 +89,33 @@ class Window(pyglet.window.Window): .. https://pyglet.readthedocs.io/en/latest/programming_guide/windowing.html#window-style Args: - width (int, optional): Window width. Defaults to 1280. - height (int, optional): Window height. Defaults to 720. - title (str, optional): The title/caption of the window - fullscreen (bool, optional): Should this be full screen? - resizable (bool, optional): Can the user resize the window? - update_rate (float, optional): How frequently to run the on_update event. - draw_rate (float, optional): How frequently to run the on_draw event. - (this is the FPS limit) - fixed_rate (float, optional): How frequently should the fixed_updates run, + width (optional): + Window width. Defaults to 1280. + height (optional): + Window height. Defaults to 720. + title (optional): + The title/caption of the window + fullscreen (optional): + Should this be full screen? + resizable (optional): + Can the user resize the window? + update_rate (optional): + How frequently to run the on_update event. + draw_rate (optional): + How frequently to run the on_draw event. (this is the FPS limit) + fixed_rate (optional): + How frequently should the fixed_updates run, fixed updates will always run at this rate. - fixed_frame_cap (float, optional): The maximum number of fixed updates that - can occur in one update loop.defaults to infinite. If large lag spikes - cause your game to freeze, try setting this to a smaller number. This - may cause your physics to lag behind temporarily. - antialiasing (bool, optional): Use multisampling framebuffer (antialiasing) - samples (int): Number of samples used in antialiasing (default 4). + fixed_frame_cap (optional): + The maximum number of fixed updates that can occur in one update loop. + defaults to infinite. If large lag spikes cause your game to freeze, + try setting this to a smaller number. This may cause your physics to + lag behind temporarily. + antialiasing (optional): + Use multisampling framebuffer (antialiasing) + samples: Number of samples used in antialiasing (default 4). Usually this is 2, 4, 8 or 16. - gl_version (tuple[int, int], optional): What OpenGL version to request. + gl_version (optional): What OpenGL version to request. This is ``(3, 3)`` by default and can be overridden when using more advanced OpenGL features. screen (optional): Pass a pyglet :py:class:`~pyglet.display.Screen` to @@ -115,13 +124,17 @@ class Window(pyglet.window.Window): style (optional): Request a non-default window style, such as borderless. Some styles only work in certain situations. See `pyglet's guide to window style `_ to learn more. - visible (bool, optional): Should the window be visible immediately - vsync (bool, optional): Wait for vertical screen refresh before swapping buffer + visible (optional): + Should the window be visible immediately + vsync (optional): + Wait for vertical screen refresh before swapping buffer This can make animations and movement look smoother. - gc_mode (str, optional): Decides how OpenGL objects should be garbage collected + gc_mode (optional): Decides how OpenGL objects should be garbage collected ("context_gc" (default) or "auto") - center_window (bool, optional): If true, will center the window. - enable_polling (bool, optional): Enabled input polling capability. + center_window (optional): + If true, will center the window. + enable_polling (optional): + Enabled input polling capability. This makes the :py:attr:`keyboard` and :py:attr:`mouse` attributes available for use. Raises: @@ -339,18 +352,18 @@ def clear( set through :py:attr:`~arcade.Window.background_color`. Args: - color (optional): Override the current background color - with one of the following: + color (optional): + Override the current background color with one of the following: 1. A :py:class:`~arcade.types.Color` instance 2. A 3 or 4-length RGB/RGBA :py:class:`tuple` of byte values (0 to 255) - color_normalized (RGBANormalized, optional): override the current background color - using normalized values (0.0 to 1.0). For example, (1.0, 0.0, 0.0, 1.0) - making the window contents red. + color_normalized (optional): + override the current background color using normalized values (0.0 to 1.0). + For example, (1.0, 0.0, 0.0, 1.0) making the window contents red. - viewport (Tuple[int, int, int, int], optional): The area of the window to clear. - By default, the entire window is cleared. + viewport (optional): + The area of the window to clear. By default, the entire window is cleared. The viewport format is ``(x, y, width, height)``. """ # Use the configured background color if none is provided @@ -433,16 +446,19 @@ def set_fullscreen( to the size it was before entering fullscreen mode. Args: - fullscreen (bool): Should we enter or leave fullscreen mode? - screen (optional): Which screen should we display on? See :func:`get_screens` - mode (optional): The screen will be switched to the given mode. The mode must + fullscreen (optional): + Should we enter or leave fullscreen mode? + screen (optional): + Which screen should we display on? See :func:`get_screens` + mode (optional): + The screen will be switched to the given mode. The mode must have been obtained by enumerating `Screen.get_modes`. If None, an appropriate mode will be selected from the given `width` and `height`. - width: Override the width of the window. Will be rounded to - :py:attr:`int`. - height: Override the height of the window. Will be rounded to - :py:attr:`int`. + width (optional): + Override the width of the window. Will be rounded to :py:attr:`int`. + height (optional): + Override the height of the window. Will be rounded to :py:attr:`int`. """ # fmt: off super().set_fullscreen( @@ -471,7 +487,7 @@ def on_update(self, delta_time: float) -> bool | None: speed, no matter the frame rate. Args: - delta_time (float): Time interval since the last time the function was + delta_time: Time interval since the last time the function was called in seconds. """ pass @@ -482,7 +498,7 @@ def on_fixed_update(self, delta_time: float): and other systems that should update at a constant rate. Args: - delta_time (float): Time interval since the last time the function was + delta_time: Time interval since the last time the function was called in seconds. """ pass @@ -496,7 +512,7 @@ def _dispatch_updates(self, delta_time: float) -> None: up to the global clock Args: - delta_time (float): Time interval since the last time the function was + delta_time: Time interval since the last time the function was called in seconds. """ GLOBAL_CLOCK.tick(delta_time) @@ -517,7 +533,8 @@ def set_update_rate(self, rate: float) -> None: # Set the update rate to 60 times per second. self.set_update_rate(1 / 60) - :param rate: Update frequency in seconds + Args: + rate: Update frequency in seconds """ self._update_rate = rate pyglet.clock.unschedule(self._dispatch_updates) @@ -542,10 +559,10 @@ def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> bool | None: Override this function to respond to changes in mouse position. Args: - x (int): x position of mouse within the window in pixels - y (int): y position of mouse within the window in pixels - dx (int): Change in x since the last time this method was called - dy (int): Change in y since the last time this method was called + x: x position of mouse within the window in pixels + y: y position of mouse within the window in pixels + dx: Change in x since the last time this method was called + dy: Change in y since the last time this method was called """ pass @@ -558,17 +575,20 @@ def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> bool | bullets ` demo. Args: - x (int): x position of the mouse - y (int): y position of the mouse - button (int): What button was pressed. - This will always be one of the following: + x: + x position of the mouse + y: + y position of the mouse + button: + What button was pressed. This will always be one of the following: - ``arcade.MOUSE_BUTTON_LEFT`` - ``arcade.MOUSE_BUTTON_RIGHT`` - ``arcade.MOUSE_BUTTON_MIDDLE`` - modifiers (int): Bitwise 'and' of all modifiers (shift, ctrl, num lock) - active during this event. See :ref:`keyboard_modifiers`. + modifiers: + Bitwise 'and' of all modifiers (shift, ctrl, num lock) + active during this event. See :ref:`keyboard_modifiers`. """ pass @@ -581,13 +601,19 @@ def on_mouse_drag( Override this function to handle dragging. Args: - x (int): x position of mouse - y (int): y position of mouse - dx (int): Change in x since the last time this method was called - dy (int): Change in y since the last time this method was called - buttons (int): Which button is pressed - modifiers (int): Bitwise 'and' of all modifiers (shift, ctrl, num lock) - active during this event. See :ref:`keyboard_modifiers`. + x: + x position of mouse + y: + y position of mouse + dx: + Change in x since the last time this method was called + dy: + Change in y since the last time this method was called + buttons: + Which button is pressed + modifiers: + Bitwise 'and' of all modifiers (shift, ctrl, num lock) + active during this event. See :ref:`keyboard_modifiers`. """ return self.on_mouse_motion(x, y, dx, dy) @@ -600,15 +626,18 @@ def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> bool to affect gameplay. Args: - x (int): x position of mouse - y (int): y position of mouse - button (int): What button was hit. One of: + x: + x position of mouse + y: + y position of mouse + button: + What button was hit. One of: - ``arcade.MOUSE_BUTTON_LEFT`` - ``arcade.MOUSE_BUTTON_RIGHT`` - ``arcade.MOUSE_BUTTON_MIDDLE`` - - modifiers (int): Bitwise 'and' of all modifiers (shift, ctrl, num lock) + modifiers: + Bitwise 'and' of all modifiers (shift, ctrl, num lock) active during this event. See :ref:`keyboard_modifiers`. """ return False @@ -636,12 +665,14 @@ def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int) -> bool game! Args: - x (int): x position of mouse - y (int): y position of mouse - scroll_x (int): number of steps scrolled horizontally - since the last call of this function - scroll_y (int): number of steps scrolled vertically since - the last call of this function + x: + x position of mouse + y: + y position of mouse + scroll_x: + Number of steps scrolled horizontally since the last call of this function + scroll_y: + Number of steps scrolled vertically since the last call of this function """ return False @@ -674,18 +705,20 @@ def set_mouse_visible(self, visible: bool = True) -> None: for more information. Args: - visible (bool): Whether to hide the system mouse cursor + visible: Whether to hide the system mouse cursor """ super().set_mouse_visible(visible) def on_action(self, action_name: str, state) -> None: """ Called when an action is dispatched. - This is related to the input manager. + This is related to the input manager / controller support. Args: - action_name (str): The name of the action - state: The state of the action + action_name: + The name of the action + state: + The state of the action """ pass @@ -700,10 +733,11 @@ def on_key_press(self, symbol: int, modifiers: int) -> bool | None: :meth:`~.Window.on_key_release`. Args: - symbol (int): Key that was just pushed down - modifiers (int): Bitwise 'and' of all modifiers (shift, - ctrl, num lock) active during this event. - See :ref:`keyboard_modifiers`. + symbol: + Key that was just pushed down + modifiers: + Bitwise 'and' of all modifiers (shift, ctrl, num lock) + active during this event. See :ref:`keyboard_modifiers`. """ return False @@ -757,8 +791,8 @@ def _on_resize(self, width: int, height: int) -> bool | None: called first. Args: - width (int): New width of the window - height (int): New height of the window + width: New width of the window + height: New height of the window """ # Retain viewport self.viewport = (0, 0, width, height) @@ -774,8 +808,8 @@ def on_resize(self, width: int, height: int) -> bool | None: ```super().on_resize(width, height)```. Args: - width (int): New width of the window - height (int): New height of the window + width: New width of the window + height: New height of the window """ pass @@ -786,8 +820,8 @@ def set_minimum_size(self, width: int, height: int) -> None: This will limit how small the window can be resized. Args: - width (int): Minimum width - height (int): Minimum height + width: Minimum width + height: Minimum height """ super().set_minimum_size(width, height) @@ -798,8 +832,8 @@ def set_maximum_size(self, width: int, height: int) -> None: This will limit how large the window can be resized. Args: - width (int): Maximum width - height (int): Maximum height + width: Maximum width + height: Maximum height """ super().set_maximum_size(width, height) @@ -808,8 +842,8 @@ def set_size(self, width: int, height: int) -> None: Resize the window. Args: - width (int): New width of the window - height (int): New height of the window + width: New width of the window + height: New height of the window """ super().set_size(width, height) @@ -889,7 +923,8 @@ def test(self, frames: int = 10) -> None: """ Used by unit test cases. Runs the event loop a few times and stops. - :param frames: + Args: + frames: How many frames to run the event loop for. """ start_time = time.time() for _ in range(frames): @@ -905,7 +940,7 @@ def test(self, frames: int = 10) -> None: time.sleep(sleep_time) self._dispatch_updates(1 / 60) - def show_view(self, new_view: "View") -> None: + def show_view(self, new_view: View) -> None: """ Set the currently active view. @@ -919,7 +954,7 @@ def show_view(self, new_view: "View") -> None: :py:attr:`arcade.Window.current_view` attribute. Args: - new_view (View): The view to activate. + new_view: The view to activate. """ if not isinstance(new_view, View): raise TypeError( @@ -1095,8 +1130,8 @@ def on_mouse_enter(self, x: int, y: int) -> bool | None: dragged. Args: - x (int): The x position the mouse entered the window - y (int): The y position the mouse entered the window + x: The x position the mouse entered the window + y: The y position the mouse entered the window """ pass @@ -1109,8 +1144,8 @@ def on_mouse_leave(self, x: int, y: int) -> bool | None: outside of the window rectangle. Args: - x (int): The x position the mouse entered the window - y (int): The y position the mouse entered the window + x: The x position the mouse entered the window + y: The y position the mouse entered the window """ pass @@ -1186,13 +1221,17 @@ def open_window( instance directly. Args: - width (int): Width of the window. - height (int): Height of the window. - window_title (str): Title/caption of the window. - resizable (bool): Whether the user can resize the window. - antialiasing (bool): Whether to use antialiasing + width: + Width of the window. + height: + Height of the window. + window_title: + Title/caption of the window. + resizable: + Whether the user can resize the window. + antialiasing: + Whether to use antialiasing """ - global _window _window = Window(width, height, window_title, resizable=resizable, antialiasing=antialiasing) _window.invalid = False @@ -1210,8 +1249,9 @@ class View: and a game over screen. Each of these could be a different view. Args: - window (Window, optional): The window this view is associated with. If None, - the current window is used. (Normally you don't need to provide this). + window (optional): + The window this view is associated with. If None, the current + window is used. (Normally you don't need to provide this). """ def __init__(self, window: Window | None = None) -> None: @@ -1247,11 +1287,13 @@ def add_section( Adds a section to the view Section Manager. Args: - section (arcade.Section): The section to add to this section manager - at_index (int, optional): The index to insert the section for event capture and + section: + The section to add to this section manager + at_index (optional): + The index to insert the section for event capture and update events. If ``None`` it will be added at the end. - at_draw_order (int, optional): Inserts the section in a specific draw order. - Overwrites section.draw_order + at_draw_order (optional): + Inserts the section in a specific draw order. Overwrites section.draw_order """ self.section_manager.add_section(section, at_index, at_draw_order) @@ -1265,17 +1307,17 @@ def clear( Clears the window with the configured background color set through :py:attr:`arcade.Window.background_color`. - :param color: (Optional) override the current background color - with one of the following: - - 1. A :py:class:`~arcade.types.Color` instance - 2. A 3 or 4-length RGB/RGBA :py:class:`tuple` of byte values (0 to 255) - - :param color_normalized: (Optional) override the current background color - using normalized values (0.0 to 1.0). For example, (1.0, 0.0, 0.0, 1.0) - making the window contents red. + Args: + color(optional): + override the current background color with one of the following: - :param Tuple[int, int, int, int] viewport: The viewport range to clear + 1. A :py:class:`~arcade.types.Color` instance + 2. A 3 or 4-length RGB/RGBA :py:class:`tuple` of byte values (0 to 255) + color_normalized (optional): + Override the current background color using normalized values (0.0 to 1.0). + For example, (1.0, 0.0, 0.0, 1.0) making the window contents red. + viewport (optional): + The viewport range to clear """ self.window.clear(color=color, color_normalized=color_normalized, viewport=viewport) @@ -1289,8 +1331,8 @@ def on_update(self, delta_time: float) -> bool | None: speed, no matter the frame rate. Args: - delta_time (float): Time interval since the last time the function was - called in seconds. + delta_time: + Time interval since the last time the function was called in seconds. """ pass @@ -1300,8 +1342,8 @@ def on_fixed_update(self, delta_time: float): and other systems that should update at a constant rate. Args: - delta_time (float): Time interval since the last time the function was - called in seconds. + delta_time: + Time interval since the last time the function was called in seconds. """ pass @@ -1336,10 +1378,10 @@ def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> bool | None: Override this function to respond to changes in mouse position. Args: - x (int): x position of mouse within the window in pixels - y (int): y position of mouse within the window in pixels - dx (int): Change in x since the last time this method was called - dy (int): Change in y since the last time this method was called + x: x position of mouse within the window in pixels + y: y position of mouse within the window in pixels + dx: Change in x since the last time this method was called + dy: Change in y since the last time this method was called """ pass @@ -1352,17 +1394,20 @@ def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> bool | bullets ` demo. Args: - x (int): x position of the mouse - y (int): y position of the mouse - button (int): What button was pressed. - This will always be one of the following: + x: + x position of the mouse + y: + y position of the mouse + button: + What button was pressed. This will always be one of the following: - ``arcade.MOUSE_BUTTON_LEFT`` - ``arcade.MOUSE_BUTTON_RIGHT`` - ``arcade.MOUSE_BUTTON_MIDDLE`` - modifiers (int): Bitwise 'and' of all modifiers (shift, ctrl, num lock) - active during this event. See :ref:`keyboard_modifiers`. + modifiers: + Bitwise 'and' of all modifiers (shift, ctrl, num lock) + active during this event. See :ref:`keyboard_modifiers`. """ pass @@ -1375,13 +1420,19 @@ def on_mouse_drag( Override this function to handle dragging. Args: - x (int): x position of mouse - y (int): y position of mouse - dx (int): Change in x since the last time this method was called - dy (int): Change in y since the last time this method was called - buttons (int): Which button is pressed - modifiers (int): Bitwise 'and' of all modifiers (shift, ctrl, num lock) - active during this event. See :ref:`keyboard_modifiers`. + x: + x position of mouse + y: + y position of mouse + dx: + Change in x since the last time this method was called + dy: + Change in y since the last time this method was called + buttons: + Which button is pressed + modifiers: + Bitwise 'and' of all modifiers (shift, ctrl, num lock) + active during this event. See :ref:`keyboard_modifiers`. """ self.on_mouse_motion(x, y, dx, dy) return False @@ -1395,15 +1446,19 @@ def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> bool to affect gameplay. Args: - x (int): x position of mouse - y (int): y position of mouse - button (int): What button was hit. One of: + x: + x position of mouse + y: + y position of mouse + button: + What button was hit. One of: - ``arcade.MOUSE_BUTTON_LEFT`` - ``arcade.MOUSE_BUTTON_RIGHT`` - ``arcade.MOUSE_BUTTON_MIDDLE`` - modifiers (int): Bitwise 'and' of all modifiers (shift, ctrl, num lock) + modifiers: + Bitwise 'and' of all modifiers (shift, ctrl, num lock) active during this event. See :ref:`keyboard_modifiers`. """ pass @@ -1431,12 +1486,16 @@ def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int) -> bool game! Args: - x (int): x position of mouse - y (int): y position of mouse - scroll_x (int): number of steps scrolled horizontally - since the last call of this function - scroll_y (int): number of steps scrolled vertically since - the last call of this function + x: + x position of mouse + y: + y position of mouse + scroll_x: + number of steps scrolled horizontally + since the last call of this function + scroll_y: + number of steps scrolled vertically since + the last call of this function """ pass @@ -1451,10 +1510,11 @@ def on_key_press(self, symbol: int, modifiers: int) -> bool | None: :meth:`~.Window.on_key_release`. Args: - symbol (int): Key that was just pushed down - modifiers (int): Bitwise 'and' of all modifiers (shift, - ctrl, num lock) active during this event. - See :ref:`keyboard_modifiers`. + symbol: + Key that was just pushed down + modifiers: + Bitwise 'and' of all modifiers (shift, ctrl, num lock) active + during this event. See :ref:`keyboard_modifiers`. """ return False @@ -1473,10 +1533,11 @@ def on_key_release(self, _symbol: int, _modifiers: int) -> bool | None: * Showing which keys are currently pressed down Args: - symbol (int): Key that was released - modifiers (int): Bitwise 'and' of all modifiers (shift, - ctrl, num lock) active during this event. - See :ref:`keyboard_modifiers`. + symbol: + Key that was released + modifiers: + Bitwise 'and' of all modifiers (shift, ctrl, num lock) active + during this event. See :ref:`keyboard_modifiers`. """ return False @@ -1489,8 +1550,8 @@ def on_resize(self, width: int, height: int) -> bool | None: ```super().on_resize(width, height)```. Args: - width (int): New width of the window - height (int): New height of the window + width: New width of the window + height: New height of the window """ pass @@ -1502,8 +1563,8 @@ def on_mouse_enter(self, x: int, y: int) -> bool | None: dragged. Args: - x (int): The x position the mouse entered the window - y (int): The y position the mouse entered the window + x: The x position the mouse entered the window + y: The y position the mouse entered the window """ pass @@ -1516,7 +1577,7 @@ def on_mouse_leave(self, x: int, y: int) -> bool | None: outside of the window rectangle. Args: - x (int): The x position the mouse entered the window - y (int): The y position the mouse entered the window + x: The x position the mouse entered the window + y: The y position the mouse entered the window """ pass diff --git a/arcade/context.py b/arcade/context.py index af446650f..892d0e55c 100644 --- a/arcade/context.py +++ b/arcade/context.py @@ -34,15 +34,18 @@ class ArcadeContext(Context): This context is normally accessed through :py:attr:`arcade.Window.ctx`. Args: - window: The pyglet window - gc_mode: The garbage collection mode for OpenGL objects. - ``auto`` is just what we would expect in python - while ``context_gc`` (default) requires you to call ``Context.gc()``. - The latter can be useful when using multiple threads when - it's not clear what thread will gc the object. - gl_api: The OpenGL API to use. By default it's set to ``gl`` which is - the standard OpenGL API. If you want to use OpenGL ES you can - set it to ``gles``. + window: + The pyglet window + gc_mode: + The garbage collection mode for OpenGL objects. ``auto`` is just + what we would expect in python while ``context_gc`` (default) + requires you to call ``Context.gc()``. The latter can be useful + when using multiple threads when it's not clear what thread will + gc the object. + gl_api: + The OpenGL API to use. By default it's set to ``gl`` which is + the standard OpenGL API. If you want to use OpenGL ES you can + set it to ``gles``. """ atlas_size: tuple[int, int] = 512, 512 @@ -352,17 +355,26 @@ def load_program( ) Args: - vertex_shader (str | Path): Path to the vertex shader. - fragment_shader (str | Path, optional): Path to the fragment shader (optional). - geometry_shader (str | Path, optional): Path to the geometry shader (optional). - tess_control_shader (str | Path, optional): Tessellation Control Shader. - tess_evaluation_shader (str | Path, optional): Tessellation Evaluation Shader. - common (Iterable[str], optional): Common files to be included in all shaders. - defines (dict[str, Any], optional): Substitute `#define` values in the source. - varyings (Sequence[str], optional): The name of the out attributes in a - transform shader. This is normally not necessary since we auto detect them, + vertex_shader: + Path to the vertex shader. + fragment_shader (optional): + Path to the fragment shader (optional). + geometry_shader (optional): + Path to the geometry shader (optional). + tess_control_shader (optional): + Tessellation Control Shader. + tess_evaluation_shader (optional): + Tessellation Evaluation Shader. + common (optional): + Common files to be included in all shaders. + defines (optional): + Substitute `#define` values in the source. + varyings (optional): + The name of the out attributes in a transform shader. + This is normally not necessary since we auto detect them, but some more complex out structures we can't detect. - varyings_capture_mode (str, optional): The capture mode for transforms. + varyings_capture_mode (optional): + The capture mode for transforms. Based on these settings, the `transform()` method will accept a single buffer or a list of buffers. @@ -420,8 +432,10 @@ def load_compute_shader( ctx.load_compute_shader(":shader:compute/do_work.glsl") Args: - path: Path to texture - common (optional): Common sources injected into compute shader + path: + Path to texture + common (optional): + Common sources injected into compute shader """ from arcade.resources import resolve @@ -461,12 +475,17 @@ def load_texture( ) Args: - path: Path to texture - flip (bool): Flips the image upside down. Default is ``True``. - build_mipmaps (bool): Build mipmaps for the texture. Default is ``False``. - internal_format (int, optional): The internal format of the texture. This can be used to - override the default internal format when using sRGBA or compressed textures. - compressed (bool, optional): If the internal format is a compressed format meaning your + path: + Path to texture + flip: + Flips the image upside down. Default is ``True``. + build_mipmaps: + Build mipmaps for the texture. Default is ``False``. + internal_format (optional): + The internal format of the texture. This can be used to override + the default internal format when using sRGBA or compressed textures. + compressed (optional): + If the internal format is a compressed format meaning your texture will be compressed by the GPU. """ from arcade.resources import resolve @@ -502,7 +521,7 @@ def shader_inc(self, source: str) -> str: Example:: - #include :my_shader:lib/common.glsl + #include :my_resource_handle:lib/common.glsl Args: source: The shader source code @@ -527,11 +546,14 @@ def get_framebuffer_image( Shortcut method for reading data from a framebuffer and converting it to a PIL image. Args: - fbo (Framebuffer): Framebuffer to get image from - components (int): Number of components to read. Default is 4 (RGBA). + fbo: + Framebuffer to get image from + components: + Number of components to read. Default is 4 (RGBA). Valid values are 1, 2, 3, 4. - flip (bool): Flip the image upside down. This is useful because OpenGL - has the origin at the bottom left corner while PIL has it at the top left. + flip: + Flip the image upside down. This is useful because OpenGL has the + origin at the bottom left corner while PIL has it at the top left. """ mode = "RGBA"[:components] image = Image.frombuffer( diff --git a/arcade/geometry.py b/arcade/geometry.py index 97ed5d226..0f3b6deb8 100644 --- a/arcade/geometry.py +++ b/arcade/geometry.py @@ -18,11 +18,11 @@ def are_polygons_intersecting(poly_a: Point2List, poly_b: Point2List) -> bool: Check if two polygons intersect. Args: - poly_a (Point2List) : List of points that define the first polygon. - poly_b (Point2List): List of points that define the second polygon. + poly_a: List of points that define the first polygon. + poly_b: List of points that define the second polygon. Returns: - True if polygons intersect, False otherwise + ``True`` if polygons intersect, ``False`` otherwise """ # if either are [], they don't intersect if not poly_a or not poly_b: @@ -95,9 +95,9 @@ def get_triangle_orientation(p: Point2, q: Point2, r: Point2) -> int: * 2 --> Counterclockwise Args: - p (Point2): Point 1 - q (Point2): Point 2 - r (Point2): Point 3 + p: Point 1 + q: Point 2 + r: Point 3 Returns: int: 0, 1, or 2 depending on the orientation @@ -118,13 +118,13 @@ def are_lines_intersecting(p1: Point2, q1: Point2, p2: Point2, q2: Point2) -> bo returns true if the two lines intersect. Args: - p1 (Point2): Point 1 - q1 (Point2): Point 2 - p2 (Point2): Point 3 - q2 (Point2): Point 4 + p1: Point 1 + q1: Point 2 + p2: Point 3 + q2: Point 4 Returns: - bool: True or false depending if lines intersect + bool: ``True`` or ``False`` depending if lines intersect """ o1 = get_triangle_orientation(p1, q1, p2) o2 = get_triangle_orientation(p1, q1, q2) @@ -160,12 +160,12 @@ def is_point_in_polygon(x: float, y: float, polygon: Point2List) -> bool: Checks if a point is inside a polygon of three or more points. Args: - x (float): X coordinate of point - y (float): Y coordinate of point - polygon (Point2List): List of points that define the polygon. + x: X coordinate of point + y: Y coordinate of point + polygon: List of points that define the polygon. Returns: - bool: True or false depending if point is inside polygon + bool: ``True`` or ``False`` depending if point is inside polygon """ p = x, y n = len(polygon) diff --git a/arcade/joysticks.py b/arcade/joysticks.py index c87efbeac..40279956b 100644 --- a/arcade/joysticks.py +++ b/arcade/joysticks.py @@ -11,9 +11,6 @@ def get_joysticks() -> list[Joystick]: Get a list of all the game controllers This is an alias of :func:`get_game_controllers`, which is better worded. - - Returns: - List of game controllers """ return pyglet.input.get_joysticks() # type: ignore # pending https://github.com/pyglet/pyglet/issues/842 @@ -21,8 +18,5 @@ def get_joysticks() -> list[Joystick]: def get_game_controllers() -> list[Joystick]: """ Get a list of all the game controllers - - Returns: - List of game controllers """ return get_joysticks() diff --git a/arcade/math.py b/arcade/math.py index f916be6da..31e8390c1 100644 --- a/arcade/math.py +++ b/arcade/math.py @@ -42,8 +42,6 @@ def clamp(a, low: float, high: float) -> float: a (float): The number to clamp low (float): The lower bound high (float): The upper bound - Returns: - float: The clamped number """ return high if a > high else max(a, low) @@ -59,8 +57,6 @@ def lerp(v1: AsFloat, v2: AsFloat, u: float) -> float: v1 (float): The first value v2 (float): The second value u (float): The interpolation value `(0.0 to 1.0)` - Returns: - float: The interpolated value """ return v1 + ((v2 - v1) * u) @@ -73,8 +69,6 @@ def lerp_2d(v1: V_2D, v2: V_2D, u: float) -> tuple[float, float]: v1 (tuple[float, float]): The first point v2 (tuple[float, float]): The second point u (float): The interpolation value `(0.0 to 1.0)` - Returns: - tuple[float, float]: The interpolated 2D point """ return (lerp(v1[0], v2[0], u), lerp(v1[1], v2[1], u)) @@ -87,8 +81,6 @@ def lerp_3d(v1: V_3D, v2: V_3D, u: float) -> tuple[float, float, float]: v1 (tuple[float, float, float]): The first point v2 (tuple[float, float, float]): The second point u (float): The interpolation value `(0.0 to 1.0)` - Returns: - tuple[float, float, float]: The interpolated 3D point """ return (lerp(v1[0], v2[0], u), lerp(v1[1], v2[1], u), lerp(v1[2], v2[2], u)) @@ -102,9 +94,6 @@ def lerp_angle(start_angle: float, end_angle: float, u: float) -> float: start_angle (float): The starting angle end_angle (float): The ending angle u (float): The interpolation value (0.0 to 1.0) - - Returns: - float: The interpolated angle """ start_angle %= 360 end_angle %= 360 @@ -124,8 +113,6 @@ def rand_in_rect(rect: Rect) -> Point2: Args: rect (Rect): The rectangle to calculate the point in. - Returns: - Point2: The random point in the rectangle. """ return ( random.uniform(rect.left, rect.right), @@ -146,8 +133,6 @@ def rand_in_circle(center: Point2, radius: float) -> Point2: Args: center (Point2): The center of the circle radius (float): The radius of the circle - Returns: - Point2: A random point in the circle """ # random angle angle = 2 * math.pi * random.random() @@ -167,8 +152,6 @@ def rand_on_circle(center: Point2, radius: float) -> Point2: Args: center (Point2): The center of the circle radius (float): The radius of the circle - Returns: - Point2: A random point on the circle """ angle = 2 * math.pi * random.random() return (radius * math.cos(angle) + center[0], radius * math.sin(angle) + center[1]) @@ -181,8 +164,6 @@ def rand_on_line(pos1: Point2, pos2: Point2) -> Point: Args: pos1 (Point2): The first point pos2 (Point2): The second point - Returns: - Point: A random point on the line """ u = random.uniform(0.0, 1.0) return lerp_2d(pos1, pos2, u) @@ -202,8 +183,6 @@ def rand_angle_spread_deg(angle: float, half_angle_spread: float) -> float: Args: angle (float): The angle to spread from half_angle_spread (float): The half angle spread - Returns: - float: A random angle """ s = random.uniform(-half_angle_spread, half_angle_spread) return angle + s @@ -219,8 +198,6 @@ def rand_vec_spread_deg( angle (float): The angle to spread from half_angle_spread (float): The half angle spread length (float): The length of the vector - Returns: - tuple[float, float]: A random vector """ a = rand_angle_spread_deg(angle, half_angle_spread) vel = Vec2.from_polar(a, length) @@ -239,8 +216,6 @@ def rand_vec_magnitude( angle (float): The angle to spread from lo_magnitude (float): The lower magnitude hi_magnitude (float): The higher magnitude - Returns: - tuple[float, float]: A random vector """ mag = random.uniform(lo_magnitude, hi_magnitude) vel = Vec2.from_polar(angle, mag) @@ -256,8 +231,6 @@ def get_distance(x1: float, y1: float, x2: float, y2: float) -> float: y1 (float): y coordinate of the first point x2 (float): x coordinate of the second point y2 (float): y coordinate of the second point - Returns: - float: Distance between the two points """ return math.hypot(x1 - x2, y1 - y2) @@ -278,8 +251,6 @@ def rotate_point( cx (float): x value of the center point you want to rotate around cy (float): y value of the center point you want to rotate around angle_degrees (float): Angle, in degrees, to rotate - Returns: - tuple[float, float]: Return rotated (x, y) pair """ temp_x = x - cx temp_y = y - cy @@ -307,9 +278,6 @@ def get_angle_degrees(x1: float, y1: float, x2: float, y2: float) -> float: y1 (float): y coordinate of the first point x2 (float): x coordinate of the second point y2 (float): y coordinate of the second point - - Returns: - float: Angle in degrees between the two points """ x_diff = x2 - x1 y_diff = y2 - y1 @@ -325,9 +293,6 @@ def get_angle_radians(x1: float, y1: float, x2: float, y2: float) -> float: y1 (float): y coordinate of the first point x2 (float): x coordinate of the second point y2 (float): y coordinate of the second point - - Returns: - float: Angle in radians between the two points """ x_diff = x2 - x1 y_diff = y2 - y1 @@ -347,10 +312,6 @@ def quaternion_rotation(axis: Point3, vector: Point3, angle: float) -> tuple[flo axis (tuple[float, float, float]): The unit length vector that will be rotated around vector (tuple[float, float, float]): The 3-dimensional vector to be rotated angle (float): The angle in degrees to rotate the vector clock-wise by - - Returns: - tuple[float, float, float]: A rotated 3-dimension vector with the same length as - the argument vector. """ _rotation_rads = -math.radians(angle) p1, p2, p3 = vector diff --git a/arcade/paths.py b/arcade/paths.py index e11484835..08f2484d4 100644 --- a/arcade/paths.py +++ b/arcade/paths.py @@ -57,14 +57,20 @@ class _AStarGraph(object): """ A grid which tracks 2 barriers and a moving sprite. - Args: - barriers: Barriers to use in the AStarSearch Algorithm + barriers: + Barriers to use in the AStarSearch Algorithm. These are turned into a set. - left (int): Far left side x value - right (int): Far right side x value - bottom (int): Far bottom side y value - top (int): Far top side y value + left (int): + Far left side x value + right (int): + Far right side x value + bottom (int): + Far bottom side y value + top (int): + Far top side y value + diagonal_movement (bool): + Whether or not to use diagonals in the AStarSearch Algorithm """ def __init__( @@ -102,9 +108,10 @@ def get_vertex_neighbours(self, pos: Point) -> list[tuple[float, float]]: These are not guaranteed to be reachable or valid points. - :param pos: Which position to search around - - :return: Returns vertexes around the point + Args: + pos: Which position to search around + Returns: + Vertices around the point """ n = [] # Moves allow link a chess king @@ -124,13 +131,14 @@ def move_cost(self, a: Point, b: Point) -> float: A barrier's cost is float("inf) so that that the Algorithm will never go on it - :param a: The 1st point to compare - :param b: The 2nd point to compare - - :return: The move cost of moving between of the 2 points + Args: + a: The 1st point to compare + b: The 2nd point to compare + Returns: + The move cost of moving between of the 2 points """ if b in self.barriers: - return float("inf") # Infitely high cost to enter barrier squares + return float("inf") # Infinitely high cost to enter barrier squares elif a[0] == b[0] or a[1] == b[1]: return 1 # Normal movement cost @@ -144,10 +152,12 @@ def _AStarSearch(start: Point2, end: Point2, graph: _AStarGraph) -> list[Point2] Graph is used to check for barriers. - :param start: point to start at - :param end: point to end at - - :return: The path from start to end. Returns None if is path is not found + Args: + start: point to start at + end: point to end at + graph: Graph to use + Returns: + The path from start to end. Returns ``None`` if is path is not found """ G: dict[Point2, float] = dict() # Actual movement cost to each position from the start position F: dict[Point2, float] = ( @@ -230,26 +240,42 @@ class AStarBarrierList: A* path finding. Args: - moving_sprite (Sprite): Sprite that will be moving - blocking_sprites (SpriteList): Sprites that can block movement - grid_size (int): Size of the grid, in pixels - left (int): Left border of playing field - right (int): Right border of playing field - bottom (int): Bottom of playing field - top (int): Top of playing field - barrier_list (SpriteList): SpriteList of barriers to use in _AStarSearch, - None if not recalculated + moving_sprite: + Sprite that will be moving + blocking_sprites: + Sprites that can block movement + grid_size (int): + Size of the grid, in pixels + left (int): + Left border of playing field + right (int): + Right border of playing field + bottom (int): + Bottom of playing field + top (int): + Top of playing field + barrier_list: + SpriteList of barriers to use in _AStarSearch, + ``None`` if not recalculated Attributes: - grid_size (int): Grid size - bottom (int): Bottom of playing field - top (int): Top of playing field - left (int): Left border of playing field - right (int): Right border of playing field - moving_sprite (Sprite): Sprite that will be moving - blocking_sprites (SpriteList): Sprites that can block movement - barrier_list (SpriteList): SpriteList of barriers to use in _AStarSearch, - None if not recalculated + grid_size: + Grid size + bottom: + Bottom of playing field + top: + Top of playing field + left: + Left border of playing field + right: + Right border of playing field + moving_sprite: + Sprite that will be moving + blocking_sprites: + Sprites that can block movement + barrier_list: + SpriteList of barriers to use in _AStarSearch, + ``None`` if not recalculated """ def __init__( @@ -312,14 +338,17 @@ def astar_calculate_path( Calculates the path using AStarSearch Algorithm and returns the path Args: - start_point (Point): Where it starts - end_point (Point): Where it ends - astar_barrier_list (AStarBarrierList): AStarBarrierList with the boundaries to use in - the AStarSearch Algorithm - diagonal_movement (bool): Whether of not to use diagonals in the AStarSearch Algorithm + start_point: + Where it starts + end_point: + Where it ends + astar_barrier_list: + AStarBarrierList with the boundaries to use in the AStarSearch Algorithm + diagonal_movement: + Whether of not to use diagonals in the AStarSearch Algorithm Returns: - List[Point] or None: List of points (the path), or None if no path is found + List of points (the path), or ``None`` if no path is found """ grid_size = astar_barrier_list.grid_size @@ -362,11 +391,16 @@ def has_line_of_sight( very slowly! Args: - observer: Start position - target: End position position - walls: List of all blocking sprites - max_distance: Max distance point 1 can see - check_resolution: Check every x pixels for a sprite. + observer: + Start position + target: + End position position + walls: + List of all blocking sprites + max_distance: + Max distance point 1 can see + check_resolution: + Check every x pixels for a sprite. Trade-off between accuracy and speed. Returns: diff --git a/arcade/perf_graph.py b/arcade/perf_graph.py index 589e45f16..bf22977e2 100644 --- a/arcade/perf_graph.py +++ b/arcade/perf_graph.py @@ -33,20 +33,29 @@ class PerfGraph(arcade.Sprite): :class:`Texture ` every ``update_rate`` seconds. Args: - width (int): The width of the chart texture in pixels - height (int): The height of the chart texture in pixels - graph_data (str): The pyglet event handler or statistic to track - update_rate (float): How often the graph updates, in seconds - background_color (RGBA255): The background color of the chart - data_line_color (RGBA255): Color of the line tracking drawn - axis_color (RGBA255): The color to draw the x & y axes in - font_color (RGBA255): The color of the label font - font_size (int): The size of the label font in points - y_axis_num_lines (int): How many grid lines should be used to - divide the y scale of the graph. - view_y_scale_step (float): The graph's view area will be scaled to a - multiple of this value to fit to the data - currently displayed. + width (int): + The width of the chart texture in pixels + height (int): + The height of the chart texture in pixels + graph_data (str): + The pyglet event handler or statistic to track + update_rate (float): + How often the graph updates, in seconds + background_color (RGBA255): + The background color of the chart + data_line_color (RGBA255): + Color of the line tracking drawn + axis_color (RGBA255): + The color to draw the x & y axes in + font_color (RGBA255): + The color of the label font + font_size (int): + The size of the label font in points + y_axis_num_lines (int): + How many grid lines should be used to divide the y scale of the graph. + view_y_scale_step (float): + The graph's view area will be scaled to a multiple of this value to + fit to the data currently displayed. """ def __init__( @@ -73,6 +82,7 @@ def __init__( # not cache vertices, so there is no need to make this attribute # a property that updates geometry when set. self.line_color = Color.from_iterable(data_line_color) + """The color of the line tracking the data.""" # Store visual style info for cached pyglet shape geometry self._background_color = Color.from_iterable(background_color) @@ -86,6 +96,8 @@ def __init__( # Variables for rendering the data line self.graph_data = graph_data + """The graphed data type, either "FPS" or a pyglet event handler name.""" + self._data_to_graph: list[float] = [] self._view_max_value = 0.0 # We'll calculate this once we have data self._view_y_scale_step = view_y_scale_step @@ -227,7 +239,7 @@ def remove_from_sprite_lists(self) -> None: # garbage collection. pyglet.clock.unschedule(self.update) - def update_graph(self, delta_time: float): + def update_graph(self, delta_time: float) -> None: """ Update the graph by redrawing the internal texture data. diff --git a/arcade/perf_info.py b/arcade/perf_info.py index ad7b095c1..7b9e7c81d 100644 --- a/arcade/perf_info.py +++ b/arcade/perf_info.py @@ -4,15 +4,15 @@ from __future__ import annotations -import collections import time +from collections import deque import pyglet # Evil globals -_timings: dict = {} +_timings: dict[str, deque[float]] = {} _pyglets_dispatch_event = None -_frame_times: collections.deque = collections.deque() +_frame_times: deque = deque() _max_history: int = 100 __all__ = [ @@ -50,7 +50,7 @@ def _dispatch_event(self, *args) -> None: if name in _timings: data = _timings[name] else: - data = collections.deque() + data = deque() _timings[name] = data # Add out time to the list @@ -114,7 +114,7 @@ def clear_timings() -> None: _timings = {} -def get_timings() -> dict: +def get_timings() -> dict[str, deque[float]]: """ Get a dict of the current dispatch event timings. @@ -138,7 +138,9 @@ def enable_timings(max_history: int = 100) -> None: See :ref:`performance_statistics_example` for an example of how to use function. - :param max_history: How many frames to keep performance info for. + Args: + max_history: + How many frames to keep performance info for. """ global _pyglets_dispatch_event, _max_history diff --git a/arcade/physics_engines.py b/arcade/physics_engines.py index fcf1efe08..eeb65ac7a 100644 --- a/arcade/physics_engines.py +++ b/arcade/physics_engines.py @@ -37,7 +37,6 @@ def _wiggle_until_free(colliding: Sprite, walls: Iterable[SpriteList]) -> None: walls: A list of walls to guess our way out of. """ - # Original x & y of the moving object o_x, o_y = colliding.position @@ -106,7 +105,6 @@ def _move_sprite( A list of other individual sprites the ``moving_sprite`` collided with. """ - # See if we are starting this turn with a sprite already colliding with us. if len(check_for_collision_with_lists(moving_sprite, can_collide)) > 0: _wiggle_until_free(moving_sprite, can_collide) @@ -281,6 +279,7 @@ def _move_sprite( def _add_to_list(dest: list[SpriteList], source: SpriteList | Iterable[SpriteList] | None) -> None: + """Helper function to add a SpriteList or list of SpriteLists to a list.""" if not source: return elif isinstance(source, SpriteList): @@ -648,7 +647,7 @@ def can_jump(self, y_distance: float = 5) -> bool: .. warning:: This runs collisions **every** time it is called! If you are thinking of calling this repeatedly, first double-check - whether you can store the returne value to a local variable instead. + whether you can store the returned value to a local variable instead. The player can jump when at least one of the following are true: after updating state: diff --git a/arcade/pymunk_physics_engine.py b/arcade/pymunk_physics_engine.py index 915fc501d..72d757820 100644 --- a/arcade/pymunk_physics_engine.py +++ b/arcade/pymunk_physics_engine.py @@ -138,7 +138,7 @@ class PymunkPhysicsEngine: def __init__( self, gravity=(0, 0), damping: float = 1.0, maximum_incline_on_ground: float = 0.708 - ): + ) -> None: # -- Pymunk self.space = pymunk.Space() self.space.gravity = gravity @@ -163,7 +163,7 @@ def add_sprite( max_vertical_velocity: int | None = None, radius: float = 0, collision_type: str | None = "default", - ): + ) -> None: """Add a sprite to the physics engine. Args: @@ -362,8 +362,64 @@ def add_sprite_list( body_type: int = DYNAMIC, damping: float | None = None, collision_type: str | None = None, - ): - """Add all sprites in a sprite list to the physics engine.""" + ) -> None: + """ + Add all sprites in a sprite list to the physics engine. + + Args: + sprite_list: + A list of sprites to add + mass: + The mass of the object (Defaults to ``1.0``). + friction: + How much the object resists sliding against surfaces: + + .. list-table:: + :header-rows: 0 + + * - ``0.0`` + - Absolutely slippery with no resistance at all + * - ``0.2`` + - Default (Waxed wood on very wet snow) + * - ``friction > 1.0`` + - Very rough + + *Higher values may not make a meaningful difference.* + + See :py:attr:`pymunk.Shape.friction` to learn more. + + elasticity: + How bouncy the object is. + + .. list-table:: + :header-rows: 0 + + * - ``0.0`` + - No bounce + * - ``0.99`` + - Very bouncy + * - ``elasticity >= 1.0`` + - May behave badly (breaks conservation of energy) + + See :py:attr:`pymunk.Shape.elasticity` to learn more. + + moment_of_inertia: + How much force is needed to change the object's rotation ( + pass :py:attr:`MOMENT_INF` or ``float('inf')`` to "lock" + its angle). + + See :py:attr:`pymunk.Shape.moment_of_inertia` to learn more. + + body_type: + :py:attr:`DYNAMIC` (default), :py:attr:`KINEMATIC`, or + :py:attr:`STATIC`. + damping: + Like air resistance. See the :py:class:`.PymunkPhysicsEngine` + top-level doc. + collision_type: + Assign a collision name to this sprite. It will be used + by :py:meth:`add_collision_handler` if called. + """ for sprite in sprite_list: self.add_sprite( sprite=sprite, @@ -376,7 +432,7 @@ def add_sprite_list( collision_type=collision_type, ) - def remove_sprite(self, sprite: Sprite): + def remove_sprite(self, sprite: Sprite) -> None: """Remove a sprite from the physics engine.""" physics_object = self.sprites[sprite] self.space.remove(physics_object.body) # type: ignore @@ -421,7 +477,7 @@ def is_on_ground(self, sprite: Sprite) -> bool: grounding = self.check_grounding(sprite) return grounding["body"] is not None - def apply_impulse(self, sprite: Sprite, impulse: tuple[float, float]): + def apply_impulse(self, sprite: Sprite, impulse: tuple[float, float]) -> None: """Apply an impulse force on a sprite""" physics_object = self.get_physics_object(sprite) if physics_object.body is None: @@ -448,7 +504,7 @@ def set_position(self, sprite: Sprite, position: pymunk.Vec2d | tuple[float, flo ) physics_object.body.position = position - def set_rotation(self, sprite: Sprite, rotation: float): + def set_rotation(self, sprite: Sprite, rotation: float) -> None: physics_object = self.get_physics_object(sprite) if physics_object.body is None: raise PymunkException( @@ -456,7 +512,7 @@ def set_rotation(self, sprite: Sprite, rotation: float): ) physics_object.body.angle = math.radians(rotation) - def set_velocity(self, sprite: Sprite, velocity: tuple[float, float]): + def set_velocity(self, sprite: Sprite, velocity: tuple[float, float]) -> None: """Directly set the velocity of a sprite known to the engine. .. warning:: Avoid using this on any :py:attr:`DYNAMIC` objects! @@ -486,8 +542,18 @@ def add_collision_handler( pre_handler: Callable | None = None, post_handler: Callable | None = None, separate_handler: Callable | None = None, - ): - """Add code to handle collisions between objects.""" + ) -> None: + """ + Add code to handle collisions between objects. + + Args: + first_type: The first type of object to check for collisions. + second_type: The second type of object to check for collisions. + begin_handler: Function to call when a collision begins. + pre_handler: Function to call before a collision is resolved. + post_handler: Function to call after a collision is resolved. + separate_handler: Function to call when two objects + """ if first_type not in self.collision_types: # LOG.debug(f"Adding new collision type of {first_type}.") @@ -531,7 +597,7 @@ def _f4(arbiter, space, data): if separate_handler: h.separate = _f4 - def resync_sprites(self): + def resync_sprites(self) -> None: """ Set visual sprites to be the same location as physics engine sprites. Call this after stepping the pymunk physics engine @@ -566,18 +632,18 @@ def resync_sprites(self): # Notify sprite we moved, in case animation needs to be updated sprite.pymunk_moved(self, dx, dy, d_angle) - def step(self, delta_time: float = 1 / 60.0, resync_sprites: bool = True): + def step(self, delta_time: float = 1 / 60.0, resync_sprites: bool = True) -> None: """ Tell the physics engine to perform calculations. - :param delta_time: Time to move the simulation forward. Keep this - value constant, do not use varying values for - each step. - :param resync_sprites: Resynchronize Arcade graphical sprites to be - at the same location as their Pymunk counterparts. - If running multiple steps per frame, set this to - false for the first steps, and true for the last - step that's part of the update. + Args: + delta_time: Time to move the simulation forward. Keep this + value constant, do not use varying values for each step. + resync_sprites: Resynchronize Arcade graphical sprites to be + at the same location as their Pymunk counterparts. + If running multiple steps per frame, set this to + false for the first steps, and true for the last + step that's part of the update. """ # Update physics # Use a constant time step, don't use delta_time @@ -588,11 +654,25 @@ def step(self, delta_time: float = 1 / 60.0, resync_sprites: bool = True): self.resync_sprites() def get_physics_object(self, sprite: Sprite) -> PymunkPhysicsObject: - """Get the shape/body for a sprite.""" + """ + Get the shape/body for a sprite. + + Args: + sprite: + The sprite to get the physics object for. + """ return self.sprites[sprite] def apply_force(self, sprite: Sprite, force: tuple[float, float]): - """Apply force to a Sprite.""" + """ + Apply force to a Sprite. + + Args: + sprite: + The sprite to apply the force to. + force: + The force to apply to the sprite. + """ physics_object = self.sprites[sprite] if physics_object.body is None: raise PymunkException( @@ -600,8 +680,16 @@ def apply_force(self, sprite: Sprite, force: tuple[float, float]): ) physics_object.body.apply_force_at_local_point(force, (0, 0)) - def set_horizontal_velocity(self, sprite: Sprite, velocity: float): - """Set a sprite's velocity""" + def set_horizontal_velocity(self, sprite: Sprite, velocity: float) -> None: + """ + Set a sprite's velocity. + + Args: + sprite: + The sprite to set the velocity for. + velocity: + The velocity to set the sprite to. + """ physics_object = self.sprites[sprite] if physics_object.body is None: raise PymunkException( @@ -611,7 +699,7 @@ def set_horizontal_velocity(self, sprite: Sprite, velocity: float): new_cv = (velocity, cv[1]) physics_object.body.velocity = new_cv - def set_friction(self, sprite: Sprite, friction: float): + def set_friction(self, sprite: Sprite, friction: float) -> None: """Set the friction a sprite experiences against other surfaces. This is how "rough" a sprite is during a collision with others: @@ -630,6 +718,12 @@ def set_friction(self, sprite: Sprite, friction: float): of the :ref:`pymunk_platformer_tutorial` * `Simple Wikipedia's Article on Friction`_ * :py:attr:`pymunk.Poly.friction` + + Args: + sprite: + The sprite to set the friction for. + friction: + How much the object resists sliding against surfaces. """ physics_object = self.sprites[sprite] if physics_object.shape is None: @@ -638,7 +732,7 @@ def set_friction(self, sprite: Sprite, friction: float): ) physics_object.shape.friction = friction - def apply_opposite_running_force(self, sprite: Sprite): + def apply_opposite_running_force(self, sprite: Sprite) -> None: """ If a sprite goes left while on top of a dynamic sprite, that sprite should get pushed to the right. @@ -651,8 +745,13 @@ def apply_opposite_running_force(self, sprite: Sprite): if body.force[0] and grounding and grounding["body"]: grounding["body"].apply_force_at_world_point((-body.force[0], 0), grounding["position"]) - def check_grounding(self, sprite: Sprite): - """See if the player is on the ground. Used to see if we can jump.""" + def check_grounding(self, sprite: Sprite) -> dict: + """ + See if the player is on the ground. Used to see if we can jump. + + Args: + sprite: The sprite to check if it is on the ground. + """ grounding = { "normal": pymunk.Vec2d.zero(), "penetration": pymunk.Vec2d.zero(), diff --git a/arcade/scene.py b/arcade/scene.py index cbc164f05..364e8f6c5 100644 --- a/arcade/scene.py +++ b/arcade/scene.py @@ -41,7 +41,8 @@ class SceneKeyError(KeyError): The main purpose of this class is to help arcade's developers keep error messages consistent. - :param name: the name of the missing :py:class:`~arcade.SpriteList` + Args: + name: the name of the missing :py:class:`~arcade.SpriteList` """ def __init__(self, name: str): @@ -93,9 +94,10 @@ def __delitem__(self, sprite_list: int | str | SpriteList) -> None: * :py:meth:`.remove_sprite_list_by_name` * :py:meth:`.remove_sprite_list_by_object` - :param sprite_list: - The index, name, or :py:class:`~arcade.SpriteList` instance to remove from - this scene. + Args: + sprite_list: + The index, name, or :py:class:`~arcade.SpriteList` instance to remove from + this scene. """ if isinstance(sprite_list, int): self.remove_sprite_list_by_index(sprite_list) @@ -112,8 +114,9 @@ def from_tilemap(cls, tilemap: TileMap) -> "Scene": The SpriteLists will use the layer names and ordering as defined in the Tiled file. - :param tilemap: The :py:class:`~arcade.tilemap.TileMap` - object to create the scene from. + Args: + tilemap: The :py:class:`~arcade.tilemap.TileMap` + object to create the scene from. """ scene = cls() for name, sprite_list in tilemap.sprite_lists.items(): @@ -130,7 +133,8 @@ def get_sprite_list(self, name: str) -> SpriteList: * directly accessing ``scene_instance._name_mapping``, although this will get flagged by linters as bad style. - :param name: The name of the sprite list to retrieve. + Args: + name: The name of the sprite list to retrieve. """ return self._name_mapping[name] @@ -141,7 +145,8 @@ def __getitem__(self, key: str) -> SpriteList: This is here for ease of use to make sub-scripting the scene object directly to retrieve a SpriteList possible. - :param key: The name of the sprite list to retrieve + Args: + key: The name of the sprite list to retrieve """ if key in self._name_mapping: return self._name_mapping[key] @@ -163,8 +168,9 @@ def add_sprite(self, name: str, sprite: Sprite) -> None: * :py:meth:`.add_sprite_list` * :py:meth:`.add_sprite_list_after` - :param name: The name of the sprite list to add to or create. - :param sprite: The sprite to add. + Args: + name: The name of the sprite list to add to or create. + sprite: The sprite to add. """ if name in self._name_mapping: self._name_mapping[name].append(sprite) @@ -187,10 +193,11 @@ def add_sprite_list( If no SpriteList is supplied via the ``sprite_list`` parameter then a new one will be created, and the ``use_spatial_hash`` parameter will be respected for that creation. - :param name: The name to give the new layer. - :param use_spatial_hash: If creating a new sprite list, whether - to enable spatial hashing on it. - :param sprite_list: Use a specific sprite list rather than creating a new one. + Args: + name: The name to give the new layer. + use_spatial_hash: If creating a new sprite list, whether + to enable spatial hashing on it. + sprite_list: Use a specific sprite list rather than creating a new one. """ if sprite_list is None: sprite_list = SpriteList(use_spatial_hash=use_spatial_hash) @@ -219,13 +226,13 @@ def add_sprite_list_before( The added sprite list will be drawn under the sprite list named in ``before``. - :param name: The name to give the new layer. - :param before: The name of the layer to place the new - one before. - :param use_spatial_hash: If creating a new sprite list, selects - whether to enable spatial hashing. - :param sprite_list: If a sprite list is passed via - this argument, it will be used instead of creating a new one. + Args: + name: The name to give the new layer. + before: The name of the layer to place the new one before. + use_spatial_hash: If creating a new sprite list, selects + whether to enable spatial hashing. + sprite_list: If a sprite list is passed via + this argument, it will be used instead of creating a new one. """ if sprite_list is None: sprite_list = SpriteList(use_spatial_hash=use_spatial_hash) @@ -252,8 +259,9 @@ def move_sprite_list_before( or ``before`` contain a name not currently in the scene. This exception can be handled as a :py:class:`KeyError`. - :param name: The name of the SpriteList to move. - :param before: The name of the SpriteList to place it before. + Args: + name: The name of the SpriteList to move. + before: The name of the SpriteList to place it before. """ if name not in self._name_mapping: raise SceneKeyError(name) @@ -283,12 +291,13 @@ def add_sprite_list_after( The added sprite list will be drawn above the sprite list named in ``after``. - :param name: The name to give the layer. - :param after: The name of the layer to place the new one after. - :param use_spatial_hash: If creating a new sprite list, selects - whether to enable spatial hashing. - :param sprite_list: If a sprite list is passed via - this argument, it will be used instead of creating a new one. + Args: + name: The name to give the layer. + after: The name of the layer to place the new one after. + use_spatial_hash: If creating a new sprite list, selects + whether to enable spatial hashing. + sprite_list: If a sprite list is passed via + this argument, it will be used instead of creating a new one. """ if sprite_list is None: sprite_list = SpriteList(use_spatial_hash=use_spatial_hash) @@ -315,8 +324,9 @@ def move_sprite_list_after( or ``after`` contain a name not currently in the scene. This exception can be handled as a :py:class:`KeyError`. - :param name: The name of the SpriteList to move. - :param after: The name of the SpriteList to place it after. + Args: + name: The name of the SpriteList to move. + after: The name of the SpriteList to place it after. """ if name not in self._name_mapping: raise SceneKeyError(name) @@ -334,7 +344,8 @@ def remove_sprite_list_by_index(self, index: int) -> None: """ Remove a layer from the scene by its index in the draw order. - :param index: The index of the sprite list to remove. + Args: + index: The index of the sprite list to remove. """ self.remove_sprite_list_by_object(self._sprite_lists[index]) @@ -348,7 +359,8 @@ def remove_sprite_list_by_name( A :py:class:`KeyError` will be raised if the SpriteList is not in the scene. - :param name: The name of the sprite list to remove. + Args: + name: The name of the sprite list to remove. """ sprite_list = self._name_mapping[name] self._sprite_lists.remove(sprite_list) @@ -361,7 +373,8 @@ def remove_sprite_list_by_object(self, sprite_list: SpriteList) -> None: A :py:class:`ValueError` will be raised if the passed sprite list is not in the scene. - :param sprite_list: The sprite list to remove. + Args: + sprite_list: The sprite list to remove. """ self._sprite_lists.remove(sprite_list) self._name_mapping = { @@ -386,8 +399,11 @@ def update( lists will be drawn in the order of the passed iterable. If a name is not in the scene, a :py:class:`KeyError` will be raised. - :param delta_time: The time step to update by in seconds. - :param names: Which layers & what order to update them in. + Args: + delta_time: The time step to update by in seconds. + names: Which layers & what order to update them in. + *args: Additional positional arguments propagated down to sprites + **kwargs: Additional keyword arguments propagated down to sprites """ # Due to api changes in 3.0 we sanity check delta_time if not isinstance(delta_time, (int, float)): @@ -423,8 +439,11 @@ def update_animation( lists will be drawn in the order of the passed iterable. If a name is not in the scene, a :py:class:`KeyError` will be raised. - :param delta_time: The time step to update by in seconds. - :param names: Which layers & what order to update them in. + Args: + delta_time: The time step to update by in seconds. + names: Which layers & what order to update them in. + *args: Additional positional arguments propagated down to sprites + **kwargs: Additional keyword arguments propagated down to sprites """ if names: for name in names: @@ -458,17 +477,16 @@ def draw( ``**kwargs`` option is for advanced users who have subclassed :py:class:`~arcade.SpriteList`. - :param names: Which layers to draw & what order to draw them in. - :param filter: Optional parameter to set OpenGL filter, such as - ``gl.GL_NEAREST`` to avoid smoothing. - :param pixelated: ``True`` for pixel art and ``False`` for - smooth scaling. - :param blend_function: - Use the specified OpenGL blend function while drawing the - sprite list, such as ``arcade.Window.ctx.BLEND_ADDITIVE`` - or ``arcade.Window.ctx.BLEND_DEFAULT``. + Args: + names: Which layers to draw & what order to draw them in. + filter: Optional parameter to set OpenGL filter, such as + ``gl.GL_NEAREST`` to avoid smoothing. + pixelated: ``True`` for pixel art and ``False`` for smooth scaling. + blend_function: + Use the specified OpenGL blend function while drawing the + sprite list, such as ``arcade.Window.ctx.BLEND_ADDITIVE`` + or ``arcade.Window.ctx.BLEND_DEFAULT``. """ - if names: for name in names: self._name_mapping[name].draw( @@ -496,11 +514,11 @@ def draw_hit_boxes( If `names` is not provided, then every layer's hit boxes will be drawn in the order specified. - :param color: The RGBA color to use to draw the hit boxes with. - :param line_thickness: How many pixels thick the hit box outlines should be - :param names: Which layers & what order to draw their hit boxes in. + Args: + color: The RGBA color to use to draw the hit boxes with. + line_thickness: How many pixels thick the hit box outlines should be + names: Which layers & what order to draw their hit boxes in. """ - if names: for name in names: self._name_mapping[name].draw_hit_boxes(color, line_thickness) diff --git a/arcade/screenshot.py b/arcade/screenshot.py index 364184d1b..8ec355b5c 100644 --- a/arcade/screenshot.py +++ b/arcade/screenshot.py @@ -16,14 +16,12 @@ def get_pixel(x: int, y: int, components: int = 3) -> tuple[int, ...]: """ Given an x, y, will return a color value of that point. - :param x: x location - :param y: y location - :param components: Number of components to fetch. By default we fetch 3 - 3 components (RGB). 4 components would be RGBA. - + Args: + x: x location + y: y location + components: Number of components to fetch. By default we fetch 3 + 3 components (RGB). 4 components would be RGBA. """ - # noinspection PyCallingNonCallable,PyTypeChecker - # The window may be 'scaled' on hi-res displays. Particularly Macs. OpenGL # won't account for this, so we need to. window = get_window() @@ -53,11 +51,12 @@ def get_image( image = arcade.get_image() image.save('screenshot.png') - :param x: Start (left) x location - :param y: Start (bottom) y location - :param width: Width of image. Leave blank for grabbing the 'rest' of the image - :param height: Height of image. Leave blank for grabbing the 'rest' of the image - :param components: Number of components to fetch. By default we fetch 4 (4=RGBA, 3=RGB) + Args: + x: Start (left) x location + y: Start (bottom) y location + width: Width of image. Leave blank for grabbing the 'rest' of the image + height: Height of image. Leave blank for grabbing the 'rest' of the image + components: Number of components to fetch. By default we fetch 4 (4=RGBA, 3=RGB) """ window = get_window() ctx = window.ctx diff --git a/arcade/sections.py b/arcade/sections.py index 6ab1eeff5..cf8ff7f5e 100644 --- a/arcade/sections.py +++ b/arcade/sections.py @@ -21,34 +21,35 @@ class Section: A Section represents a rectangular portion of the viewport Events are dispatched to the section based on it's position on the screen. - :param left: the left position of this section - :param bottom: the bottom position of this section - :param width: the width of this section - :param height: the height of this section - :param name: the name of this section - :param bool | Iterable accept_keyboard_keys: whether or not this section - captures keyboard keys through. keyboard events. If the param is an iterable - means the keyboard keys that are captured in press/release events: - for example: ``[arcade.key.UP, arcade.key.DOWN]`` will only capture this two keys - :param bool Iterable accept_mouse_events: whether or not this section - captures mouse events. If the param is an iterable means the mouse events - that are captured. for example: ``['on_mouse_press', 'on_mouse_release']`` - will only capture this two events. - :param prevent_dispatch: a list of event names that will not be dispatched to subsequent - sections. You can pass None (default) or {True} to prevent the dispatch of all events. - :param prevent_dispatch_view: a list of event names that will not be dispatched to the view. - You can pass None (default) or {True} to prevent the dispatch of all events to the view. - :param local_mouse_coordinates: if True the section mouse events will receive x, y - coordinates section related to the section dimensions and position (not related - to the screen) - :param enabled: if False the section will not capture any events - :param modal: if True the section will be a modal section: will prevent updates - and event captures on other sections. Will also draw last (on top) but capture - events first. - :param draw_order: The order this section will have when on_draw is called. - The lower the number the earlier this will get draw. - This can be different from the event capture order or the on_update order which - is defined by the insertion order. + Args: + left: the left position of this section + bottom: the bottom position of this section + width: the width of this section + height: the height of this section + name: the name of this section + bool | Iterable accept_keyboard_keys: whether or not this section + captures keyboard keys through. keyboard events. If the param is an iterable + means the keyboard keys that are captured in press/release events: + for example: ``[arcade.key.UP, arcade.key.DOWN]`` will only capture this two keys + bool Iterable accept_mouse_events: whether or not this section + captures mouse events. If the param is an iterable means the mouse events + that are captured. for example: ``['on_mouse_press', 'on_mouse_release']`` + will only capture this two events. + prevent_dispatch: a list of event names that will not be dispatched to subsequent + sections. You can pass None (default) or {True} to prevent the dispatch of all events. + prevent_dispatch_view: a list of event names that will not be dispatched to the view. + You can pass None (default) or {True} to prevent the dispatch of all events to the view. + local_mouse_coordinates: if True the section mouse events will receive x, y + coordinates section related to the section dimensions and position (not related + to the screen) + enabled: if False the section will not capture any events + modal: if True the section will be a modal section: will prevent updates + and event captures on other sections. Will also draw last (on top) but capture + events first. + draw_order: The order this section will have when on_draw is called. + The lower the number the earlier this will get draw. + This can be different from the event capture order or the on_update order which + is defined by the insertion order. """ def __init__( @@ -68,8 +69,8 @@ def __init__( modal: bool = False, draw_order: int = 1, ): - # name of the section self.name: str | None = name + """The name of this section""" # parent view: set by the SectionManager. Protected, you should not change # section.view manually @@ -83,20 +84,23 @@ def __init__( # set draw_order: the lower the number the earlier this section will get draw self._draw_order: int = draw_order - # if True 'update' and 'on_update' will not trigger in this section self.block_updates: bool = False + """if True 'update' and 'on_update' will not trigger in this section""" - # arcade keyboard keys to accept. self.accept_keyboard_keys: bool | Iterable = accept_keyboard_keys - # arcade mouse events to accept. + """arcade keyboard keys to accept.""" + self.accept_mouse_events: bool | Iterable = accept_mouse_events + """arcade mouse events to accept.""" - # prevents events to propagate self.prevent_dispatch: Iterable = prevent_dispatch or {True} - # prevents events to propagate to the view + """prevents events to propagate""" + self.prevent_dispatch_view: Iterable = prevent_dispatch_view or {True} - # mouse coordinates relative to section + """prevents events to propagate to the view""" + self.local_mouse_coordinates: bool = local_mouse_coordinates + """mouse coordinates relative to section""" # section position into the current viewport # if screen is resized it's upto the user to move or resize each section @@ -115,8 +119,8 @@ def __init__( self._ec_bottom: int = 0 if self._modal else self._bottom self._ec_top: int = self.window.height if self._modal else self._top - # optional section camera self.camera: Projector | None = None + """optional section camera""" def __repr__(self): name = f"Section {self.name}" if self.name else "Section" @@ -246,6 +250,7 @@ def top(self, value: int): @property def rect(self) -> Rect: + """The section rectangle of this view""" return LRBT(self.left, self.right, self.bottom, self.top) @property @@ -257,7 +262,11 @@ def window(self): return self._view.window def overlaps_with(self, section: "Section") -> bool: - """Checks if this section overlaps with another section""" + """Checks if this section overlaps with another section + + Args: + section: The section to check for overlap + """ return not ( self.right < section.left or self.left > section.right @@ -266,68 +275,166 @@ def overlaps_with(self, section: "Section") -> bool: ) def mouse_is_on_top(self, x: int, y: int) -> bool: - """Check if the current mouse position is on top of this section""" + """Check if the current mouse position is on top of this section + + Args: + x: The x position of the mouse + y: The y position of the mouse + """ test_x = self._left <= x <= self._right test_y = self._bottom <= y <= self._top return test_x and test_y def should_receive_mouse_event(self, x: int, y: int) -> bool: - """Check if the current section should receive a mouse event at a given position""" + """Check if the current section should receive a mouse event at a given position + + Args: + x: The x position of the mouse + y: The y position of the mouse + """ test_x = self._ec_left <= x <= self._ec_right test_y = self._ec_bottom <= y <= self._ec_top return test_x and test_y def get_xy_screen_relative(self, section_x: int, section_y: int): - """Returns screen coordinates from section coordinates""" + """Returns screen coordinates from section coordinates + + Args: + section_x: The x position of the section + section_y: The y position of the section + """ return self.left + section_x, self.bottom + section_y def get_xy_section_relative(self, screen_x: int, screen_y: int): - """returns section coordinates from screen coordinates""" + """returns section coordinates from screen coordinates + + Args: + screen_x: The x position of the screen + screen_y: The y position of the screen + """ return screen_x - self.left, screen_y - self.bottom # Following methods are just the usual view methods # + on_mouse_enter / on_mouse_leave / on_show_section / on_hide_section def on_draw(self): + """Override this method with your custom drawing code.""" pass def on_update(self, delta_time: float): + """Override this method with your custom update code.""" pass def on_resize(self, width: int, height: int): + """Override this method with your custom resize code.""" pass def on_mouse_press(self, x: int, y: int, button: int, modifiers: int): + """ + Called when the user presses a mouse button. + + Args: + x: x position of the mouse + y: y position of the mouse + button: the button pressed + modifiers: the modifiers pressed + """ pass def on_mouse_release(self, x: int, y: int, button: int, modifiers: int): + """ + Called when the user releases a mouse button. + + Args: + x: x position of the mouse + y: y position of the mouse + button: the button released + modifiers: the modifiers pressed + """ pass def on_mouse_motion(self, x: int, y: int, dx: int, dy: int): + """ + Called when the user moves the mouse. + + Args: + x: x position of the mouse + y: y position of the mouse + dx: change in x position + dy: change in y position + """ pass def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int): + """ + Called when the user scrolls the mouse wheel. + + Args: + x: x position of the mouse + y: y position of the mouse + scroll_x: change in x position + scroll_y: change in y position + """ pass def on_mouse_drag(self, x: int, y: int, dx: int, dy: int, _buttons: int, _modifiers: int): + """ + Called when the user moves the mouse with a button pressed. + + Args: + x: x position of the mouse + y: y position of the mouse + dx: change in x position + dy: change in y position + """ self.on_mouse_motion(x, y, dx, dy) def on_mouse_enter(self, x: int, y: int): + """ + Called when the mouse enters the section + + Args: + x: x position of the mouse + y: y position of the mouse + """ pass def on_mouse_leave(self, x: int, y: int): + """ + Called when the mouse leaves the section + + Args: + x: x position of the mouse + y: y position of the mouse + """ pass def on_key_press(self, symbol: int, modifiers: int): + """ + Called when the user presses a key. + + Args: + symbol: the key pressed + modifiers: the modifiers pressed + """ pass def on_key_release(self, _symbol: int, _modifiers: int): + """ + Called when the user releases a key. + + Args: + symbol: the key released + modifiers: the modifiers pressed + """ pass def on_show_section(self): + """Called when the section is shown""" pass def on_hide_section(self): + """Called when the section is hidden""" pass @@ -335,10 +442,13 @@ class SectionManager: """ This manages the different Sections a View has. Actions such as dispatching the events to the correct Section, draw order, etc. + + Args: + view: the view this section manager belongs to """ - def __init__(self, view: "View"): - self.view: "View" = view # the view this section manager belongs to + def __init__(self, view: View): + self.view = view # the view this section manager belongs to # store sections in update/event order and in draw order # a list of the current sections for this in update/event order @@ -418,8 +528,11 @@ def enable(self) -> None: def get_section_by_name(self, name: str) -> Section | None: """ Returns the first section with the given name - :param name: the name of the section you want - :return: the first section with the provided name. None otherwise + + Args: + name: The name of the section you want + Returns: + The first section with the provided name. None otherwise """ for section in self._sections: if section.name == name: @@ -428,7 +541,7 @@ def get_section_by_name(self, name: str) -> Section | None: def add_section( self, - section: "Section", + section: Section, at_index: int | None = None, at_draw_order: int | None = None, ) -> None: @@ -436,11 +549,12 @@ def add_section( Adds a section to this Section Manager Will trigger section.on_show_section if section is enabled - :param section: The section to add to this section manager - :param at_index: Inserts the section at that index for event capture and update events. - If None at the end - :param at_draw_order: Inserts the section in a specific draw order. - Overwrites section.draw_order + Args: + section: The section to add to this section manager + at_index: Inserts the section at that index for event capture and update events. + If None at the end + at_draw_order: Inserts the section in a specific draw order. + Overwrites section.draw_order """ if not isinstance(section, Section): raise ValueError("You can only add Section instances") @@ -464,7 +578,8 @@ def remove_section(self, section: Section) -> None: """ Removes a section from this section manager - :param section: the section to remove + Args: + section: The section to remove """ # trigger on_hide_section if the view is the current one and section is enabled @@ -506,7 +621,8 @@ def on_update(self, delta_time: float) -> None: """ Called on each event loop. - :param delta_time: the delta time since this method was called last time + Args: + delta_time: the delta time since this method was called last time """ modal_present = False if self.view_update_first is True: @@ -547,8 +663,9 @@ def on_resize(self, width: int, height: int) -> None: """ Called when the window is resized. - :param width: the new width of the screen - :param height: the new height of the screen + Args: + width: the new width of the screen + height: the new height of the screen """ # The Default camera auto-resizes. if self.view_resize_first is True: @@ -568,11 +685,13 @@ def get_first_section(self, x: int, y: int, *, event_capture: bool = True) -> Se """ Returns the first section based on x,y position - :param x: the x axis coordinate - :param y: the y axis coordinate - :param event_capture: True will use event capture dimensions, - False will use section draw size - :return: a section if match the params otherwise None + Args: + x: the x axis coordinate + y: the y axis coordinate + event_capture: True will use event capture dimensions, + False will use section draw size + Returns: + A section if match the params otherwise None """ for section in self._sections: if section.enabled: @@ -588,11 +707,13 @@ def get_sections( """ Returns a list of sections based on x,y position - :param x: the x axis coordinate - :param y: the y axis coordinate - :param event_capture: True will use event capture dimensions, - False will use section draw size - :return: a generator with the sections that match the params + Args: + x: the x axis coordinate + y: the y axis coordinate + event_capture: True will use event capture dimensions, + False will use section draw size + Returns: + A generator with the sections that match the params """ for section in self._sections: if section.enabled: @@ -613,15 +734,17 @@ def dispatch_mouse_event( """ Generic method to dispatch mouse events to the correct Sections - :param event: the mouse event name to dispatch - :param x: the x axis coordinate - :param y: the y axis coordinate - :param args: any other position arguments that should be delivered to the dispatched event - :param current_section: the section this mouse event should be delivered to. - If None, will retrieve all - sections that should receive this event based on x, y coordinates - :param kwargs: any other keyword arguments that should be delivered to the dispatched event - :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns + Args: + event: the mouse event name to dispatch + x: the x axis coordinate + y: the y axis coordinate + args: any other position arguments that should be delivered to the dispatched event + current_section: the section this mouse event should be delivered to. + If None, will retrieve all + sections that should receive this event based on x, y coordinates + kwargs: any other keyword arguments that should be delivered to the dispatched event + Returns: + ``EVENT_HANDLED`` or ``EVENT_UNHANDLED``, or whatever the dispatched method returns """ sections: list | Generator @@ -682,10 +805,12 @@ def dispatch_keyboard_event(self, event: str, *args, **kwargs) -> bool | None: """ Generic method to dispatch keyboard events to the correct sections - :param event: the keyboard event name to dispatch - :param args: any other position arguments that should be delivered to the dispatched event - :param kwargs: any other keyword arguments that should be delivered to the dispatched event - :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns + Args: + event: the keyboard event name to dispatch + args: any other position arguments that should be delivered to the dispatched event + kwargs: any other keyword arguments that should be delivered to the dispatched event + Returns: + ``EVENT_HANDLED`` or ``EVENT_UNHANDLED``, or whatever the dispatched method returns """ propagate_to_view = True prevent_dispatch = EVENT_UNHANDLED @@ -729,11 +854,13 @@ def on_mouse_press(self, x: int, y: int, *args, **kwargs) -> bool | None: """ Triggers the on_mouse_press event on the appropriate sections or view - :param x: the x axis coordinate - :param y: the y axis coordinate - :param args: any other position arguments that should be delivered to the dispatched event - :param kwargs: any other keyword arguments that should be delivered to the dispatched event - :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns + Args: + x: the x axis coordinate + y: the y axis coordinate + args: any other position arguments that should be delivered to the dispatched event + kwargs: any other keyword arguments that should be delivered to the dispatched event + Returns: + ``EVENT_HANDLED`` or ``EVENT_UNHANDLED``, or whatever the dispatched method returns """ return self.dispatch_mouse_event("on_mouse_press", x, y, *args, **kwargs) @@ -741,11 +868,13 @@ def on_mouse_release(self, x: int, y: int, *args, **kwargs) -> bool | None: """ Triggers the on_mouse_release event on the appropriate sections or view - :param x: the x axis coordinate - :param y: the y axis coordinate - :param args: any other position arguments that should be delivered to the dispatched event - :param kwargs: any other keyword arguments that should be delivered to the dispatched event - :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns + Args: + x: the x axis coordinate + y: the y axis coordinate + args: any other position arguments that should be delivered to the dispatched event + kwargs: any other keyword arguments that should be delivered to the dispatched event + Returns: + ``EVENT_HANDLED`` or ``EVENT_UNHANDLED``, or whatever the dispatched method returns """ return self.dispatch_mouse_event("on_mouse_release", x, y, *args, **kwargs) @@ -757,13 +886,15 @@ def dispatch_mouse_enter_leave_events( based on 'on_mouse_motion' and 'on_mouse_drag' events. Will also dispatch the event (event_origin) that called this method - :param event_origin: The mouse event name that called this method. - This event will be called here. - :param x: The x axis coordinate - :param y: The y axis coordinate - :param args: Any other position arguments that should be delivered to the dispatched event - :param kwargs: Any other keyword arguments that should be delivered to the dispatched event - :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns + Args: + event_origin: The mouse event name that called this method. + This event will be called here. + x: The x axis coordinate + y: The y axis coordinate + args: Any other position arguments that should be delivered to the dispatched event + kwargs: Any other keyword arguments that should be delivered to the dispatched event + Returns: + ``EVENT_HANDLED`` or ``EVENT_UNHANDLED``, or whatever the dispatched method returns """ before_sections = self.mouse_over_sections current_sections = list(self.get_sections(x, y)) # consume the generator @@ -804,11 +935,13 @@ def on_mouse_motion(self, x: int, y: int, *args, **kwargs) -> bool | None: This method dispatches the on_mouse_motion and also calculates if on_mouse_enter/leave should be fired. - :param x: the x axis coordinate - :param y: the y axis coordinate - :param args: any other position arguments that should be deliverd to the dispatched event - :param kwargs: any other keyword arguments that should be delivered to the dispatched event - :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns + Args: + x: the x axis coordinate + y: the y axis coordinate + args: any other position arguments that should be delivered to the dispatched event + kwargs: any other keyword arguments that should be delivered to the dispatched event + Returns: + ``EVENT_HANDLED`` or ``EVENT_UNHANDLED``, or whatever the dispatched method returns """ return self.dispatch_mouse_enter_leave_events("on_mouse_motion", x, y, *args, **kwargs) @@ -817,11 +950,13 @@ def on_mouse_drag(self, x: int, y: int, *args, **kwargs) -> bool | None: This method dispatches the on_mouse_drag and also calculates if on_mouse_enter/leave should be fired. - :param x: the x axis coordinate - :param y: the y axis coordinate - :param args: any other position arguments that should be delivered to the dispatched event - :param kwargs: any other keyword arguments that should be delivered to the dispatched event - :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns + Args: + x: the x axis coordinate + y: the y axis coordinate + args: any other position arguments that should be delivered to the dispatched event + kwargs: any other keyword arguments that should be delivered to the dispatched event + Returns: + ``EVENT_HANDLED`` or ``EVENT_UNHANDLED``, or whatever the dispatched method returns """ return self.dispatch_mouse_enter_leave_events("on_mouse_drag", x, y, *args, **kwargs) @@ -829,11 +964,13 @@ def on_mouse_scroll(self, x: int, y: int, *args, **kwargs) -> bool | None: """ Triggers the on_mouse_scroll event on the appropriate sections or view - :param x: the x axis coordinate - :param y: the y axis coordinate - :param args: any other position arguments that should be deliverd to the dispatched event - :param kwargs: any other keyword arguments that should be delivered to the dispatched event - :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns + Args: + x: the x axis coordinate + y: the y axis coordinate + args: any other position arguments that should be delivered to the dispatched event + kwargs: any other keyword arguments that should be delivered to the dispatched event + Returns: + ``EVENT_HANDLED`` or ``EVENT_UNHANDLED``, or whatever the dispatched method returns """ return self.dispatch_mouse_event("on_mouse_scroll", x, y, *args, **kwargs) @@ -842,11 +979,13 @@ def on_mouse_enter(self, x: int, y: int, *args, **kwargs) -> bool | None: Triggered when the mouse enters the window space Will trigger on_mouse_enter on the appropriate sections or view - :param x: the x axis coordinate - :param y: the y axis coordinate - :param args: any other position arguments that should be delivered to the dispatched event - :param kwargs: any other keyword arguments that should be delivered to the dispatched event - :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns + Args: + x: the x axis coordinate + y: the y axis coordinate + args: any other position arguments that should be delivered to the dispatched event + kwargs: any other keyword arguments that should be delivered to the dispatched event + Returns: + ``EVENT_HANDLED`` or ``EVENT_UNHANDLED``, or whatever the dispatched method returns """ current_sections = list(self.get_sections(x, y)) # consume the generator @@ -867,11 +1006,13 @@ def on_mouse_leave(self, x: int, y: int, *args, **kwargs) -> bool | None: Triggered when the mouse leaves the window space Will trigger on_mouse_leave on the appropriate sections or view - :param x: the x axis coordinate - :param y: the y axis coordinate - :param args: any other position arguments that should be delivered to the dispatched event - :param kwargs: any other keyword arguments that should be delivered to the dispatched event - :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns + Args: + x: the x axis coordinate + y: the y axis coordinate + args: any other position arguments that should be delivered to the dispatched event + kwargs: any other keyword arguments that should be delivered to the dispatched event + Returns: + ``EVENT_HANDLED`` or ``EVENT_UNHANDLED``, or whatever the dispatched method returns """ prevent_dispatch = EVENT_UNHANDLED for section in self.mouse_over_sections: @@ -888,9 +1029,11 @@ def on_key_press(self, *args, **kwargs) -> bool | None: """ Triggers the on_key_press event on the appropriate sections or view - :param args: any other position arguments that should be delivered to the dispatched event - :param kwargs: any other keyword arguments that should be delivered to the dispatched event - :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns + Args: + args: any other position arguments that should be delivered to the dispatched event + kwargs: any other keyword arguments that should be delivered to the dispatched event + Returns: + ``EVENT_HANDLED`` or ``EVENT_UNHANDLED``, or whatever the dispatched method returns """ return self.dispatch_keyboard_event("on_key_press", *args, **kwargs) @@ -898,16 +1041,18 @@ def on_key_release(self, *args, **kwargs) -> bool | None: """ Triggers the on_key_release event on the appropriate sections or view - :param args: any other position arguments that should be delivered to the dispatched event - :param kwargs: any other keyword arguments that should be delivered to the dispatched event - :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns + Args: + args: any other position arguments that should be delivered to the dispatched event + kwargs: any other keyword arguments that should be delivered to the dispatched event + Returns: + ``EVENT_HANDLED`` or ``EVENT_UNHANDLED``, or whatever the dispatched method returns """ return self.dispatch_keyboard_event("on_key_release", *args, **kwargs) def on_show_view(self) -> None: """ - Called when the view is shown - The View.on_show_view is called before this by the Window.show_view method + Called when the view is shown. The :py:meth:`View.on_show_view` is called before + this by the :py:meth:`Window.show_view` method. """ for section in self.sections: if section.enabled: diff --git a/arcade/shape_list.py b/arcade/shape_list.py index 560b9b9bf..4cd950c5f 100644 --- a/arcade/shape_list.py +++ b/arcade/shape_list.py @@ -62,10 +62,11 @@ class Shape: This shape can be drawn using the draw() method, or added to a ShapeElementList for drawing in batch. - :param points: A list of points that make up the shape. - :param colors: A list of colors that correspond to the points. - :param mode: The OpenGL drawing mode. Defaults to GL_TRIANGLES. - :param program: The program to use when drawing this shape (Shape.draw() only) + Args: + points: A list of points that make up the shape. + colors: A list of colors that correspond to the points. + mode: The OpenGL drawing mode. Defaults to GL_TRIANGLES. + program: The program to use when drawing this shape (Shape.draw() only) """ def __init__( @@ -130,12 +131,13 @@ def create_line( """ Create a Shape object for a line. - :param start_x: Starting x position - :param start_y: Starting y position - :param end_x: Ending x position - :param end_y: Ending y position - :param color: Color of the line - :param line_width: Width of the line + Args: + start_x: Starting x position + start_y: Starting y position + end_x: Ending x position + end_y: Ending y position + color: Color of the line + line_width: Width of the line """ points = get_points_for_thick_line(start_x, start_y, end_x, end_y, line_width) color_list = [color, color, color, color] @@ -152,12 +154,13 @@ def create_line_generic_with_colors( This function is used by ``create_line_strip`` and ``create_line_loop``, just changing the OpenGL type for the line drawing. - :param point_list: A list of points that make up the shape. - :param color_sequence: A sequence of colors such - as a :py:class:`list`; each color must be either a - :py:class:`~arcade.types.Color` instance or a 4-length RGBA - :py:class:`tuple`. - :param shape_mode: The OpenGL drawing mode. Defaults to GL_TRIANGLES. + Args: + point_list: A list of points that make up the shape. + color_sequence: A sequence of colors such + as a :py:class:`list`; each color must be either a + :py:class:`~arcade.types.Color` instance or a 4-length RGBA + :py:class:`tuple`. + shape_mode: The OpenGL drawing mode. Defaults to ``GL_TRIANGLES``. """ return Shape( points=point_list, @@ -175,9 +178,10 @@ def create_line_generic( This function is used by ``create_line_strip`` and ``create_line_loop``, just changing the OpenGL type for the line drawing. - :param point_list: A list of points that make up the shape. - :param color: A color such as a :py:class:`~arcade.types.Color` - :param shape_mode: The OpenGL drawing mode. Defaults to GL_TRIANGLES. + Args: + point_list: A list of points that make up the shape. + color: A color such as a :py:class:`~arcade.types.Color` + shape_mode: The OpenGL drawing mode. Defaults to ``GL_TRIANGLES``. """ colors = [Color.from_iterable(color)] * len(point_list) return create_line_generic_with_colors(point_list, colors, shape_mode) @@ -190,9 +194,10 @@ def create_line_strip(point_list: PointList, color: RGBA255, line_width: float = Internally, thick lines are created by two triangles. - :param point_list: - :param color: - :param line_width: + Args: + point_list: A list of points that make up the shape. + color: A color such as a :py:class:`~arcade.types.Color` + line_width: Width of the line """ if line_width == 1: return create_line_generic(point_list, color, gl.GL_LINE_STRIP) @@ -222,9 +227,10 @@ def create_line_loop( Create a multi-point line loop to be rendered later. This works faster than draw_line because the vertexes are only loaded to the graphics card once, rather than each frame. - :param point_list: A list of points that make up the shape. - :param color: A color such as a :py:class:`~arcade.types.Color` - :param line_width: Width of the line + Args: + point_list: A list of points that make up the shape. + color: A color such as a :py:class:`~arcade.types.Color` + line_width: Width of the line """ point_list = list(point_list) + [point_list[0]] return create_line_strip(point_list, color, line_width) @@ -238,9 +244,10 @@ def create_lines( Create a multi-point line loop to be rendered later. This works faster than draw_line because the vertexes are only loaded to the graphics card once, rather than each frame. - :param point_list: A list of points that make up the shape. - :param color: A color such as a :py:class:`~arcade.types.Color` - :param line_width: Width of the line + Args: + point_list: A list of points that make up the shape. + color: A color such as a :py:class:`~arcade.types.Color` + line_width: Width of the line """ return create_line_generic(point_list, color, gl.GL_LINES) @@ -254,11 +261,10 @@ def create_lines_with_colors( Create a line segments to be rendered later. This works faster than draw_line because the vertexes are only loaded to the graphics card once, rather than each frame. - :param point_list: Line segments start and end point tuples list - :param color_list: Three or four byte tuples list for every point - :param line_width: Width of the line - - :Returns Shape: + Args: + point_list: Line segments start and end point tuples list + color_list: Three or four byte tuples list for every point + line_width: Width of the line """ if line_width == 1: return create_line_generic_with_colors(point_list, color_list, gl.GL_LINES) @@ -292,8 +298,9 @@ def create_polygon(point_list: PointList, color: RGBA255) -> Shape: draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. - :param point_list: A list of points that make up the shape. - :param color: A color such as a :py:class:`~arcade.types.Color` + Args: + point_list: A list of points that make up the shape. + color: A color such as a :py:class:`~arcade.types.Color` """ # We assume points were given in order, either clockwise or counter clockwise. # Polygon is assumed to be monotone. @@ -327,12 +334,13 @@ def create_rectangle_filled( draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. - :param center_x: X position of the center of the rectangle - :param center_y: Y position of the center of the rectangle - :param width: Width of the rectangle - :param height: Height of the rectangle - :param color: A color such as a :py:class:`~arcade.types.Color` - :param tilt_angle: Angle to tilt the rectangle in degrees + Args: + center_x: X position of the center of the rectangle + center_y: Y position of the center of the rectangle + width: Width of the rectangle + height: Height of the rectangle + color: A color such as a :py:class:`~arcade.types.Color` + tilt_angle: Angle to tilt the rectangle in degrees """ return create_rectangle( center_x, @@ -364,13 +372,14 @@ def create_rectangle_outline( draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. - :param center_x: X position of the center of the rectangle - :param center_y: Y position of the center of the rectangle - :param width: Width of the rectangle - :param height: Height of the rectangle - :param color: A color such as a :py:class:`~arcade.types.Color` - :param border_width: Width of the border - :param tilt_angle: Angle to tilt the rectangle in degrees + Args: + center_x: X position of the center of the rectangle + center_y: Y position of the center of the rectangle + width: Width of the rectangle + height: Height of the rectangle + color: A color such as a :py:class:`~arcade.types.Color` + border_width: Width of the border + tilt_angle: Angle to tilt the rectangle in degrees """ return create_rectangle( center_x, @@ -395,11 +404,12 @@ def get_rectangle_points( Utility function that will return all four coordinate points of a rectangle given the x, y center, width, height, and rotation. - :param center_x: X position of the center of the rectangle - :param center_y: Y position of the center of the rectangle - :param width: Width of the rectangle - :param height: Height of the rectangle - :param tilt_angle: Angle to tilt the rectangle in degrees + Args: + center_x: X position of the center of the rectangle + center_y: Y position of the center of the rectangle + width: Width of the rectangle + height: Height of the rectangle + tilt_angle: Angle to tilt the rectangle in degrees """ x1 = -width / 2 + center_x y1 = -height / 2 + center_y @@ -443,14 +453,15 @@ def create_rectangle( draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. - :param center_x: X position of the center of the rectangle - :param center_y: Y position of the center of the rectangle - :param width: Width of the rectangle - :param height: Height of the rectangle - :param color: A color such as a :py:class:`~arcade.types.Color` - :param border_width: Width of the border - :param tilt_angle: Angle to tilt the rectangle in degrees - :param filled: If True, the rectangle is filled. If False, it is an outline. + Args: + center_x: X position of the center of the rectangle + center_y: Y position of the center of the rectangle + width: Width of the rectangle + height: Height of the rectangle + color: A color such as a :py:class:`~arcade.types.Color` + border_width: Width of the border + tilt_angle: Angle to tilt the rectangle in degrees + filled: If True, the rectangle is filled. If False, it is an outline. """ data: list[Point] = cast( list[Point], get_rectangle_points(center_x, center_y, width, height, tilt_angle) @@ -521,8 +532,9 @@ def create_rectangle_filled_with_colors(point_list, color_list) -> Shape: draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. - :param point_list: List of points to create the rectangle from - :param color_list: List of colors to create the rectangle from + Args: + point_list: List of points to create the rectangle from + color_list: List of colors to create the rectangle from """ shape_mode = gl.GL_TRIANGLE_STRIP new_point_list = [point_list[0], point_list[1], point_list[3], point_list[2]] @@ -541,6 +553,10 @@ def create_rectangles_filled_with_colors(point_list, color_list: Sequence[RGBA25 For even faster performance, add multiple shapes into a ShapeElementList and draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. + + Args: + point_list: List of points to create the rectangles from + color_list: List of colors to create the rectangles from """ shape_mode = gl.GL_TRIANGLES new_point_list: list[Point] = [] @@ -572,11 +588,12 @@ def create_triangles_filled_with_colors( draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. - :param point_list: Triangles vertices tuples. - :param color_sequence: A sequence of colors such - as a :py:class:`list`; each color must be either a - :py:class:`~arcade.types.Color` instance or a 4-length RGBA - :py:class:`tuple`. + Args: + point_list: Triangles vertices tuples. + color_sequence: A sequence of colors such + as a :py:class:`list`; each color must be either a + :py:class:`~arcade.types.Color` instance or a 4-length RGBA + :py:class:`tuple`. """ shape_mode = gl.GL_TRIANGLES return create_line_generic_with_colors(point_list, color_sequence, shape_mode) @@ -599,11 +616,12 @@ def create_triangles_strip_filled_with_colors( draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. - :param point_list: Triangles vertices tuples. - :param color_sequence: A sequence of colors such - as a :py:class:`list`; each color must be either a - :py:class:`~arcade.types.Color` instance or a 4-length RGBA - :py:class:`tuple`. + Args: + point_list: Triangles vertices tuples. + color_sequence: A sequence of colors such + as a :py:class:`list`; each color must be either a + :py:class:`~arcade.types.Color` instance or a 4-length RGBA + :py:class:`tuple`. """ shape_mode = gl.GL_TRIANGLE_STRIP return create_line_generic_with_colors(point_list, color_sequence, shape_mode) @@ -628,6 +646,15 @@ def create_ellipse_filled( For even faster performance, add multiple shapes into a ShapeElementList and draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. + + Args: + center_x: X position of the center of the ellipse + center_y: Y position of the center of the ellipse + width: Width of the ellipse + height: Height of the ellipse + color: A color such as a :py:class:`~arcade.types.Color` + tilt_angle: Angle to tilt the ellipse + num_segments: Number of segments to use to draw the ellipse """ border_width = 1 return create_ellipse( @@ -663,6 +690,16 @@ def create_ellipse_outline( For even faster performance, add multiple shapes into a ShapeElementList and draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. + + Args: + center_x: X position of the center of the ellipse + center_y: Y position of the center of the ellipse + width: Width of the ellipse + height: Height of the ellipse + color: A color such as a :py:class:`~arcade.types.Color` + border_width: Width of the border + tilt_angle: Angle to tilt the ellipse + num_segments: Number of segments to use to draw the ellipse """ return create_ellipse( center_x, @@ -699,15 +736,16 @@ def create_ellipse( draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. - :param center_x: X position of the center of the ellipse. - :param center_y: Y position of the center of the ellipse. - :param width: Width of the ellipse. - :param height: Height of the ellipse. - :param color: Color of the ellipse. - :param border_width: Width of the border. - :param tilt_angle: Angle to tilt the ellipse. - :param num_segments: Number of segments to use to draw the ellipse. - :param filled: If True, create a filled ellipse. If False, create an outline. + Args: + center_x: X position of the center of the ellipse. + center_y: Y position of the center of the ellipse. + width: Width of the ellipse. + height: Height of the ellipse. + color: Color of the ellipse. + border_width: Width of the border. + tilt_angle: Angle to tilt the ellipse. + num_segments: Number of segments to use to draw the ellipse. + filled: If True, create a filled ellipse. If False, create an outline. """ # Create an array with the vertex point_list point_list = [] @@ -758,14 +796,15 @@ def create_ellipse_filled_with_colors( draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. - :param center_x: X position of the center of the ellipse. - :param center_y: Y position of the center of the ellipse. - :param width: Width of the ellipse. - :param height: Height of the ellipse. - :param outside_color: Color of the outside of the ellipse. - :param inside_color: Color of the inside of the ellipse. - :param tilt_angle: Angle to tilt the ellipse. - :param num_segments: Number of segments to use to draw the ellipse. + Args: + center_x: X position of the center of the ellipse. + center_y: Y position of the center of the ellipse. + width: Width of the ellipse. + height: Height of the ellipse. + outside_color: Color of the outside of the ellipse. + inside_color: Color of the inside of the ellipse. + tilt_angle: Angle to tilt the ellipse. + num_segments: Number of segments to use to draw the ellipse. """ # Create an array with the vertex data # Create an array with the vertex point_list @@ -800,7 +839,8 @@ class ShapeElementList(Generic[TShape]): Adding new shapes is fast, but removing them is slow. - :param blend: If True, shapes will be drawn with blending enabled. + Args: + blend: If True, shapes will be drawn with blending enabled. """ def __init__(self, blend: bool = True) -> None: @@ -822,6 +862,9 @@ def __init__(self, blend: bool = True) -> None: def append(self, item: TShape) -> None: """ Add a new shape to the list. + + Args: + item: Shape to add to the list. """ self.shape_list.append(item) batch = self.batches.get(item.mode, None) @@ -841,6 +884,9 @@ def append(self, item: TShape) -> None: def remove(self, item: TShape) -> None: """ Remove a specific shape from the list. + + Args: + item: Shape to remove from the list. """ self.shape_list.remove(item) batch = self.batches[item.mode] @@ -882,8 +928,9 @@ def clear(self, position: bool = True, angle: bool = True) -> None: """ Clear all the contents from the shape list. - :param position: Reset the position to 0,0 - :param angle: Reset the angle to 0 + Args: + position: Reset the position to ``0, 0`` + angle: Reset the angle to ``0.0`` """ self.shape_list.clear() self.batches.clear() @@ -898,8 +945,9 @@ def move(self, change_x: float, change_y: float) -> None: """ Change the center_x/y of the shape list relative to the current position. - :param change_x: Amount to move on the x axis - :param change_y: Amount to move on the y axis + Args: + change_x: Amount to move on the x axis + change_y: Amount to move on the y axis """ self.center_x += change_x self.center_y += change_y @@ -919,7 +967,7 @@ def position(self, value: tuple[float, float]) -> None: @property def center_x(self) -> float: - """Get or set the center x coordinate of the ShapeElementList.""" + """Get or set the center x coordinate of the shape list.""" return self._center_x @center_x.setter @@ -928,7 +976,7 @@ def center_x(self, value: float) -> None: @property def center_y(self) -> float: - """Get or set the center y coordinate of the ShapeElementList.""" + """Get or set the center y coordinate of the shape list.""" return self._center_y @center_y.setter @@ -945,7 +993,7 @@ def angle(self, value: float) -> None: self._angle = value def __len__(self) -> int: - """Return the length of the sprite list.""" + """Return the length of the shape list.""" return len(self.shape_list) def __iter__(self) -> Iterable[TShape]: diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py index f7f9b828b..1f6a5a705 100644 --- a/arcade/sprite/sprite.py +++ b/arcade/sprite/sprite.py @@ -95,37 +95,52 @@ def __init__( # Movement self._velocity = 0.0, 0.0 self.change_angle: float = 0.0 + """Change in angle per 1/60th of a second.""" # Custom sprite properties self._properties: dict[str, Any] | None = None # Boundaries for moving platforms in tilemaps - #: :py:class:`~arcade.physics_engines.PhysicsEnginePlatformer` - #: uses this as the left boundary for moving - #: :py:attr:`~arcade.physics_engines.PhysicsEnginePlatformer.platforms`. self.boundary_left: float | None = None - #: :py:class:`~arcade.physics_engines.PhysicsEnginePlatformer` - #: uses this as the right boundary for moving - #: :py:attr:`~arcade.physics_engines.PhysicsEnginePlatformer.platforms`. + """ + :py:class:`~arcade.physics_engines.PhysicsEnginePlatformer` + uses this as the left boundary for moving + :py:attr:`~arcade.physics_engines.PhysicsEnginePlatformer.platforms`. + """ + self.boundary_right: float | None = None - #: :py:class:`~arcade.physics_engines.PhysicsEnginePlatformer` - #: uses this as the top boundary for moving - #: :py:attr:`~arcade.physics_engines.PhysicsEnginePlatformer.platforms`. + """ + :py:class:`~arcade.physics_engines.PhysicsEnginePlatformer` + uses this as the right boundary for moving + :py:attr:`~arcade.physics_engines.PhysicsEnginePlatformer.platforms`. + """ + self.boundary_top: float | None = None - #: :py:class:`~arcade.physics_engines.PhysicsEnginePlatformer` - #: uses this as the top boundary for moving - #: :py:attr:`~arcade.physics_engines.PhysicsEnginePlatformer.platforms`. + """ + :py:class:`~arcade.physics_engines.PhysicsEnginePlatformer` + uses this as the top boundary for moving + :py:attr:`~arcade.physics_engines.PhysicsEnginePlatformer.platforms`. + """ + self.boundary_bottom: float | None = None + """ + :py:class:`~arcade.physics_engines.PhysicsEnginePlatformer` + uses this as the top boundary for moving + :py:attr:`~arcade.physics_engines.PhysicsEnginePlatformer.platforms`. + """ self.cur_texture_index: int = 0 + """Current texture index for sprite animation.""" self.textures: list[Texture] = _textures + """List of textures stored in the sprite.""" self.physics_engines: list[Any] = [] + """List of physics engines that have registered this sprite.""" self._sprite_list: SpriteList | None = None # Debug properties self.guid: str | None = None - """str: A GUID for debugging purposes.""" + """A unique id for debugging purposes.""" self._hit_box: RotatableHitBox = self._hit_box.create_rotatable(angle=self._angle) diff --git a/arcade/start_finish_data.py b/arcade/start_finish_data.py index 2d5b00b7e..52ccff1d1 100644 --- a/arcade/start_finish_data.py +++ b/arcade/start_finish_data.py @@ -7,11 +7,29 @@ class StartFinishRenderData: """ State data for offscreen rendering with :py:meth:`arcade.start_render` and - :py:meth:`arcade.finish_render`. This is only meant for simply module level - drawing like creating a static image we display on the screen. + :py:meth:`arcade.finish_render`. This is only meant for simple module level + drawing like creating a static image we display repeatedly once the module + has executed. - :param pixelated: Should the image be pixelated or smooth when scaled? - :param blend: Should we draw with alpha blending enabled? + Example:: + + import arcade + arcade.open_window(500, 500, "Picture") + arcade.set_background_color(arcade.color.WHITE) + # This renderer is permanently enabled here + arcade.start_render() + arcade.draw_text("Hello World", 190, 50, arcade.color.BLACK, 20) + arcade.draw_circle_filled(250, 250, 100, arcade.color.RED) + arcade.finish_render() + # Repeatedly display the image produced between start and finish render + arcade.run() + + This renderer is enabled by calling :py:meth:`arcade.start_render`. It's + an irreversible action. + + Args: + pixelated: Should the image be pixelated or smooth when scaled? + blend: Should we draw with alpha blending enabled? """ def __init__(self, pixelated: bool = False, blend: bool = True): @@ -29,7 +47,11 @@ def __init__(self, pixelated: bool = False, blend: bool = True): self.completed = False def begin(self): - """Enable rendering into the buffer""" + """ + Enable rendering into the buffer. + + Should only be called once followed by a call to :py:meth:`end`. + """ self.generator_func = self.atlas.render_into(self.texture) fbo = self.generator_func.__enter__() fbo.clear(color=self.window.background_color) @@ -43,7 +65,9 @@ def end(self): self.completed = True def draw(self): - """Draw the buffer to the screen""" + """ + Draw the buffer to the screen attempting to preserve the aspect ratio. + """ # Stretch the texture to the window size with black bars if needed w, h = self.window.get_size() min_factor = min(w / self.texture.width, h / self.texture.height) diff --git a/doc/api_docs/arcade.rst b/doc/api_docs/arcade.rst index 06541d959..d7b2bcfd3 100644 --- a/doc/api_docs/arcade.rst +++ b/doc/api_docs/arcade.rst @@ -45,6 +45,7 @@ for the Python Arcade library. See also: api/math gl/index api/exceptions + api/start_finish_render api/future .. _arcade-api-gui: diff --git a/util/update_quick_index.py b/util/update_quick_index.py index 9820c6575..6e7b20223 100644 --- a/util/update_quick_index.py +++ b/util/update_quick_index.py @@ -222,6 +222,7 @@ "arcade.application", "arcade.window_commands", "arcade.sections", + "arcade.screenshot", ] }, "sound.rst": { @@ -347,6 +348,12 @@ "arcade.exceptions" ], }, + "start_finish_render.rst": { + "title": "Start/Finish Render", + "use_declarations_in": [ + "arcade.start_finish_data", + ], + }, "future.rst": { "title": "Future Features", "use_declarations_in": [