bascenev1lib.actor.zoomtext

Defined Actor(s).

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Defined Actor(s)."""
  4
  5from __future__ import annotations
  6
  7import random
  8import logging
  9from typing import TYPE_CHECKING, override
 10
 11import bascenev1 as bs
 12
 13if TYPE_CHECKING:
 14    from typing import Any, Sequence
 15
 16
 17class ZoomText(bs.Actor):
 18    """Big Zooming Text.
 19
 20    Category: Gameplay Classes
 21
 22    Used for things such as the 'BOB WINS' victory messages.
 23    """
 24
 25    def __init__(
 26        self,
 27        text: str | bs.Lstr,
 28        position: tuple[float, float] = (0.0, 0.0),
 29        shiftposition: tuple[float, float] | None = None,
 30        shiftdelay: float | None = None,
 31        lifespan: float | None = None,
 32        flash: bool = True,
 33        trail: bool = True,
 34        h_align: str = 'center',
 35        color: Sequence[float] = (0.9, 0.4, 0.0),
 36        jitter: float = 0.0,
 37        trailcolor: Sequence[float] = (1.0, 0.35, 0.1, 0.0),
 38        scale: float = 1.0,
 39        project_scale: float = 1.0,
 40        tilt_translate: float = 0.0,
 41        maxwidth: float | None = None,
 42    ):
 43        # pylint: disable=too-many-locals
 44        super().__init__()
 45        self._dying = False
 46        positionadjusted = (position[0], position[1] - 100)
 47        if shiftdelay is None:
 48            shiftdelay = 2.500
 49        if shiftdelay < 0.0:
 50            logging.error('got shiftdelay < 0')
 51            shiftdelay = 0.0
 52        self._project_scale = project_scale
 53        self.node = bs.newnode(
 54            'text',
 55            delegate=self,
 56            attrs={
 57                'position': positionadjusted,
 58                'big': True,
 59                'text': text,
 60                'trail': trail,
 61                'vr_depth': 0,
 62                'shadow': 0.0 if trail else 0.3,
 63                'scale': scale,
 64                'maxwidth': maxwidth if maxwidth is not None else 0.0,
 65                'tilt_translate': tilt_translate,
 66                'h_align': h_align,
 67                'v_align': 'center',
 68            },
 69        )
 70
 71        # we never jitter in vr mode..
 72        if bs.app.env.vr:
 73            jitter = 0.0
 74
 75        # if they want jitter, animate its position slightly...
 76        if jitter > 0.0:
 77            self._jitter(positionadjusted, jitter * scale)
 78
 79        # if they want shifting, move to the shift position and
 80        # then resume jittering
 81        if shiftposition is not None:
 82            positionadjusted2 = (shiftposition[0], shiftposition[1] - 100)
 83            bs.timer(
 84                shiftdelay,
 85                bs.WeakCall(self._shift, positionadjusted, positionadjusted2),
 86            )
 87            if jitter > 0.0:
 88                bs.timer(
 89                    shiftdelay + 0.25,
 90                    bs.WeakCall(
 91                        self._jitter, positionadjusted2, jitter * scale
 92                    ),
 93                )
 94        color_combine = bs.newnode(
 95            'combine',
 96            owner=self.node,
 97            attrs={'input2': color[2], 'input3': 1.0, 'size': 4},
 98        )
 99        if trail:
100            trailcolor_n = bs.newnode(
101                'combine',
102                owner=self.node,
103                attrs={
104                    'size': 3,
105                    'input0': trailcolor[0],
106                    'input1': trailcolor[1],
107                    'input2': trailcolor[2],
108                },
109            )
110            trailcolor_n.connectattr('output', self.node, 'trailcolor')
111            basemult = 0.85
112            bs.animate(
113                self.node,
114                'trail_project_scale',
115                {
116                    0: 0 * project_scale,
117                    basemult * 0.201: 0.6 * project_scale,
118                    basemult * 0.347: 0.8 * project_scale,
119                    basemult * 0.478: 0.9 * project_scale,
120                    basemult * 0.595: 0.93 * project_scale,
121                    basemult * 0.748: 0.95 * project_scale,
122                    basemult * 0.941: 0.95 * project_scale,
123                },
124            )
125        if flash:
126            mult = 2.0
127            tm1 = 0.15
128            tm2 = 0.3
129            bs.animate(
130                color_combine,
131                'input0',
132                {0: color[0] * mult, tm1: color[0], tm2: color[0] * mult},
133                loop=True,
134            )
135            bs.animate(
136                color_combine,
137                'input1',
138                {0: color[1] * mult, tm1: color[1], tm2: color[1] * mult},
139                loop=True,
140            )
141            bs.animate(
142                color_combine,
143                'input2',
144                {0: color[2] * mult, tm1: color[2], tm2: color[2] * mult},
145                loop=True,
146            )
147        else:
148            color_combine.input0 = color[0]
149            color_combine.input1 = color[1]
150        color_combine.connectattr('output', self.node, 'color')
151        bs.animate(
152            self.node,
153            'project_scale',
154            {0: 0, 0.27: 1.05 * project_scale, 0.3: 1 * project_scale},
155        )
156
157        # if they give us a lifespan, kill ourself down the line
158        if lifespan is not None:
159            bs.timer(lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage()))
160
161    @override
162    def handlemessage(self, msg: Any) -> Any:
163        assert not self.expired
164        if isinstance(msg, bs.DieMessage):
165            if not self._dying and self.node:
166                self._dying = True
167                if msg.immediate:
168                    self.node.delete()
169                else:
170                    bs.animate(
171                        self.node,
172                        'project_scale',
173                        {
174                            0.0: 1 * self._project_scale,
175                            0.6: 1.2 * self._project_scale,
176                        },
177                    )
178                    bs.animate(self.node, 'opacity', {0.0: 1, 0.3: 0})
179                    bs.animate(self.node, 'trail_opacity', {0.0: 1, 0.6: 0})
180                    bs.timer(0.7, self.node.delete)
181            return None
182        return super().handlemessage(msg)
183
184    def _jitter(
185        self, position: tuple[float, float], jitter_amount: float
186    ) -> None:
187        if not self.node:
188            return
189        cmb = bs.newnode('combine', owner=self.node, attrs={'size': 2})
190        for index, attr in enumerate(['input0', 'input1']):
191            keys = {}
192            timeval = 0.0
193            # gen some random keys for that stop-motion-y look
194            for _i in range(10):
195                keys[timeval] = (
196                    position[index]
197                    + (random.random() - 0.5) * jitter_amount * 1.6
198                )
199                timeval += random.random() * 0.1
200            bs.animate(cmb, attr, keys, loop=True)
201        cmb.connectattr('output', self.node, 'position')
202
203    def _shift(
204        self, position1: tuple[float, float], position2: tuple[float, float]
205    ) -> None:
206        if not self.node:
207            return
208        cmb = bs.newnode('combine', owner=self.node, attrs={'size': 2})
209        bs.animate(cmb, 'input0', {0.0: position1[0], 0.25: position2[0]})
210        bs.animate(cmb, 'input1', {0.0: position1[1], 0.25: position2[1]})
211        cmb.connectattr('output', self.node, 'position')
class ZoomText(bascenev1._actor.Actor):
 18class ZoomText(bs.Actor):
 19    """Big Zooming Text.
 20
 21    Category: Gameplay Classes
 22
 23    Used for things such as the 'BOB WINS' victory messages.
 24    """
 25
 26    def __init__(
 27        self,
 28        text: str | bs.Lstr,
 29        position: tuple[float, float] = (0.0, 0.0),
 30        shiftposition: tuple[float, float] | None = None,
 31        shiftdelay: float | None = None,
 32        lifespan: float | None = None,
 33        flash: bool = True,
 34        trail: bool = True,
 35        h_align: str = 'center',
 36        color: Sequence[float] = (0.9, 0.4, 0.0),
 37        jitter: float = 0.0,
 38        trailcolor: Sequence[float] = (1.0, 0.35, 0.1, 0.0),
 39        scale: float = 1.0,
 40        project_scale: float = 1.0,
 41        tilt_translate: float = 0.0,
 42        maxwidth: float | None = None,
 43    ):
 44        # pylint: disable=too-many-locals
 45        super().__init__()
 46        self._dying = False
 47        positionadjusted = (position[0], position[1] - 100)
 48        if shiftdelay is None:
 49            shiftdelay = 2.500
 50        if shiftdelay < 0.0:
 51            logging.error('got shiftdelay < 0')
 52            shiftdelay = 0.0
 53        self._project_scale = project_scale
 54        self.node = bs.newnode(
 55            'text',
 56            delegate=self,
 57            attrs={
 58                'position': positionadjusted,
 59                'big': True,
 60                'text': text,
 61                'trail': trail,
 62                'vr_depth': 0,
 63                'shadow': 0.0 if trail else 0.3,
 64                'scale': scale,
 65                'maxwidth': maxwidth if maxwidth is not None else 0.0,
 66                'tilt_translate': tilt_translate,
 67                'h_align': h_align,
 68                'v_align': 'center',
 69            },
 70        )
 71
 72        # we never jitter in vr mode..
 73        if bs.app.env.vr:
 74            jitter = 0.0
 75
 76        # if they want jitter, animate its position slightly...
 77        if jitter > 0.0:
 78            self._jitter(positionadjusted, jitter * scale)
 79
 80        # if they want shifting, move to the shift position and
 81        # then resume jittering
 82        if shiftposition is not None:
 83            positionadjusted2 = (shiftposition[0], shiftposition[1] - 100)
 84            bs.timer(
 85                shiftdelay,
 86                bs.WeakCall(self._shift, positionadjusted, positionadjusted2),
 87            )
 88            if jitter > 0.0:
 89                bs.timer(
 90                    shiftdelay + 0.25,
 91                    bs.WeakCall(
 92                        self._jitter, positionadjusted2, jitter * scale
 93                    ),
 94                )
 95        color_combine = bs.newnode(
 96            'combine',
 97            owner=self.node,
 98            attrs={'input2': color[2], 'input3': 1.0, 'size': 4},
 99        )
100        if trail:
101            trailcolor_n = bs.newnode(
102                'combine',
103                owner=self.node,
104                attrs={
105                    'size': 3,
106                    'input0': trailcolor[0],
107                    'input1': trailcolor[1],
108                    'input2': trailcolor[2],
109                },
110            )
111            trailcolor_n.connectattr('output', self.node, 'trailcolor')
112            basemult = 0.85
113            bs.animate(
114                self.node,
115                'trail_project_scale',
116                {
117                    0: 0 * project_scale,
118                    basemult * 0.201: 0.6 * project_scale,
119                    basemult * 0.347: 0.8 * project_scale,
120                    basemult * 0.478: 0.9 * project_scale,
121                    basemult * 0.595: 0.93 * project_scale,
122                    basemult * 0.748: 0.95 * project_scale,
123                    basemult * 0.941: 0.95 * project_scale,
124                },
125            )
126        if flash:
127            mult = 2.0
128            tm1 = 0.15
129            tm2 = 0.3
130            bs.animate(
131                color_combine,
132                'input0',
133                {0: color[0] * mult, tm1: color[0], tm2: color[0] * mult},
134                loop=True,
135            )
136            bs.animate(
137                color_combine,
138                'input1',
139                {0: color[1] * mult, tm1: color[1], tm2: color[1] * mult},
140                loop=True,
141            )
142            bs.animate(
143                color_combine,
144                'input2',
145                {0: color[2] * mult, tm1: color[2], tm2: color[2] * mult},
146                loop=True,
147            )
148        else:
149            color_combine.input0 = color[0]
150            color_combine.input1 = color[1]
151        color_combine.connectattr('output', self.node, 'color')
152        bs.animate(
153            self.node,
154            'project_scale',
155            {0: 0, 0.27: 1.05 * project_scale, 0.3: 1 * project_scale},
156        )
157
158        # if they give us a lifespan, kill ourself down the line
159        if lifespan is not None:
160            bs.timer(lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage()))
161
162    @override
163    def handlemessage(self, msg: Any) -> Any:
164        assert not self.expired
165        if isinstance(msg, bs.DieMessage):
166            if not self._dying and self.node:
167                self._dying = True
168                if msg.immediate:
169                    self.node.delete()
170                else:
171                    bs.animate(
172                        self.node,
173                        'project_scale',
174                        {
175                            0.0: 1 * self._project_scale,
176                            0.6: 1.2 * self._project_scale,
177                        },
178                    )
179                    bs.animate(self.node, 'opacity', {0.0: 1, 0.3: 0})
180                    bs.animate(self.node, 'trail_opacity', {0.0: 1, 0.6: 0})
181                    bs.timer(0.7, self.node.delete)
182            return None
183        return super().handlemessage(msg)
184
185    def _jitter(
186        self, position: tuple[float, float], jitter_amount: float
187    ) -> None:
188        if not self.node:
189            return
190        cmb = bs.newnode('combine', owner=self.node, attrs={'size': 2})
191        for index, attr in enumerate(['input0', 'input1']):
192            keys = {}
193            timeval = 0.0
194            # gen some random keys for that stop-motion-y look
195            for _i in range(10):
196                keys[timeval] = (
197                    position[index]
198                    + (random.random() - 0.5) * jitter_amount * 1.6
199                )
200                timeval += random.random() * 0.1
201            bs.animate(cmb, attr, keys, loop=True)
202        cmb.connectattr('output', self.node, 'position')
203
204    def _shift(
205        self, position1: tuple[float, float], position2: tuple[float, float]
206    ) -> None:
207        if not self.node:
208            return
209        cmb = bs.newnode('combine', owner=self.node, attrs={'size': 2})
210        bs.animate(cmb, 'input0', {0.0: position1[0], 0.25: position2[0]})
211        bs.animate(cmb, 'input1', {0.0: position1[1], 0.25: position2[1]})
212        cmb.connectattr('output', self.node, 'position')

Big Zooming Text.

Category: Gameplay Classes

Used for things such as the 'BOB WINS' victory messages.

ZoomText( text: str | babase._language.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)
 26    def __init__(
 27        self,
 28        text: str | bs.Lstr,
 29        position: tuple[float, float] = (0.0, 0.0),
 30        shiftposition: tuple[float, float] | None = None,
 31        shiftdelay: float | None = None,
 32        lifespan: float | None = None,
 33        flash: bool = True,
 34        trail: bool = True,
 35        h_align: str = 'center',
 36        color: Sequence[float] = (0.9, 0.4, 0.0),
 37        jitter: float = 0.0,
 38        trailcolor: Sequence[float] = (1.0, 0.35, 0.1, 0.0),
 39        scale: float = 1.0,
 40        project_scale: float = 1.0,
 41        tilt_translate: float = 0.0,
 42        maxwidth: float | None = None,
 43    ):
 44        # pylint: disable=too-many-locals
 45        super().__init__()
 46        self._dying = False
 47        positionadjusted = (position[0], position[1] - 100)
 48        if shiftdelay is None:
 49            shiftdelay = 2.500
 50        if shiftdelay < 0.0:
 51            logging.error('got shiftdelay < 0')
 52            shiftdelay = 0.0
 53        self._project_scale = project_scale
 54        self.node = bs.newnode(
 55            'text',
 56            delegate=self,
 57            attrs={
 58                'position': positionadjusted,
 59                'big': True,
 60                'text': text,
 61                'trail': trail,
 62                'vr_depth': 0,
 63                'shadow': 0.0 if trail else 0.3,
 64                'scale': scale,
 65                'maxwidth': maxwidth if maxwidth is not None else 0.0,
 66                'tilt_translate': tilt_translate,
 67                'h_align': h_align,
 68                'v_align': 'center',
 69            },
 70        )
 71
 72        # we never jitter in vr mode..
 73        if bs.app.env.vr:
 74            jitter = 0.0
 75
 76        # if they want jitter, animate its position slightly...
 77        if jitter > 0.0:
 78            self._jitter(positionadjusted, jitter * scale)
 79
 80        # if they want shifting, move to the shift position and
 81        # then resume jittering
 82        if shiftposition is not None:
 83            positionadjusted2 = (shiftposition[0], shiftposition[1] - 100)
 84            bs.timer(
 85                shiftdelay,
 86                bs.WeakCall(self._shift, positionadjusted, positionadjusted2),
 87            )
 88            if jitter > 0.0:
 89                bs.timer(
 90                    shiftdelay + 0.25,
 91                    bs.WeakCall(
 92                        self._jitter, positionadjusted2, jitter * scale
 93                    ),
 94                )
 95        color_combine = bs.newnode(
 96            'combine',
 97            owner=self.node,
 98            attrs={'input2': color[2], 'input3': 1.0, 'size': 4},
 99        )
100        if trail:
101            trailcolor_n = bs.newnode(
102                'combine',
103                owner=self.node,
104                attrs={
105                    'size': 3,
106                    'input0': trailcolor[0],
107                    'input1': trailcolor[1],
108                    'input2': trailcolor[2],
109                },
110            )
111            trailcolor_n.connectattr('output', self.node, 'trailcolor')
112            basemult = 0.85
113            bs.animate(
114                self.node,
115                'trail_project_scale',
116                {
117                    0: 0 * project_scale,
118                    basemult * 0.201: 0.6 * project_scale,
119                    basemult * 0.347: 0.8 * project_scale,
120                    basemult * 0.478: 0.9 * project_scale,
121                    basemult * 0.595: 0.93 * project_scale,
122                    basemult * 0.748: 0.95 * project_scale,
123                    basemult * 0.941: 0.95 * project_scale,
124                },
125            )
126        if flash:
127            mult = 2.0
128            tm1 = 0.15
129            tm2 = 0.3
130            bs.animate(
131                color_combine,
132                'input0',
133                {0: color[0] * mult, tm1: color[0], tm2: color[0] * mult},
134                loop=True,
135            )
136            bs.animate(
137                color_combine,
138                'input1',
139                {0: color[1] * mult, tm1: color[1], tm2: color[1] * mult},
140                loop=True,
141            )
142            bs.animate(
143                color_combine,
144                'input2',
145                {0: color[2] * mult, tm1: color[2], tm2: color[2] * mult},
146                loop=True,
147            )
148        else:
149            color_combine.input0 = color[0]
150            color_combine.input1 = color[1]
151        color_combine.connectattr('output', self.node, 'color')
152        bs.animate(
153            self.node,
154            'project_scale',
155            {0: 0, 0.27: 1.05 * project_scale, 0.3: 1 * project_scale},
156        )
157
158        # if they give us a lifespan, kill ourself down the line
159        if lifespan is not None:
160            bs.timer(lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage()))

Instantiates an Actor in the current bascenev1.Activity.

node
@override
def handlemessage(self, msg: Any) -> Any:
162    @override
163    def handlemessage(self, msg: Any) -> Any:
164        assert not self.expired
165        if isinstance(msg, bs.DieMessage):
166            if not self._dying and self.node:
167                self._dying = True
168                if msg.immediate:
169                    self.node.delete()
170                else:
171                    bs.animate(
172                        self.node,
173                        'project_scale',
174                        {
175                            0.0: 1 * self._project_scale,
176                            0.6: 1.2 * self._project_scale,
177                        },
178                    )
179                    bs.animate(self.node, 'opacity', {0.0: 1, 0.3: 0})
180                    bs.animate(self.node, 'trail_opacity', {0.0: 1, 0.6: 0})
181                    bs.timer(0.7, self.node.delete)
182            return None
183        return super().handlemessage(msg)

General message handling; can be passed any message object.

Inherited Members
bascenev1._actor.Actor
autoretain
on_expire
expired
exists
is_alive
activity
getactivity