bastd.actor.onscreentimer
Defines Actor(s).
1# Released under the MIT License. See LICENSE for details. 2# 3"""Defines Actor(s).""" 4from __future__ import annotations 5 6from typing import TYPE_CHECKING, overload 7 8import ba 9 10if TYPE_CHECKING: 11 from typing import Any, Literal 12 13 14class OnScreenTimer(ba.Actor): 15 """A handy on-screen timer. 16 17 category: Gameplay Classes 18 19 Useful for time-based games where time increases. 20 """ 21 22 def __init__(self) -> None: 23 super().__init__() 24 self._starttime_ms: int | None = None 25 self.node = ba.newnode( 26 'text', 27 attrs={ 28 'v_attach': 'top', 29 'h_attach': 'center', 30 'h_align': 'center', 31 'color': (1, 1, 0.5, 1), 32 'flatness': 0.5, 33 'shadow': 0.5, 34 'position': (0, -70), 35 'scale': 1.4, 36 'text': '', 37 }, 38 ) 39 self.inputnode = ba.newnode( 40 'timedisplay', attrs={'timemin': 0, 'showsubseconds': True} 41 ) 42 self.inputnode.connectattr('output', self.node, 'text') 43 44 def start(self) -> None: 45 """Start the timer.""" 46 tval = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) 47 assert isinstance(tval, int) 48 self._starttime_ms = tval 49 self.inputnode.time1 = self._starttime_ms 50 ba.getactivity().globalsnode.connectattr( 51 'time', self.inputnode, 'time2' 52 ) 53 54 def has_started(self) -> bool: 55 """Return whether this timer has started yet.""" 56 return self._starttime_ms is not None 57 58 def stop( 59 self, 60 endtime: int | float | None = None, 61 timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS, 62 ) -> None: 63 """End the timer. 64 65 If 'endtime' is not None, it is used when calculating 66 the final display time; otherwise the current time is used. 67 68 'timeformat' applies to endtime and can be SECONDS or MILLISECONDS 69 """ 70 if endtime is None: 71 endtime = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) 72 timeformat = ba.TimeFormat.MILLISECONDS 73 74 if self._starttime_ms is None: 75 print('Warning: OnScreenTimer.stop() called without start() first') 76 else: 77 endtime_ms: int 78 if timeformat is ba.TimeFormat.SECONDS: 79 endtime_ms = int(endtime * 1000) 80 elif timeformat is ba.TimeFormat.MILLISECONDS: 81 assert isinstance(endtime, int) 82 endtime_ms = endtime 83 else: 84 raise ValueError(f'invalid timeformat: {timeformat}') 85 86 self.inputnode.timemax = endtime_ms - self._starttime_ms 87 88 # Overloads so type checker knows our exact return type based in args. 89 @overload 90 def getstarttime( 91 self, timeformat: Literal[ba.TimeFormat.SECONDS] = ba.TimeFormat.SECONDS 92 ) -> float: 93 ... 94 95 @overload 96 def getstarttime( 97 self, timeformat: Literal[ba.TimeFormat.MILLISECONDS] 98 ) -> int: 99 ... 100 101 def getstarttime( 102 self, timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS 103 ) -> int | float: 104 """Return the sim-time when start() was called. 105 106 Time will be returned in seconds if timeformat is SECONDS or 107 milliseconds if it is MILLISECONDS. 108 """ 109 val_ms: Any 110 if self._starttime_ms is None: 111 print('WARNING: getstarttime() called on un-started timer') 112 val_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) 113 else: 114 val_ms = self._starttime_ms 115 assert isinstance(val_ms, int) 116 if timeformat is ba.TimeFormat.SECONDS: 117 return 0.001 * val_ms 118 if timeformat is ba.TimeFormat.MILLISECONDS: 119 return val_ms 120 raise ValueError(f'invalid timeformat: {timeformat}') 121 122 @property 123 def starttime(self) -> float: 124 """Shortcut for start time in seconds.""" 125 return self.getstarttime() 126 127 def handlemessage(self, msg: Any) -> Any: 128 # if we're asked to die, just kill our node/timer 129 if isinstance(msg, ba.DieMessage): 130 if self.node: 131 self.node.delete()
class
OnScreenTimer(ba._actor.Actor):
15class OnScreenTimer(ba.Actor): 16 """A handy on-screen timer. 17 18 category: Gameplay Classes 19 20 Useful for time-based games where time increases. 21 """ 22 23 def __init__(self) -> None: 24 super().__init__() 25 self._starttime_ms: int | None = None 26 self.node = ba.newnode( 27 'text', 28 attrs={ 29 'v_attach': 'top', 30 'h_attach': 'center', 31 'h_align': 'center', 32 'color': (1, 1, 0.5, 1), 33 'flatness': 0.5, 34 'shadow': 0.5, 35 'position': (0, -70), 36 'scale': 1.4, 37 'text': '', 38 }, 39 ) 40 self.inputnode = ba.newnode( 41 'timedisplay', attrs={'timemin': 0, 'showsubseconds': True} 42 ) 43 self.inputnode.connectattr('output', self.node, 'text') 44 45 def start(self) -> None: 46 """Start the timer.""" 47 tval = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) 48 assert isinstance(tval, int) 49 self._starttime_ms = tval 50 self.inputnode.time1 = self._starttime_ms 51 ba.getactivity().globalsnode.connectattr( 52 'time', self.inputnode, 'time2' 53 ) 54 55 def has_started(self) -> bool: 56 """Return whether this timer has started yet.""" 57 return self._starttime_ms is not None 58 59 def stop( 60 self, 61 endtime: int | float | None = None, 62 timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS, 63 ) -> None: 64 """End the timer. 65 66 If 'endtime' is not None, it is used when calculating 67 the final display time; otherwise the current time is used. 68 69 'timeformat' applies to endtime and can be SECONDS or MILLISECONDS 70 """ 71 if endtime is None: 72 endtime = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) 73 timeformat = ba.TimeFormat.MILLISECONDS 74 75 if self._starttime_ms is None: 76 print('Warning: OnScreenTimer.stop() called without start() first') 77 else: 78 endtime_ms: int 79 if timeformat is ba.TimeFormat.SECONDS: 80 endtime_ms = int(endtime * 1000) 81 elif timeformat is ba.TimeFormat.MILLISECONDS: 82 assert isinstance(endtime, int) 83 endtime_ms = endtime 84 else: 85 raise ValueError(f'invalid timeformat: {timeformat}') 86 87 self.inputnode.timemax = endtime_ms - self._starttime_ms 88 89 # Overloads so type checker knows our exact return type based in args. 90 @overload 91 def getstarttime( 92 self, timeformat: Literal[ba.TimeFormat.SECONDS] = ba.TimeFormat.SECONDS 93 ) -> float: 94 ... 95 96 @overload 97 def getstarttime( 98 self, timeformat: Literal[ba.TimeFormat.MILLISECONDS] 99 ) -> int: 100 ... 101 102 def getstarttime( 103 self, timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS 104 ) -> int | float: 105 """Return the sim-time when start() was called. 106 107 Time will be returned in seconds if timeformat is SECONDS or 108 milliseconds if it is MILLISECONDS. 109 """ 110 val_ms: Any 111 if self._starttime_ms is None: 112 print('WARNING: getstarttime() called on un-started timer') 113 val_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) 114 else: 115 val_ms = self._starttime_ms 116 assert isinstance(val_ms, int) 117 if timeformat is ba.TimeFormat.SECONDS: 118 return 0.001 * val_ms 119 if timeformat is ba.TimeFormat.MILLISECONDS: 120 return val_ms 121 raise ValueError(f'invalid timeformat: {timeformat}') 122 123 @property 124 def starttime(self) -> float: 125 """Shortcut for start time in seconds.""" 126 return self.getstarttime() 127 128 def handlemessage(self, msg: Any) -> Any: 129 # if we're asked to die, just kill our node/timer 130 if isinstance(msg, ba.DieMessage): 131 if self.node: 132 self.node.delete()
A handy on-screen timer.
category: Gameplay Classes
Useful for time-based games where time increases.
OnScreenTimer()
23 def __init__(self) -> None: 24 super().__init__() 25 self._starttime_ms: int | None = None 26 self.node = ba.newnode( 27 'text', 28 attrs={ 29 'v_attach': 'top', 30 'h_attach': 'center', 31 'h_align': 'center', 32 'color': (1, 1, 0.5, 1), 33 'flatness': 0.5, 34 'shadow': 0.5, 35 'position': (0, -70), 36 'scale': 1.4, 37 'text': '', 38 }, 39 ) 40 self.inputnode = ba.newnode( 41 'timedisplay', attrs={'timemin': 0, 'showsubseconds': True} 42 ) 43 self.inputnode.connectattr('output', self.node, 'text')
Instantiates an Actor in the current ba.Activity.
def
start(self) -> None:
45 def start(self) -> None: 46 """Start the timer.""" 47 tval = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) 48 assert isinstance(tval, int) 49 self._starttime_ms = tval 50 self.inputnode.time1 = self._starttime_ms 51 ba.getactivity().globalsnode.connectattr( 52 'time', self.inputnode, 'time2' 53 )
Start the timer.
def
has_started(self) -> bool:
55 def has_started(self) -> bool: 56 """Return whether this timer has started yet.""" 57 return self._starttime_ms is not None
Return whether this timer has started yet.
def
stop( self, endtime: int | float | None = None, timeformat: ba._generated.enums.TimeFormat = <TimeFormat.SECONDS: 0>) -> None:
59 def stop( 60 self, 61 endtime: int | float | None = None, 62 timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS, 63 ) -> None: 64 """End the timer. 65 66 If 'endtime' is not None, it is used when calculating 67 the final display time; otherwise the current time is used. 68 69 'timeformat' applies to endtime and can be SECONDS or MILLISECONDS 70 """ 71 if endtime is None: 72 endtime = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) 73 timeformat = ba.TimeFormat.MILLISECONDS 74 75 if self._starttime_ms is None: 76 print('Warning: OnScreenTimer.stop() called without start() first') 77 else: 78 endtime_ms: int 79 if timeformat is ba.TimeFormat.SECONDS: 80 endtime_ms = int(endtime * 1000) 81 elif timeformat is ba.TimeFormat.MILLISECONDS: 82 assert isinstance(endtime, int) 83 endtime_ms = endtime 84 else: 85 raise ValueError(f'invalid timeformat: {timeformat}') 86 87 self.inputnode.timemax = endtime_ms - self._starttime_ms
End the timer.
If 'endtime' is not None, it is used when calculating the final display time; otherwise the current time is used.
'timeformat' applies to endtime and can be SECONDS or MILLISECONDS
def
getstarttime( self, timeformat: ba._generated.enums.TimeFormat = <TimeFormat.SECONDS: 0>) -> int | float:
102 def getstarttime( 103 self, timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS 104 ) -> int | float: 105 """Return the sim-time when start() was called. 106 107 Time will be returned in seconds if timeformat is SECONDS or 108 milliseconds if it is MILLISECONDS. 109 """ 110 val_ms: Any 111 if self._starttime_ms is None: 112 print('WARNING: getstarttime() called on un-started timer') 113 val_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) 114 else: 115 val_ms = self._starttime_ms 116 assert isinstance(val_ms, int) 117 if timeformat is ba.TimeFormat.SECONDS: 118 return 0.001 * val_ms 119 if timeformat is ba.TimeFormat.MILLISECONDS: 120 return val_ms 121 raise ValueError(f'invalid timeformat: {timeformat}')
Return the sim-time when start() was called.
Time will be returned in seconds if timeformat is SECONDS or milliseconds if it is MILLISECONDS.
def
handlemessage(self, msg: Any) -> Any:
128 def handlemessage(self, msg: Any) -> Any: 129 # if we're asked to die, just kill our node/timer 130 if isinstance(msg, ba.DieMessage): 131 if self.node: 132 self.node.delete()
General message handling; can be passed any message object.
Inherited Members
- ba._actor.Actor
- autoretain
- on_expire
- expired
- exists
- is_alive
- activity
- getactivity