# Released under the MIT License. See LICENSE for details.#"""Defines Actor(s)."""from__future__importannotationsfromtypingimportTYPE_CHECKING,overrideimportloggingimportbascenev1asbsifTYPE_CHECKING:fromtypingimportAny
[docs]classOnScreenTimer(bs.Actor):"""A handy on-screen timer. category: Gameplay Classes Useful for time-based games where time increases. """def__init__(self)->None:super().__init__()self._starttime_ms:int|None=Noneself.node=bs.newnode('text',attrs={'v_attach':'top','h_attach':'center','h_align':'center','color':(1,1,0.5,1),'flatness':0.5,'shadow':0.5,'position':(0,-70),'scale':1.4,'text':'',},)self.inputnode=bs.newnode('timedisplay',attrs={'timemin':0,'showsubseconds':True})self.inputnode.connectattr('output',self.node,'text')
[docs]defstart(self)->None:"""Start the timer."""tval=int(bs.time()*1000.0)assertisinstance(tval,int)self._starttime_ms=tvalself.inputnode.time1=self._starttime_msbs.getactivity().globalsnode.connectattr('time',self.inputnode,'time2')
[docs]defhas_started(self)->bool:"""Return whether this timer has started yet."""returnself._starttime_msisnotNone
[docs]defstop(self,endtime:int|float|None=None)->None:"""End the timer. If 'endtime' is not None, it is used when calculating the final display time; otherwise the current time is used. """ifendtimeisNone:endtime=bs.time()ifself._starttime_msisNone:logging.warning('OnScreenTimer.stop() called without first calling start()')else:endtime_ms=int(endtime*1000)self.inputnode.timemax=endtime_ms-self._starttime_ms
[docs]defgetstarttime(self)->float:"""Return the scene-time when start() was called. Time will be returned in seconds if timeformat is SECONDS or milliseconds if it is MILLISECONDS. """val_ms:Anyifself._starttime_msisNone:print('WARNING: getstarttime() called on un-started timer')val_ms=int(bs.time()*1000.0)else:val_ms=self._starttime_msassertisinstance(val_ms,int)return0.001*val_ms
@propertydefstarttime(self)->float:"""Shortcut for start time in seconds."""returnself.getstarttime()
[docs]@overridedefhandlemessage(self,msg:Any)->Any:# if we're asked to die, just kill our node/timerifisinstance(msg,bs.DieMessage):ifself.node:self.node.delete()