Source code for arcade.sprite.colored

from __future__ import annotations

from weakref import WeakValueDictionary

import PIL
import PIL.Image

import arcade
import arcade.cache
from arcade.texture import (
    ImageData,
    Texture,
    make_circle_texture,
    make_soft_circle_texture,
)
from arcade.types import RGBA255, Color
from arcade.types.rect import Rect

from .sprite import Sprite


[docs] class SpriteSolidColor(Sprite): """ A rectangular sprite of the given ``width``, ``height``, and ``color``. The texture is automatically generated instead of loaded from a file. Internally only a single global image is used for this sprite type so concerns about memory usage non-existent regardless of size or number of sprite variations. Different texture configurations (width, height) are weakly cached internally to avoid creating multiple textures with the same configuration. Args: width: Width of the sprite in pixels height: Height of the sprite in pixels center_x: Initial x position of the sprite center_y: Initial y position of the sprite color: The color of the sprite as a :py:class:`~arcade.types.Color`, an RGBA tuple, or an RGB tuple. angle: Initial angle of the sprite in degrees """ __slots__ = () _default_image: ImageData | None = None # To avoid making lots of texture instances with the same configuration # we cache them here weakly. Making a 100 x 100 grid of white sprites # only create 1 texture instead of 1000. This saves memory and processing # time for the default texture atlas. _texture_cache: WeakValueDictionary[tuple[int, int], Texture] = WeakValueDictionary() def __init__( self, width: int, height: int, center_x: float = 0, center_y: float = 0, color: RGBA255 = Color(255, 255, 255, 255), angle: float = 0, **kwargs, ): texture = self.__class__._texture_cache.get((width, height)) if texture is None: texture = Texture( self._get_default_image(), hit_box_points=( (-width / 2, -height / 2), (width / 2, -height / 2), (width / 2, height / 2), (-width / 2, height / 2), ), ) texture.size = width, height self.__class__._texture_cache[(width, height)] = texture super().__init__( texture, center_x=center_x, center_y=center_y, angle=angle, ) self.color = Color.from_iterable(color)
[docs] @classmethod def from_rect(cls, rect: Rect, color: Color, angle: float = 0.0) -> SpriteSolidColor: """ Construct a new SpriteSolidColor from a :py:class:`~arcade.types.rect.Rect`. Args: rect: The rectangle to use for the sprite's dimensions and position. color: The color of the sprite as a :py:class:`~arcade.types.Color`, an RGBA tuple, or an RGB tuple. angle: The angle of the sprite in degrees. """ return cls(int(rect.width), int(rect.height), rect.x, rect.y, color, angle)
def _get_default_image(self) -> ImageData: """Lazy-load the default image for this sprite type.""" im = self.__class__._default_image if im is None: im = ImageData( PIL.Image.new("RGBA", size=(32, 32), color=(255, 255, 255, 255)), hash="sprite_solid_color", ) self.__class__._default_image = im return im
[docs] class SpriteCircle(Sprite): """ A circle of the specified `radius <https://simple.wikipedia.org/wiki/Radius>`_. The texture is automatically generated instead of loaded from a file. There may be a stutter the first time a combination of ``radius``, ``color``, and ``soft`` is used due to texture generation. All subsequent calls for the same combination will run faster because they will re-use the texture generated earlier. For a gradient fill instead of a solid color, set ``soft`` to ``True``. The circle will fade from an opaque center to transparent at the edges. Args: radius: Radius of the circle in pixels color: The Color of the sprite as an RGB or RGBA tuple soft: If ``True``, the circle will fade from an opaque center to transparent edges. """ # Local weak cache for textures to avoid creating multiple instances with the same configuration _texture_cache: WeakValueDictionary[tuple[int, RGBA255, bool], Texture] = WeakValueDictionary() def __init__(self, radius: int, color: RGBA255, soft: bool = False, **kwargs): radius = int(radius) diameter = radius * 2 cache_key = diameter, color, soft # Get existing texture from cache if possible texture = self.__class__._texture_cache.get(cache_key) if not texture: if soft: texture = make_soft_circle_texture( diameter, color=(255, 255, 255, 255), hit_box_algorithm=arcade.hitbox.algo_simple, ) else: texture = make_circle_texture( diameter, color=(255, 255, 255, 255), ) self.__class__._texture_cache[cache_key] = texture # apply results to the new sprite super().__init__(texture) self.color = Color.from_iterable(color)