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.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.
@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