Source code for rubato.classes.game_object

"""
A game object is a basic element that holds components, postion, and z_index.
"""
from __future__ import annotations
from typing import List, Union, Dict
import sdl2
import sdl2.sdlgfx

from . import Hitbox, Polygon, Circle, Rectangle, Component
from .. import Game, Vector, Defaults, Display, DuplicateComponentError


[docs]class GameObject: """ The base game object class. Attributes: name (str): The name of the game object. Will default to: "Game Object {number in group}" pos (Vector): The current position of the game object. z_index (int): The z_index of the game object. components (List[Component]): All the components attached to this game object. """
[docs] def __init__(self, options: dict = {}): """ Initializes a game object. Args: options: A game object config. Defaults to the :ref:`Game Object defaults <gameobjdef>`. """ param = Defaults.gameobj_defaults | options self.name: str = param["name"] self.pos: Vector = param["pos"] self.debug: bool = param["debug"] self.z_index: int = param["z_index"] self._components: Dict[type, List[Component]] = {}
@property def relative_pos(self) -> Vector: """The relative position of the game object.""" return self.map_coord(self.pos)
[docs] def add(self, component: Component) -> GameObject: """ Add a component to the game object. Args: component (Component): The component to add. Raises: DuplicateComponentError: Raised when there is already a component of the same type on the game object. Returns: GameObject: The current game object """ comp_type = type(component) if component.singular and comp_type in self._components: raise DuplicateComponentError( f"There is already a component of type {comp_type} on the game object {self.name}" ) if isinstance(component, Hitbox): component._pos = lambda: self.pos # pylint: disable=protected-access comp_type = Hitbox if comp_type not in self._components: self._components[comp_type] = [] self._components[comp_type].append(component) component.gameobj = self return self
[docs] def remove(self, comp_type: type): """ Removes a component from the game object. Args: comp_type (type): The type of the component to remove. Raises: Warning: The component was not in the game object and nothing was removed. """ if comp_type in self._components: del self._components[comp_type][0] if not self._components[comp_type]: del self._components[comp_type] else: raise Warning( f"The component of type {comp_type} is not in the game object {self.name} and was not removed." )
[docs] def remove_all(self, comp_type: type): """ Removes all components of a type from the game object. Args: comp_type (type): The type of the component to remove. Raises: Warning: The components were not in the game object and nothing was removed. """ if comp_type in self._components: del self._components[comp_type] else: raise Warning( f"The components of type {comp_type} are not in the game object {self.name} and were not removed." )
[docs] def get(self, comp_type: type) -> Union[Component, None]: """ Gets a component from the game object. Args: comp_type (type): The type of the component to search for. Returns: Union[Component, None]: The component if it was found or None if it wasn't. """ if comp_type in (Rectangle, Polygon, Circle): comp_type = Hitbox if comp_type in self._components: return self._components[comp_type][0] return None
[docs] def get_all(self, comp_type: type) -> List[Component]: """ Gets all the components of a type from the game object. Args: comp_type (type): The type of component to search for. Returns: List[Component]: A list containing all the components of that type. If no components were found, the list is empty. """ if comp_type in (Rectangle, Polygon, Circle): comp_type = Hitbox if comp_type in self._components: return self._components[comp_type] return []
[docs] def delete(self): """ Deletes and frees everything from the game object. This is called when you remove it from a group or scene. Warning: Calling this will render the gameobject useless in the future. """ for comps in self._components.values(): for comp in comps: comp.delete()
def setup(self): for comps in self._components.values(): for comp in comps: comp.setup() def draw(self): for comps in self._components.values(): for comp in comps: comp.draw() if self.debug or Game.debug: rel_pos = self.relative_pos sdl2.sdlgfx.thickLineRGBA( Display.renderer.sdlrenderer, int(rel_pos.x) - int(self.scale_value(10)), int(rel_pos.y), int(rel_pos.x) + int(self.scale_value(10)), int(rel_pos.y), int(2 * max(1, Display.display_ratio.y)), 0, 255, 0, 255 ) sdl2.sdlgfx.thickLineRGBA( Display.renderer.sdlrenderer, int(rel_pos.x), int(rel_pos.y) - int(self.scale_value(10)), int(rel_pos.x), int(rel_pos.y) + int(self.scale_value(10)), int(2 * max(1, Display.display_ratio.x)), 0, 255, 0, 255 ) def update(self): for comps in self._components.values(): for comp in comps: comp.update() def fixed_update(self): for comps in self._components.values(): for comp in comps: comp.fixed_update()
[docs] @staticmethod def map_coord(coord: Vector) -> Vector: """ Maps a coordinate to the camera's coordinate system. Args: coord: The coordinate to map. Returns: Vector: The mapped coordinate. """ return Game.camera.transform(coord)
[docs] @staticmethod def scale_value(value: Union[int, float]) -> Union[int, float]: """ Scales a value to match the current camera's scale. Args: value: The value to scale. Returns: Union[int, float]: The scaled value. """ return Game.camera.scale(value)