Source code for bascenev1lib.actor.zoomtext

# Released under the MIT License. See LICENSE for details.
#
"""Defined Actor(s)."""

from __future__ import annotations

import random
import logging
from typing import TYPE_CHECKING, override

import bascenev1 as bs

if TYPE_CHECKING:
    from typing import Any, Sequence


[docs] class ZoomText(bs.Actor): """Big Zooming Text. Category: Gameplay Classes Used for things such as the 'BOB WINS' victory messages. """ def __init__( self, text: str | bs.Lstr, position: tuple[float, float] = (0.0, 0.0), shiftposition: tuple[float, float] | None = None, shiftdelay: float | None = None, lifespan: float | None = None, flash: bool = True, trail: bool = True, h_align: str = 'center', color: Sequence[float] = (0.9, 0.4, 0.0), jitter: float = 0.0, trailcolor: Sequence[float] = (1.0, 0.35, 0.1, 0.0), scale: float = 1.0, project_scale: float = 1.0, tilt_translate: float = 0.0, maxwidth: float | None = None, ): # pylint: disable=too-many-locals super().__init__() self._dying = False positionadjusted = (position[0], position[1] - 100) if shiftdelay is None: shiftdelay = 2.500 if shiftdelay < 0.0: logging.error('got shiftdelay < 0') shiftdelay = 0.0 self._project_scale = project_scale self.node = bs.newnode( 'text', delegate=self, attrs={ 'position': positionadjusted, 'big': True, 'text': text, 'trail': trail, 'vr_depth': 0, 'shadow': 0.0 if trail else 0.3, 'scale': scale, 'maxwidth': maxwidth if maxwidth is not None else 0.0, 'tilt_translate': tilt_translate, 'h_align': h_align, 'v_align': 'center', }, ) # we never jitter in vr mode.. if bs.app.env.vr: jitter = 0.0 # if they want jitter, animate its position slightly... if jitter > 0.0: self._jitter(positionadjusted, jitter * scale) # if they want shifting, move to the shift position and # then resume jittering if shiftposition is not None: positionadjusted2 = (shiftposition[0], shiftposition[1] - 100) bs.timer( shiftdelay, bs.WeakCall(self._shift, positionadjusted, positionadjusted2), ) if jitter > 0.0: bs.timer( shiftdelay + 0.25, bs.WeakCall( self._jitter, positionadjusted2, jitter * scale ), ) color_combine = bs.newnode( 'combine', owner=self.node, attrs={'input2': color[2], 'input3': 1.0, 'size': 4}, ) if trail: trailcolor_n = bs.newnode( 'combine', owner=self.node, attrs={ 'size': 3, 'input0': trailcolor[0], 'input1': trailcolor[1], 'input2': trailcolor[2], }, ) trailcolor_n.connectattr('output', self.node, 'trailcolor') basemult = 0.85 bs.animate( self.node, 'trail_project_scale', { 0: 0 * project_scale, basemult * 0.201: 0.6 * project_scale, basemult * 0.347: 0.8 * project_scale, basemult * 0.478: 0.9 * project_scale, basemult * 0.595: 0.93 * project_scale, basemult * 0.748: 0.95 * project_scale, basemult * 0.941: 0.95 * project_scale, }, ) if flash: mult = 2.0 tm1 = 0.15 tm2 = 0.3 bs.animate( color_combine, 'input0', {0: color[0] * mult, tm1: color[0], tm2: color[0] * mult}, loop=True, ) bs.animate( color_combine, 'input1', {0: color[1] * mult, tm1: color[1], tm2: color[1] * mult}, loop=True, ) bs.animate( color_combine, 'input2', {0: color[2] * mult, tm1: color[2], tm2: color[2] * mult}, loop=True, ) else: color_combine.input0 = color[0] color_combine.input1 = color[1] color_combine.connectattr('output', self.node, 'color') bs.animate( self.node, 'project_scale', {0: 0, 0.27: 1.05 * project_scale, 0.3: 1 * project_scale}, ) # if they give us a lifespan, kill ourself down the line if lifespan is not None: bs.timer(lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage()))
[docs] @override def handlemessage(self, msg: Any) -> Any: assert not self.expired if isinstance(msg, bs.DieMessage): if not self._dying and self.node: self._dying = True if msg.immediate: self.node.delete() else: bs.animate( self.node, 'project_scale', { 0.0: 1 * self._project_scale, 0.6: 1.2 * self._project_scale, }, ) bs.animate(self.node, 'opacity', {0.0: 1, 0.3: 0}) bs.animate(self.node, 'trail_opacity', {0.0: 1, 0.6: 0}) bs.timer(0.7, self.node.delete) return None return super().handlemessage(msg)
def _jitter( self, position: tuple[float, float], jitter_amount: float ) -> None: if not self.node: return cmb = bs.newnode('combine', owner=self.node, attrs={'size': 2}) for index, attr in enumerate(['input0', 'input1']): keys = {} timeval = 0.0 # gen some random keys for that stop-motion-y look for _i in range(10): keys[timeval] = ( position[index] + (random.random() - 0.5) * jitter_amount * 1.6 ) timeval += random.random() * 0.1 bs.animate(cmb, attr, keys, loop=True) cmb.connectattr('output', self.node, 'position') def _shift( self, position1: tuple[float, float], position2: tuple[float, float] ) -> None: if not self.node: return cmb = bs.newnode('combine', owner=self.node, attrs={'size': 2}) bs.animate(cmb, 'input0', {0.0: position1[0], 0.25: position2[0]}) bs.animate(cmb, 'input1', {0.0: position1[1], 0.25: position2[1]}) cmb.connectattr('output', self.node, 'position')