bastd.actor.onscreencountdown
Defines Actor Type(s).
1# Released under the MIT License. See LICENSE for details. 2# 3"""Defines Actor Type(s).""" 4 5from __future__ import annotations 6 7from typing import TYPE_CHECKING 8 9import ba 10 11if TYPE_CHECKING: 12 from typing import Any, Callable 13 14 15class OnScreenCountdown(ba.Actor): 16 """A Handy On-Screen Timer. 17 18 category: Gameplay Classes 19 20 Useful for time-based games that count down to zero. 21 """ 22 23 def __init__(self, 24 duration: int, 25 endcall: Callable[[], Any] | None = None): 26 """Duration is provided in seconds.""" 27 super().__init__() 28 self._timeremaining = duration 29 self._ended = False 30 self._endcall = endcall 31 self.node = ba.newnode('text', 32 attrs={ 33 'v_attach': 'top', 34 'h_attach': 'center', 35 'h_align': 'center', 36 'color': (1, 1, 0.5, 1), 37 'flatness': 0.5, 38 'shadow': 0.5, 39 'position': (0, -70), 40 'scale': 1.4, 41 'text': '' 42 }) 43 self.inputnode = ba.newnode('timedisplay', 44 attrs={ 45 'time2': duration * 1000, 46 'timemax': duration * 1000, 47 'timemin': 0 48 }) 49 self.inputnode.connectattr('output', self.node, 'text') 50 self._countdownsounds = { 51 10: ba.getsound('announceTen'), 52 9: ba.getsound('announceNine'), 53 8: ba.getsound('announceEight'), 54 7: ba.getsound('announceSeven'), 55 6: ba.getsound('announceSix'), 56 5: ba.getsound('announceFive'), 57 4: ba.getsound('announceFour'), 58 3: ba.getsound('announceThree'), 59 2: ba.getsound('announceTwo'), 60 1: ba.getsound('announceOne') 61 } 62 self._timer: ba.Timer | None = None 63 64 def start(self) -> None: 65 """Start the timer.""" 66 globalsnode = ba.getactivity().globalsnode 67 globalsnode.connectattr('time', self.inputnode, 'time1') 68 self.inputnode.time2 = (globalsnode.time + 69 (self._timeremaining + 1) * 1000) 70 self._timer = ba.Timer(1.0, self._update, repeat=True) 71 72 def on_expire(self) -> None: 73 super().on_expire() 74 75 # Release callbacks/refs. 76 self._endcall = None 77 78 def _update(self, forcevalue: int | None = None) -> None: 79 if forcevalue is not None: 80 tval = forcevalue 81 else: 82 self._timeremaining = max(0, self._timeremaining - 1) 83 tval = self._timeremaining 84 85 # if there's a countdown sound for this time that we 86 # haven't played yet, play it 87 if tval == 10: 88 assert self.node 89 assert isinstance(self.node.scale, float) 90 self.node.scale *= 1.2 91 cmb = ba.newnode('combine', owner=self.node, attrs={'size': 4}) 92 cmb.connectattr('output', self.node, 'color') 93 ba.animate(cmb, 'input0', {0: 1.0, 0.15: 1.0}, loop=True) 94 ba.animate(cmb, 'input1', {0: 1.0, 0.15: 0.5}, loop=True) 95 ba.animate(cmb, 'input2', {0: 0.1, 0.15: 0.0}, loop=True) 96 cmb.input3 = 1.0 97 if tval <= 10 and not self._ended: 98 ba.playsound(ba.getsound('tick')) 99 if tval in self._countdownsounds: 100 ba.playsound(self._countdownsounds[tval]) 101 if tval <= 0 and not self._ended: 102 self._ended = True 103 if self._endcall is not None: 104 self._endcall()
class
OnScreenCountdown(ba._actor.Actor):
16class OnScreenCountdown(ba.Actor): 17 """A Handy On-Screen Timer. 18 19 category: Gameplay Classes 20 21 Useful for time-based games that count down to zero. 22 """ 23 24 def __init__(self, 25 duration: int, 26 endcall: Callable[[], Any] | None = None): 27 """Duration is provided in seconds.""" 28 super().__init__() 29 self._timeremaining = duration 30 self._ended = False 31 self._endcall = endcall 32 self.node = ba.newnode('text', 33 attrs={ 34 'v_attach': 'top', 35 'h_attach': 'center', 36 'h_align': 'center', 37 'color': (1, 1, 0.5, 1), 38 'flatness': 0.5, 39 'shadow': 0.5, 40 'position': (0, -70), 41 'scale': 1.4, 42 'text': '' 43 }) 44 self.inputnode = ba.newnode('timedisplay', 45 attrs={ 46 'time2': duration * 1000, 47 'timemax': duration * 1000, 48 'timemin': 0 49 }) 50 self.inputnode.connectattr('output', self.node, 'text') 51 self._countdownsounds = { 52 10: ba.getsound('announceTen'), 53 9: ba.getsound('announceNine'), 54 8: ba.getsound('announceEight'), 55 7: ba.getsound('announceSeven'), 56 6: ba.getsound('announceSix'), 57 5: ba.getsound('announceFive'), 58 4: ba.getsound('announceFour'), 59 3: ba.getsound('announceThree'), 60 2: ba.getsound('announceTwo'), 61 1: ba.getsound('announceOne') 62 } 63 self._timer: ba.Timer | None = None 64 65 def start(self) -> None: 66 """Start the timer.""" 67 globalsnode = ba.getactivity().globalsnode 68 globalsnode.connectattr('time', self.inputnode, 'time1') 69 self.inputnode.time2 = (globalsnode.time + 70 (self._timeremaining + 1) * 1000) 71 self._timer = ba.Timer(1.0, self._update, repeat=True) 72 73 def on_expire(self) -> None: 74 super().on_expire() 75 76 # Release callbacks/refs. 77 self._endcall = None 78 79 def _update(self, forcevalue: int | None = None) -> None: 80 if forcevalue is not None: 81 tval = forcevalue 82 else: 83 self._timeremaining = max(0, self._timeremaining - 1) 84 tval = self._timeremaining 85 86 # if there's a countdown sound for this time that we 87 # haven't played yet, play it 88 if tval == 10: 89 assert self.node 90 assert isinstance(self.node.scale, float) 91 self.node.scale *= 1.2 92 cmb = ba.newnode('combine', owner=self.node, attrs={'size': 4}) 93 cmb.connectattr('output', self.node, 'color') 94 ba.animate(cmb, 'input0', {0: 1.0, 0.15: 1.0}, loop=True) 95 ba.animate(cmb, 'input1', {0: 1.0, 0.15: 0.5}, loop=True) 96 ba.animate(cmb, 'input2', {0: 0.1, 0.15: 0.0}, loop=True) 97 cmb.input3 = 1.0 98 if tval <= 10 and not self._ended: 99 ba.playsound(ba.getsound('tick')) 100 if tval in self._countdownsounds: 101 ba.playsound(self._countdownsounds[tval]) 102 if tval <= 0 and not self._ended: 103 self._ended = True 104 if self._endcall is not None: 105 self._endcall()
A Handy On-Screen Timer.
category: Gameplay Classes
Useful for time-based games that count down to zero.
OnScreenCountdown(duration: int, endcall: Optional[Callable[[], Any]] = None)
24 def __init__(self, 25 duration: int, 26 endcall: Callable[[], Any] | None = None): 27 """Duration is provided in seconds.""" 28 super().__init__() 29 self._timeremaining = duration 30 self._ended = False 31 self._endcall = endcall 32 self.node = ba.newnode('text', 33 attrs={ 34 'v_attach': 'top', 35 'h_attach': 'center', 36 'h_align': 'center', 37 'color': (1, 1, 0.5, 1), 38 'flatness': 0.5, 39 'shadow': 0.5, 40 'position': (0, -70), 41 'scale': 1.4, 42 'text': '' 43 }) 44 self.inputnode = ba.newnode('timedisplay', 45 attrs={ 46 'time2': duration * 1000, 47 'timemax': duration * 1000, 48 'timemin': 0 49 }) 50 self.inputnode.connectattr('output', self.node, 'text') 51 self._countdownsounds = { 52 10: ba.getsound('announceTen'), 53 9: ba.getsound('announceNine'), 54 8: ba.getsound('announceEight'), 55 7: ba.getsound('announceSeven'), 56 6: ba.getsound('announceSix'), 57 5: ba.getsound('announceFive'), 58 4: ba.getsound('announceFour'), 59 3: ba.getsound('announceThree'), 60 2: ba.getsound('announceTwo'), 61 1: ba.getsound('announceOne') 62 } 63 self._timer: ba.Timer | None = None
Duration is provided in seconds.
def
start(self) -> None:
65 def start(self) -> None: 66 """Start the timer.""" 67 globalsnode = ba.getactivity().globalsnode 68 globalsnode.connectattr('time', self.inputnode, 'time1') 69 self.inputnode.time2 = (globalsnode.time + 70 (self._timeremaining + 1) * 1000) 71 self._timer = ba.Timer(1.0, self._update, repeat=True)
Start the timer.
def
on_expire(self) -> None:
73 def on_expire(self) -> None: 74 super().on_expire() 75 76 # Release callbacks/refs. 77 self._endcall = None
Called for remaining ba.Actor
s when their ba.Activity shuts down.
Actors can use this opportunity to clear callbacks or other references which have the potential of keeping the ba.Activity alive inadvertently (Activities can not exit cleanly while any Python references to them remain.)
Once an actor is expired (see ba.Actor.is_expired()) it should no longer perform any game-affecting operations (creating, modifying, or deleting nodes, media, timers, etc.) Attempts to do so will likely result in errors.
Inherited Members
- ba._actor.Actor
- handlemessage
- autoretain
- expired
- exists
- is_alive
- activity
- getactivity