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