Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,17 @@ Arcade [PyPi Release History](https://pypi.org/project/arcade/#history) page.
- Fixed `InputManager.parse()` raising `AttributeError`, so a saved input configuration couldn't be loaded.

### Breaking Changes
- Removed outdated and duplicate names from the `arcade` namespace ([#2402](https://github.com/pythonarcade/arcade/issues/2402)):
- `AnimatedWalkingSprite` and the `FACE_UP`, `FACE_DOWN`, `FACE_LEFT` and `FACE_RIGHT` constants it used. Its docs already called it deprecated and said to write your own sprite class instead. The `sprite_move_animation` example shows how.
- `get_game_controllers()`, which did the same as `get_joysticks()`. Its name suggested it returned game controllers, but it returned joysticks. For game controllers, use `get_controllers()`.
- `draw_lrbt_rectangle_filled` and `draw_lrbt_rectangle_outline` were each listed twice in `arcade.__all__`.
- The default font is now Liberation Sans, which comes with Arcade, instead of whichever of Calibri and Arial the computer has ([#1135](https://github.com/pythonarcade/arcade/issues/1135)). Text looks the same on every computer. It applies to `Text`, `draw_text()`, `create_text_sprite()`, `TextPool`, and the GUI's `UILabel`, `UITextArea`, `UIInputText` and buttons (which still use Kenney Future first if you load the Kenney fonts). Liberation Sans has the same letter widths as Arial, so text on Windows, which used Calibri, is about 10% wider. For the old look, pass `font_name=("calibri", "arial")`.
- The Liberation fonts load the first time one is used, so `font_name="Liberation Mono"` works without `load_liberation_fonts()`.
- `UITextArea` and `UIInputText` accept font file paths and resource handles for `font_name`, like `Text`.
- `arcade.load_tilemap()` and `TileMap` now give every layer's sprite list a spatial hash by default (`use_spatial_hash=True`) ([#2663](https://github.com/pythonarcade/arcade/issues/2663)). Forgetting it on a wall layer made collision checks against it much slower: 100 bullets checked against 2,000 wall tiles took 48 ms per frame without it and 0.6 ms with it. A hash makes moving a layer's sprites slower, so for a layer whose sprites move a lot, such as moving platforms, turn it off with `layer_options={"Moving Platforms": {"use_spatial_hash": False}}`, or for the whole map with `use_spatial_hash=False`.
- `layer_options` now warns about option names it doesn't know, which it used to ignore. The performance tips page named the option `"use_spatial_hashing"`; it's `"use_spatial_hash"`.
- `Sprite`, `BasicSprite`, `SpriteSolidColor`, `SpriteCircle`, `TextureAnimationSprite` and `AnimatedWalkingSprite` raise `TypeError` for keyword arguments they don't accept, instead of silently ignoring them. For example, `Sprite(path, hit_box_algorithm=...)` used to do nothing; set the hit box algorithm when loading the texture instead. `Sprite` now takes `visible` as a named argument.
- `SpriteSolidColor`, `SpriteCircle`, `TextureAnimationSprite` and `AnimatedWalkingSprite` now pass extra keyword arguments on to `Sprite`, so arguments such as `angle` and `visible` work. They used to be dropped.
- `Sprite`, `BasicSprite`, `SpriteSolidColor`, `SpriteCircle` and `TextureAnimationSprite` raise `TypeError` for keyword arguments they don't accept, instead of silently ignoring them. For example, `Sprite(path, hit_box_algorithm=...)` used to do nothing; set the hit box algorithm when loading the texture instead. `Sprite` now takes `visible` as a named argument.
- `SpriteSolidColor`, `SpriteCircle` and `TextureAnimationSprite` now pass extra keyword arguments on to `Sprite`, so arguments such as `angle` and `visible` work. They used to be dropped.
- This found arguments that had silently done nothing: tilemap image layers passed `filename` and `hit_box_algorithm`, animated tiles passed `path_or_texture`, and platform tutorial steps 19 and 20 passed `scaling` instead of `scale`, so their bullets were drawn at full size instead of 80%.
- `arcade.math.get_angle_degrees()` now measures clockwise from straight up, like `Sprite.angle`: 0 is up, 90 is right, 180 is down and -90 is left. It used to measure clockwise from the right, which disagreed with `get_angle_radians()`, which already measured from up ([#2754](https://github.com/pythonarcade/arcade/issues/2754)). The two now always give the same angle in different units. A sprite whose image points up faces a point with `sprite.angle = get_angle_degrees(...)`. For the old value, subtract 90.
- Fixed the `sprite_rotate_around_tank` example's corrected barrel, which sat 90 degrees off from the mouse, and updated `turn_and_move` for the new angles. `turn_and_move`'s sprite also now stops when moving straight along an axis, which it never did.
Expand Down Expand Up @@ -85,7 +89,7 @@ Arcade [PyPi Release History](https://pypi.org/project/arcade/#history) page.
- Type checking with mypy and pyright now fails the CI check, like formatting and linting. Their existing errors are fixed.
- Fixed code excerpts in the docs that highlighted or showed the wrong lines, because the example code had changed since their line numbers were set. This covers 62 excerpts: 48 in the platformer, pymunk platformer, menu, card game, compute shader, raycasting and shader toy glow tutorials, and 14 on example pages. Most now highlight the same code they were written for. Where the code was rewritten, they highlight the code that does the same job now.
- Removed `arcade/experimental/perspective_parallax.py`, an unreferenced demo of `PerspectiveProjector` that didn't show a parallax effect. The `background_parallax` example shows parallax scrolling.
- Sped up `import arcade` from about 2.7 to 0.9 seconds on Windows ([#1159](https://github.com/pythonarcade/arcade/issues/1159)). Most of the time went to pyglet looking for game controllers when imported. Arcade now imports the controller code the first time `get_controllers()`, `ControllerManager`, `get_joysticks()` or `get_game_controllers()` is used, so the wait happens then instead. Sound still loads at import, so playing the first sound doesn't pause the game.
- Sped up `import arcade` from about 2.7 to 0.9 seconds on Windows ([#1159](https://github.com/pythonarcade/arcade/issues/1159)). Most of the time went to pyglet looking for game controllers when imported. Arcade now imports the controller code the first time `get_controllers()`, `ControllerManager` or `get_joysticks()` is used, so the wait happens then instead. Sound still loads at import, so playing the first sound doesn't pause the game.
- Arcade's extra controller mappings now load at the same time. Code that calls `pyglet.input.get_controllers()` directly without using Arcade's controller functions first only gets pyglet's own mappings.

## 4.0.0.dev8
Expand Down
15 changes: 0 additions & 15 deletions arcade/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ def configure_logging(level: int | None = None):
# Game controllers are imported on first use, because pyglet lists the
# input devices when imported. See __getattr__ at the bottom of this file.
if TYPE_CHECKING:
from .joysticks import get_game_controllers
from .joysticks import get_joysticks
from .controller import ControllerManager
from .controller import get_controllers
Expand All @@ -162,13 +161,8 @@ def configure_logging(level: int | None = None):
from .sound import play_sound
from .sound import stop_sound

from .sprite import FACE_DOWN
from .sprite import FACE_LEFT
from .sprite import FACE_RIGHT
from .sprite import FACE_UP
from .sprite import TextureAnimationSprite
from .sprite import load_animated_gif
from .sprite import AnimatedWalkingSprite
from .sprite import TextureAnimation
from .sprite import TextureKeyframe
from .sprite import PyMunk
Expand Down Expand Up @@ -283,16 +277,11 @@ def configure_logging(level: int | None = None):
"PSControllerButtons",
"XBoxControllerButtons",
"AStarBarrierList",
"AnimatedWalkingSprite",
"TextureAnimationSprite",
"TextureAnimation",
"TextureKeyframe",
"ArcadeContext",
"ControllerManager",
"FACE_DOWN",
"FACE_LEFT",
"FACE_RIGHT",
"FACE_UP",
"MOUSE_BUTTON_LEFT",
"MOUSE_BUTTON_MIDDLE",
"MOUSE_BUTTON_RIGHT",
Expand Down Expand Up @@ -361,8 +350,6 @@ def configure_logging(level: int | None = None):
"draw_line_strip",
"draw_lines",
"draw_lrbt_rectangle_filled",
"draw_lrbt_rectangle_filled",
"draw_lrbt_rectangle_outline",
"draw_lrbt_rectangle_outline",
"draw_parabola_filled",
"draw_parabola_outline",
Expand All @@ -388,7 +375,6 @@ def configure_logging(level: int | None = None):
"get_distance_between_sprites",
"get_sprites_in_rect",
"get_controllers",
"get_game_controllers",
"get_image",
"get_joysticks",
"get_pixel",
Expand Down Expand Up @@ -450,7 +436,6 @@ def configure_logging(level: int | None = None):
if not headless:
_LAZY_IMPORTS = {
"get_joysticks": "joysticks",
"get_game_controllers": "joysticks",
"joysticks": "joysticks",
"ControllerManager": "controller",
"get_controllers": "controller",
Expand Down
15 changes: 5 additions & 10 deletions arcade/joysticks.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
import pyglet.input
from pyglet.input import Joystick

__all__ = ["get_joysticks", "get_game_controllers"]
__all__ = ["get_joysticks"]


def get_joysticks() -> list[Joystick]:
"""
Get a list of all the game controllers
Get a list of all the joysticks.

This is an alias of :func:`get_game_controllers`, which is better worded.
These are pyglet :py:class:`~pyglet.input.Joystick` objects, which give
raw access to the axes and buttons. For game controllers with named
buttons and sticks, use :py:func:`arcade.get_controllers` instead.
"""
return pyglet.input.get_joysticks() # type: ignore # pending https://github.com/pyglet/pyglet/issues/842


def get_game_controllers() -> list[Joystick]:
"""
Get a list of all the game controllers
"""
return get_joysticks()
12 changes: 0 additions & 12 deletions arcade/sprite/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,8 @@
TextureAnimationSprite,
TextureAnimation,
TextureKeyframe,
AnimatedWalkingSprite,
)
from .colored import SpriteSolidColor, SpriteCircle
from .enums import (
FACE_LEFT,
FACE_RIGHT,
FACE_UP,
FACE_DOWN,
)


def load_animated_gif(resource_name: str | Path) -> TextureAnimationSprite:
Expand Down Expand Up @@ -76,13 +69,8 @@ def load_animated_gif(resource_name: str | Path) -> TextureAnimationSprite:
"TextureAnimationSprite",
"TextureAnimation",
"TextureKeyframe",
"AnimatedWalkingSprite",
"load_animated_gif",
"SpriteSolidColor",
"SpriteCircle",
"FACE_LEFT",
"FACE_RIGHT",
"FACE_UP",
"FACE_DOWN",
"PymunkMixin",
]
163 changes: 1 addition & 162 deletions arcade/sprite/animated.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import bisect
import logging
import math

from arcade import Texture
from arcade.types import Point2

from .enums import (
FACE_DOWN,
FACE_LEFT,
FACE_RIGHT,
FACE_UP,
)

from .sprite import Sprite

logger = logging.getLogger("arcade")
Expand Down Expand Up @@ -211,156 +203,3 @@ def update_animation(self, delta_time: float = 1 / 60, **kwargs) -> None:
if index != self._current_keyframe_index:
self._current_keyframe_index = index
self.texture = keyframe.texture


class AnimatedWalkingSprite(Sprite):
"""
Deprecated Sprite for platformer games that supports walking animations.
Make sure to call update_animation after loading the animations so the
initial texture can be set. Or manually set it.

It is highly recommended you create your own version of this class rather than
try to use this pre-packaged one.

For an example, see this section of the platformer tutorial:
:ref:`platformer_part_twelve`.

Args:
scale:
Initial scale of the sprite.
center_x:
Initial x position of the sprite.
center_y:
Initial y position of the sprite.
**kwargs:
Passed to :py:class:`~arcade.Sprite`, such as ``angle``, ``scale`` or ``visible``.
"""

def __init__(
self,
scale: float | Point2 = 1.0,
center_x: float = 0.0,
center_y: float = 0.0,
**kwargs,
):
super().__init__(
None,
scale=scale,
center_x=center_x,
center_y=center_y,
**kwargs,
)
self.state = FACE_RIGHT
self.stand_right_textures: list[Texture] = []
self.stand_left_textures: list[Texture] = []
self.walk_left_textures: list[Texture] = []
self.walk_right_textures: list[Texture] = []
self.walk_up_textures: list[Texture] = []
self.walk_down_textures: list[Texture] = []
self.cur_texture_index = 0
self.texture_change_distance = 20
self.last_texture_change_center_x: float = 0.0
self.last_texture_change_center_y: float = 0.0

def update_animation(self, delta_time: float = 1 / 60) -> None:
"""
Logic for texture animation.

Args:
delta_time: Time since last update.
"""
x1 = self.center_x
x2 = self.last_texture_change_center_x
y1 = self.center_y
y2 = self.last_texture_change_center_y
distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
texture_list: list[Texture] = []

change_direction = False
if (
self.change_x > 0
and self.change_y == 0
and self.state != FACE_RIGHT
and len(self.walk_right_textures) > 0
):
self.state = FACE_RIGHT
change_direction = True
elif (
self.change_x < 0
and self.change_y == 0
and self.state != FACE_LEFT
and len(self.walk_left_textures) > 0
):
self.state = FACE_LEFT
change_direction = True
elif (
self.change_y < 0
and self.change_x == 0
and self.state != FACE_DOWN
and len(self.walk_down_textures) > 0
):
self.state = FACE_DOWN
change_direction = True
elif (
self.change_y > 0
and self.change_x == 0
and self.state != FACE_UP
and len(self.walk_up_textures) > 0
):
self.state = FACE_UP
change_direction = True

if self.change_x == 0 and self.change_y == 0:
if self.state == FACE_LEFT:
self.texture = self.stand_left_textures[0]
elif self.state == FACE_RIGHT:
self.texture = self.stand_right_textures[0]
elif self.state == FACE_UP:
self.texture = self.walk_up_textures[0]
elif self.state == FACE_DOWN:
self.texture = self.walk_down_textures[0]

elif change_direction or distance >= self.texture_change_distance:
self.last_texture_change_center_x = self.center_x
self.last_texture_change_center_y = self.center_y

if self.state == FACE_LEFT:
texture_list = self.walk_left_textures
if texture_list is None or len(texture_list) == 0:
raise RuntimeError(
"update_animation was called on a sprite that doesn't have a "
"list of walk left textures."
)
elif self.state == FACE_RIGHT:
texture_list = self.walk_right_textures
if texture_list is None or len(texture_list) == 0:
raise RuntimeError(
"update_animation was called on a sprite that doesn't have a list of "
"walk right textures."
)
elif self.state == FACE_UP:
texture_list = self.walk_up_textures
if texture_list is None or len(texture_list) == 0:
raise RuntimeError(
"update_animation was called on a sprite that doesn't have a list of "
"walk up textures."
)
elif self.state == FACE_DOWN:
texture_list = self.walk_down_textures
if texture_list is None or len(texture_list) == 0:
raise RuntimeError(
"update_animation was called on a sprite that doesn't "
"have a list of walk down textures."
)

self.cur_texture_index += 1
if self.cur_texture_index >= len(texture_list):
self.cur_texture_index = 0

self.texture = texture_list[self.cur_texture_index]

if self._texture is None:
logger.warning("Error, no texture set")
else:
self.width = self._texture.width * self.scale_x
self.height = self._texture.height * self.scale_y
4 changes: 0 additions & 4 deletions arcade/sprite/enums.py

This file was deleted.

Loading
Loading