Source code for bascenev1lib.gameutils

# Released under the MIT License. See LICENSE for details.
#
"""Various utilities useful for gameplay."""

from __future__ import annotations

from typing import TYPE_CHECKING

import bascenev1 as bs

if TYPE_CHECKING:
    pass


[docs] class SharedObjects: """Various common components for use in games. Objects contained here are created on-demand as accessed and shared by everything in the current activity. This includes things such as standard materials. """ _STORENAME = bs.storagename() def __init__(self) -> None: activity = bs.getactivity() if self._STORENAME in activity.customdata: raise RuntimeError( 'Use SharedObjects.get() to fetch the' ' shared instance for this activity.' ) self._object_material: bs.Material | None = None self._player_material: bs.Material | None = None self._pickup_material: bs.Material | None = None self._footing_material: bs.Material | None = None self._attack_material: bs.Material | None = None self._death_material: bs.Material | None = None self._region_material: bs.Material | None = None self._railing_material: bs.Material | None = None
[docs] @classmethod def get(cls) -> SharedObjects: """Fetch/create the instance of this class for the current activity.""" activity = bs.getactivity() shobs = activity.customdata.get(cls._STORENAME) if shobs is None: shobs = SharedObjects() activity.customdata[cls._STORENAME] = shobs assert isinstance(shobs, SharedObjects) return shobs
@property def player_material(self) -> bs.Material: """a bascenev1.Material to be applied to player parts. Generally, materials related to the process of scoring when reaching a goal, etc will look for the presence of this material on things that hit them. """ if self._player_material is None: self._player_material = bs.Material() return self._player_material @property def object_material(self) -> bs.Material: """A bascenev1.Material that should be applied to any small, normal, physical objects such as bombs, boxes, players, etc. Other materials often check for the presence of this material as a prerequisite for performing certain actions (such as disabling collisions between initially-overlapping objects) """ if self._object_material is None: self._object_material = bs.Material() return self._object_material @property def pickup_material(self) -> bs.Material: """A bascenev1.Material; collision shapes used for picking things up will have this material applied. To prevent an object from being picked up, you can add a material that disables collisions against things containing this material. """ if self._pickup_material is None: self._pickup_material = bs.Material() return self._pickup_material @property def footing_material(self) -> bs.Material: """Anything that can be 'walked on' should have this bascenev1.Material applied; generally just terrain and whatnot. A character will snap upright whenever touching something with this material so it should not be applied to props, etc. """ if self._footing_material is None: self._footing_material = bs.Material() return self._footing_material @property def attack_material(self) -> bs.Material: """A bascenev1.Material applied to explosion shapes, punch shapes, etc. An object not wanting to receive impulse/etc messages can disable collisions against this material. """ if self._attack_material is None: self._attack_material = bs.Material() return self._attack_material @property def death_material(self) -> bs.Material: """A bascenev1.Material that sends a ba.DieMessage() to anything that touches it; handy for terrain below a cliff, etc. """ if self._death_material is None: mat = self._death_material = bs.Material() mat.add_actions( ('message', 'their_node', 'at_connect', bs.DieMessage()) ) return self._death_material @property def region_material(self) -> bs.Material: """A bascenev1.Material used for non-physical collision shapes (regions); collisions can generally be allowed with this material even when initially overlapping since it is not physical. """ if self._region_material is None: self._region_material = bs.Material() return self._region_material @property def railing_material(self) -> bs.Material: """A bascenev1.Material with a very low friction/stiffness/etc that can be applied to invisible 'railings' useful for gently keeping characters from falling off of cliffs. """ if self._railing_material is None: mat = self._railing_material = bs.Material() mat.add_actions(('modify_part_collision', 'collide', False)) mat.add_actions(('modify_part_collision', 'stiffness', 0.003)) mat.add_actions(('modify_part_collision', 'damping', 0.00001)) mat.add_actions( conditions=('they_have_material', self.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'friction', 0.0), ), ) return self._railing_material
# Docs-generation hack; import some stuff that we likely only forward-declared # in our actual source code so that docs tools can find it. from typing import (Coroutine, Any, Literal, Callable, Generator, Awaitable, Sequence, Self) import asyncio from concurrent.futures import Future from pathlib import Path from enum import Enum