Source code for rubato.struct.sprite

"""
A sprite is a class that handles rendering of images.
"""
from __future__ import annotations

import sdl2, sdl2.ext, sdl2.sdlgfx

from .. import get_path, Display, Vector, Game


[docs]class Sprite: """ A sprite is a class that handles rendering of images independent of Game Objects. Args: rel_path: The relative path to the image. pos: The position to draw the image at. Defaults to Vector(0, 0). rotation: The rotation of the image. Defaults to 0. scale: The scale of the image. Defaults to Vector(1, 1). aa: Whether anti aliasing is turned on. Defaults to True. Attributes: image: The image that is rendered. This is an SDL_Surface or a string in the surface hasn't been set yet. pos: The position of the image. """ def __init__( self, rel_path: str, pos: Vector = Vector(), rotation: float = 0, scale: Vector = Vector(1, 1), aa: bool = True, ): self.image: sdl2.SDL_Surface | str = "" self._original: sdl2.SDL_Surface | str = "" self.tx: sdl2.ext.Texture | str = "" if rel_path != "": try: self.image = sdl2.ext.load_img(rel_path, False) except OSError: self.image = sdl2.ext.load_img(get_path(rel_path), False) except sdl2.ext.SDLError as e: fname = rel_path.replace("\\", "/").split("/")[-1] raise TypeError(f"{fname} is not a valid image file") from e self._original = Display.clone_surface(self.image) self.tx = sdl2.ext.Texture(Display.renderer, self.image) self.pos = pos self._rotation = rotation self._scale = scale self._aa = aa self._changed = True self._last_camera_zoom = 1 @property def rotation(self) -> float: """The rotation of the sprite.""" return self._rotation @rotation.setter def rotation(self, new: float): self._rotation = new self._changed = True @property def scale(self) -> Vector: """The scale of the sprite.""" return self._scale @scale.setter def scale(self, new: Vector): self._scale = new self._changed = True @property def aa(self) -> bool: """Whether anti-aliasing is enabled.""" return self._aa @aa.setter def aa(self, new: bool): self._aa = new self._changed = True def _update_rotozoom(self): self._last_camera_zoom = Game.camera.zoom self._changed = False self.image = sdl2.sdlgfx.rotozoomSurfaceXY( self._original, -self.rotation, # It seems that rotation is counterclockwise, even though we assume clockwise until now. # Requires further investigation but is a fix for now. self.scale.x * self._last_camera_zoom, self.scale.y * self._last_camera_zoom, int(self.aa), ).contents self.tx = sdl2.ext.Texture(Display.renderer, self.image)
[docs] def get_size(self) -> Vector: """ Gets the current size of the image. Returns: The size of the image """ self._update_rotozoom() if self.image.w == self._original.w and self.image.h == self._original.h: return Vector(self.image.w, self.image.h) * self.scale return Vector(self.image.w, self.image.h)
[docs] def get_size_original(self) -> Vector: """ Gets the original size of the image. Returns: Vector: The original size of the image. """ return Vector(self._original.w, self._original.h)
[docs] def update(self): """Updates the rotozoom of the sprite if any changes were made.""" if self._changed or self._last_camera_zoom != Game.camera.zoom: self._update_rotozoom()
[docs] def delete(self): """Deletes the sprite""" self.tx.destroy() sdl2.SDL_FreeSurface(self.image) sdl2.SDL_FreeSurface(self._original) self.image = None self.tx = None self._original = None
[docs] def clone(self): """ Creates a clone of the sprite. """ s = Sprite( "", self.pos, self.rotation, self.scale, self.aa, ) # pylint: disable=protected-access if self.image != "": s.image = Display.clone_surface(self.image) s._original = Display.clone_surface(self._original) s._changed = True return s