Source code for rubato.classes.group
"""
Groups contain game objects or other groups and allow separation between game objects.
"""
from __future__ import annotations
from typing import List, TYPE_CHECKING
from . import GameObject, Hitbox, Engine
from .. import Error
if TYPE_CHECKING:
from . import 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.
z_index: The z-index of the group. Defaults to 0.
active: Whether the group is active or not. Defaults to True.
Attributes:
name (str): The name of the group.
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.
z_index (int): The z-index of the group.
active (bool): Whether the group is active or not.
"""
def __init__(self, name: str = "", z_index: int = 0, active: bool = True):
self.name: str = name
self.groups: List[Group] = []
self.game_objects: List[GameObject] = []
self.z_index: int = z_index
self.active: bool = active
[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 the group itself. A group cannot be
added to itself.
ValueError: The group can only hold game objects or other groups.
"""
for item in items:
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.")
[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()
# collide all hitboxes with each other
hitboxes: List[Hitbox] = []
for game_obj in self.game_objects:
if hts := game_obj._components.get(Hitbox, []): # pylint: disable=protected-access
for ht in hts:
for hitbox in hitboxes:
Engine.collide(ht, hitbox)
hitboxes.extend(hts)
for group in self.groups:
group.fixed_update()
# collide children groups with parent hitboxes
for game_obj in group.game_objects:
if hts := game_obj._components.get(Hitbox, []): # pylint: disable=protected-access
for ht in hts:
for hitbox in hitboxes:
Engine.collide(ht, hitbox)
def draw(self, camera: Camera):
if self.active:
self.groups.sort(key=lambda i: i.z_index)
for group in self.groups:
if group.z_index <= camera.z_index:
group.draw(camera)
self.game_objects.sort(key=lambda i: i.z_index)
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 in this group and all groups it contains.
Returns:
int: The number of GameObjects in a group
"""
return len(self.game_objects) + sum([group.count() for group in self.groups])