Source code for rubato.struct.group

"""
Groups contain game objects or other groups and allow separation between game objects.
"""
from __future__ import annotations
from typing import List

from . import GameObject, Hitbox, QTree
from .. import Error, Display, Camera


[docs]class Group: """ The group class implementation. Args: name: The name of the group. Defaults to "" and is set to "Group #" when it is added to another Group or Scene. active: Whether the group is active or not. Defaults to True. Attributes: name (str): The name of the group. active (bool): Whether the group is active or not. groups (List[Group]): A list of groups that are children of this group. game_objects (List[GameObject]): A list of game objects that are children of this group. """ def __init__(self, name: str = "", active: bool = True): self.name: str = name self.active: bool = active self.groups: List[Group] = [] self.game_objects: List[GameObject] = []
[docs] def add(self, *items: GameObject | Group): """ Adds an item to the group. Args: items: The item(s) you wish to add to the group Raises: Error: The item being added is already in the group. ValueError: The group can only hold game objects or other groups. Returns: Group: This group. """ for item in items: if self.contains(item): raise Error(f"The group {self.name} already contains {item.name}.") if isinstance(item, GameObject): self.add_game_obj(item) elif isinstance(item, Group): self.add_group(item) else: raise ValueError(f"The group {self.name} can only hold game objects/groups.") return self
[docs] def add_group(self, g: Group): """Add a group to the group.""" if self == g: raise Error("Cannot add a group to itself.") if g.name == "": g.name = f"Group {len(self.groups)}" self.groups.append(g)
[docs] def add_game_obj(self, g: GameObject): """Add a game object to the group""" if g.name == "": g.name = f"Game Object {len(self.game_objects)}" self.game_objects.append(g)
[docs] def delete(self, item: GameObject | Group): """ Removes an item from the group. Args: item: The item to remove from the group. Note: The actually game object is not deleted, just removed from the group. Raises: ValueError: The item is not in the group and cannot be deleted. """ try: if isinstance(item, GameObject): self.game_objects.remove(item) elif isinstance(item, Group): self.groups.remove(item) except ValueError as e: raise ValueError(f"The item {item.name} is not in the group {self.name}") from e
def update(self): if self.active: for group in self.groups: group.update() for game_obj in self.game_objects: game_obj.update()
[docs] def fixed_update(self): """ Runs a physics iteration on the group. Called automatically by rubato as long as the group is added to a scene. """ if self.active: for game_obj in self.game_objects: game_obj.fixed_update() qtree = QTree(Display.top_left, Display.bottom_right) # collide all hitboxes with each other for game_obj in self.game_objects: hts = game_obj._components.get(Hitbox, []) # pylint: disable=protected-access if hts: bb = QTree.calc_bb(hts) qtree.collide(hts, bb) qtree.insert(hts, bb) for group in self.groups: group.fixed_update() # collide children groups with parent hitboxes for game_obj in group.game_objects: hts = game_obj._components.get(Hitbox, []) # pylint: disable=protected-access if hts: qtree.collide(hts, QTree.calc_bb(hts))
def draw(self, camera: Camera): if self.active: for group in self.groups: group.draw(camera) for game_obj in self.game_objects: if game_obj.z_index <= camera.z_index: game_obj.draw(camera)
[docs] def count(self) -> int: """ Counts all the GameObjects and subgroups in this group. Returns: int: The total number of GameObjects and subgroups contained in this group. """ return len(self.game_objects) + len(self.groups) + sum([group.count() for group in self.groups])
[docs] def clone(self) -> Group: """ Clones the group and all of its children. Warning: This is a relatively expensive operation as it clones every game object and component in the group. """ new_group = Group(f"{self.name} (clone)", self.active) for group in self.groups: new_group.add(group.clone()) for game_obj in self.game_objects: new_group.add(game_obj.clone()) return new_group
[docs] def contains(self, other: GameObject | Group) -> bool: """ Checks if the group contains the given object. Args: other: The object to check for. Returns: bool: Whether the group contains the object or not. """ if isinstance(other, GameObject): return other in self.game_objects or sum([group.contains(other) for group in self.groups]) != 0 if isinstance(other, Group): return other in self.groups or sum([group.contains(other) for group in self.groups]) != 0 return False