Explorar o código

Chronometer() added to widgets

Zero! Studio hai 1 ano
pai
achega
0e66ad54ae
Modificáronse 4 ficheiros con 150 adicións e 45 borrados
  1. 1 1
      jogai/_globals.py
  2. 6 6
      jogai/videogame.py
  3. 139 38
      jogai/widgets.py
  4. 4 0
      scripts/basics.py

+ 1 - 1
jogai/_globals.py

@@ -23,4 +23,4 @@ vg_characters = []
 vg_groups = []
 vg_levelbars = []
 vg_scoreboards = []
-vg_texts = []
+vg_widgets = []

+ 6 - 6
jogai/videogame.py

@@ -409,15 +409,15 @@ def update():
                 sprite_item._update_rect_position()
                 paint(sprite_item)
                 sprite_item.update()
-    if _globals.vg_texts:
-        for text_item in _globals.vg_texts:
-            paint(text_item)
-    if _globals.vg_scoreboards:
-        for scoreboard_item in _globals.vg_scoreboards:
-            paint(scoreboard_item)
     if _globals.vg_levelbars:
         for levelbar_item in _globals.vg_levelbars:
             levelbar_item.draw()
+    if _globals.vg_scoreboards:
+        for scoreboard_item in _globals.vg_scoreboards:
+            paint(scoreboard_item)
+    if _globals.vg_widgets:
+        for widgets_item in _globals.vg_widgets:
+            paint(widgets_item)
     if _globals.marks:
         _globals.marks.draw()
     pygame.display.flip()

+ 139 - 38
jogai/widgets.py

@@ -79,66 +79,105 @@ class Text:
             self.render(position=position)
 
 
-class Scoreboard(Text):
-    def __init__(self, prefix: str, score: int = 0, **kwargs):
-        if not isinstance(prefix, str):
-            raise TypeError(_('The prefix text must be a string.'))
+class Chronometer(Text):
+    def __init__(
+        self, initial: int = 0, in_milliseconds: bool = False, **kwargs
+    ):
+        if not isinstance(initial, int):
+            raise TypeError(_('The initial value must be an integer.'))
+        if initial < 0:
+            raise ValueError(_('The countdown cannot be negative.'))
+        if not isinstance(in_milliseconds, bool):
+            raise TypeError(_('in_milliseconds argument must be a boolean.'))
+
         super().__init__(**kwargs)
-        self._prefix = prefix
-        self.set_score(score)
+        self._initial = initial if in_milliseconds else initial * 1000
+        self._time = 0
+        self._timestamp = 0
+        self._onpause = True
+        self._message = self.format_clock()
+
         if 'position' in kwargs:
             self.render(position=kwargs['position'])
         else:
             self.render()
 
     def __int__(self):
-        return int(self._score)
+        return self.get_milliseconds()
 
     def __repr__(self):
-        return f'Scoreboard <{self._message}>'
+        return f'Chronometer <{self.format_clock()}>'
 
     def __str__(self):
         return self._message
 
     @property
-    def score(self):
-        return self._score
+    def time(self):
+        return self.get_milliseconds()
 
     @property
-    def message(self):
-        return self._message
+    def onpause(self) -> bool:
+        return self._onpause
 
-    def set_score(self, score: int):
-        """
-        Set the character score.
+    def format_clock(self, include_millis: bool = False) -> str:
+        formatted_time = tuple(
+            map(lambda x: str(x).zfill(2), self.get_clock())
+        )
+        formatted_clock = ':'.join(formatted_time[:-1])
+        if include_millis:
+            formatted_clock += f'.{formatted_time[-1]}'
+        return formatted_clock
+
+    def get_clock(self) -> tuple:
+        millis = self.get_milliseconds()
+        if millis > 0:
+            quotient = millis // 1000
+            millis = millis % 1000
+            seconds = quotient % 60
+            quotient = quotient // 60
+            minutes = quotient % 60
+            hours = quotient // 60
+            return hours, minutes, seconds, millis
+        return 0, 0, 0, 0
+
+    def get_milliseconds(self) -> int:
+        if self._onpause:
+            current = (
+                self._initial - self._time if self._initial else self._time
+            )
+        else:
+            if self._initial:
+                current = self._initial - (
+                    self._time + pygame.time.get_ticks() - self._timestamp
+                )
+            else:
+                current = (
+                    self._time + pygame.time.get_ticks() - self._timestamp
+                )
 
-        Parameters:
-            score: the new character score
+        current = max(0, current)
+        return current
 
-        Examples:
-            >>> scoreboard = Scoreboard('My character: ')
-            >>> scoreboard.set_score(100)
-        """
-        if not isinstance(score, int):
-            raise TypeError(_('Score must be an integer.'))
-        self._score = score
-        self._message = f'{self._prefix}{self._score}'
-        self.render()
+    def get_seconds(self) -> int:
+        return self.get_milliseconds() // 1000
 
-    def add_score(self, score: int):
-        """
-        Increment the character score.
+    def init(self):
+        self._time = 0
+        self._timestamp = pygame.time.get_ticks()
+        self._onpause = False
 
-        Parameters:
-            score: the character score to be added
+    def pause(self):
+        if not self._onpause:
+            self._onpause = True
+            self._time = self._time + pygame.time.get_ticks() - self._timestamp
 
-        Examples:
-            >>> scoreboard = Scoreboard('My character: ')
-            >>> scoreboard.add_score(5)
-        """
-        if not isinstance(score, int):
-            raise TypeError(_('Score must be an integer.'))
-        self._score += score
+    def resume(self):
+        if self._onpause:
+            self._onpause = False
+            self._timestamp = pygame.time.get_ticks()
+
+    def update(self):
+        self._message = self.format_clock()
 
 
 class LevelBar(pygame.Surface):
@@ -300,3 +339,65 @@ class LevelBar(pygame.Surface):
                 self._thick,
             )
         self.rect = self.get_rect()
+
+
+class Scoreboard(Text):
+    def __init__(self, prefix: str, score: int = 0, **kwargs):
+        if not isinstance(prefix, str):
+            raise TypeError(_('The prefix text must be a string.'))
+        super().__init__(**kwargs)
+        self._prefix = prefix
+        self.set_score(score)
+        if 'position' in kwargs:
+            self.render(position=kwargs['position'])
+        else:
+            self.render()
+
+    def __int__(self):
+        return int(self._score)
+
+    def __repr__(self):
+        return f'Scoreboard <{self._message}>'
+
+    def __str__(self):
+        return self._message
+
+    @property
+    def score(self):
+        return self._score
+
+    @property
+    def message(self):
+        return self._message
+
+    def set_score(self, score: int):
+        """
+        Set the character score.
+
+        Parameters:
+            score: the new character score
+
+        Examples:
+            >>> scoreboard = Scoreboard('My character: ')
+            >>> scoreboard.set_score(100)
+        """
+        if not isinstance(score, int):
+            raise TypeError(_('Score must be an integer.'))
+        self._score = score
+        self._message = f'{self._prefix}{self._score}'
+        self.render()
+
+    def add_score(self, score: int):
+        """
+        Increment the character score.
+
+        Parameters:
+            score: the character score to be added
+
+        Examples:
+            >>> scoreboard = Scoreboard('My character: ')
+            >>> scoreboard.add_score(5)
+        """
+        if not isinstance(score, int):
+            raise TypeError(_('Score must be an integer.'))
+        self._score += score

+ 4 - 0
scripts/basics.py

@@ -6,6 +6,10 @@ def test_example01():
     prepare('02.yaml')
     sq = StairsGroup(brick, 5)
     add_group(sq)
+    crono = Chronometer(5)
+    add_text(crono)
+    crono.init()
 
     while is_running():
         update()
+        print(crono)