Răsfoiți Sursa

LevelBar() added to texts.

Zero! Studio 1 an în urmă
părinte
comite
1eed4725c2
6 a modificat fișierele cu 200 adăugiri și 7 ștergeri
  1. 7 0
      jogai/__init__.py
  2. 1 0
      jogai/_globals.py
  3. 10 1
      jogai/settings.py
  4. 155 0
      jogai/texts.py
  5. 25 6
      jogai/videogame.py
  6. 2 0
      scripts/basics.py

+ 7 - 0
jogai/__init__.py

@@ -1,11 +1,18 @@
 import pygame
 
+from jogai import settings
 from jogai.character import Character
 from jogai.group import *
 from jogai.scene import Scene
 from jogai.texts import *
 from jogai.videogame import *
 
+if not isinstance(settings.LEVELBARS_MAX_PARTS, int):
+    raise TypeError(_('LEVELBARS_MAX_PARTS must be an integer.'))
+
+if settings.LEVELBARS_MAX_PARTS <= 0:
+    raise ValueError(_('LEVELBARS_MAX_PARTS must be a positive integer.'))
+
 pygame.init()
 pygame.font.init()
 _globals.mark_font = pygame.font.SysFont('FreeMono', 10)

+ 1 - 0
jogai/_globals.py

@@ -21,5 +21,6 @@ mark_font = None
 vg_scene = None
 vg_characters = []
 vg_groups = []
+vg_levelbars = []
 vg_scoreboards = []
 vg_texts = []

+ 10 - 1
jogai/settings.py

@@ -29,4 +29,13 @@ DATA_DIR = _('data')
 DEFAULT_JUMP_FORCE = 10.0
 
 # SCOREBOARDS
-SCOREBOARD_POSITION = (50, 50)
+SCOREBOARD_POSITION = (20, 20)
+
+# LEVELBARS
+LEVELBARS_MAX_PARTS = 25
+LEVELBARS_DEFAULT_WIDTH = 250
+LEVELBARS_DEFAULT_HEIGHT = 20
+LEVELBARS_DEFAULT_THICK = 3
+LEVELBARS_DEFAULT_POSITION = (WINDOW_WIDTH - LEVELBARS_DEFAULT_WIDTH - 20, 25)
+LEVELBARS_DEFAULT_BORDER_COLOR = (200, 0, 0)
+LEVELBARS_DEFAULT_FILL_COLOR = (241, 74, 6)

+ 155 - 0
jogai/texts.py

@@ -137,3 +137,158 @@ class Scoreboard(Text):
         if not isinstance(score, int):
             raise TypeError(_('Score must be an integer.'))
         self.score += score
+
+
+class LevelBar(pygame.Surface):
+    def __init__(
+        self,
+        parts: int,
+        initial_level: int | None = None,
+        position: tuple | list = settings.LEVELBARS_DEFAULT_POSITION,
+        border_color: tuple | list = settings.LEVELBARS_DEFAULT_BORDER_COLOR,
+        fill_color: tuple | list = settings.LEVELBARS_DEFAULT_FILL_COLOR,
+    ):
+        if not isinstance(parts, int):
+            raise TypeError(_('The amount of parts must be an integer.'))
+        if not (0 < parts <= settings.LEVELBARS_MAX_PARTS):
+            raise TypeError(
+                _(
+                    f'The amount of parts must be between 1 and {settings.LEVELBARS_MAX_PARTS}.'
+                )
+            )
+        super().__init__(
+            (
+                settings.LEVELBARS_DEFAULT_WIDTH,
+                settings.LEVELBARS_DEFAULT_HEIGHT,
+            )
+        )
+        self._parts = parts
+        if initial_level is None:
+            initial_level = parts
+        self.set(initial_level)
+        self.border_color = border_color
+        self.fill_color = fill_color
+        self.x, self.y = position
+        self._width = settings.LEVELBARS_DEFAULT_WIDTH
+        self._height = settings.LEVELBARS_DEFAULT_HEIGHT
+        self._thick = settings.LEVELBARS_DEFAULT_THICK
+
+    def __int__(self):
+        return int(self._level)
+
+    def __repr(self):
+        return f'LevelBar <{self._level}/{self._parts}>'
+
+    def __str__(self):
+        return f'{self._level}/{self._parts}'
+
+    def decrease(self, decrease: int):
+        """
+        Decrease the level for this bar.
+
+        Parameters:
+            decrease: amount to decrease
+
+        Examples:
+            >>> lifes = LevelBar(5, 3)
+            >>> lifes.decrease(1)
+        """
+        if not isinstance(decrease, int):
+            raise TypeError(_('The decrease level must be an integer.'))
+        if self._level - decrease < 0:
+            raise ValueError(_('The decrease cannot be less than zero.'))
+        self.set(self._level - decrease)
+
+    def increase(self, increase: int):
+        """
+        Increase the level for this bar.
+
+        Parameters:
+            increase: amount to increase
+
+        Examples:
+            >>> lifes = LevelBar(5)
+            >>> lifes.increase(1)
+        """
+        if not isinstance(increase, int):
+            raise TypeError(_('The increase level must be an integer.'))
+        if self._level + increase > self._parts:
+            raise ValueError(_('The increase cannot exceed the maximum level.'))
+        self.set(self._level + increase)
+
+    def set(self, level):
+        """
+        Set the new level for this bar.
+
+        Parameters:
+            level: the new level
+
+        Examples:
+            >>> lifes = LevelBar(5)
+            >>> lifes.set(3)
+        """
+        if not isinstance(level, int):
+            raise TypeError(_('The level must be an integer.'))
+        if not (0 <= level <= self._parts):
+            raise ValueError(
+                _(
+                    'The level range must be between zero and the number of parts.'
+                )
+            )
+        self._level = level
+
+    def draw(self, position: tuple | list | None = None):
+        if position is None:
+            position = (self.x, self.y)
+        else:
+            self.x, self.y = position
+
+        division = int(self._width / self._parts)
+        # left border
+        pygame.draw.line(
+            _globals._window,
+            self.border_color,
+            position,
+            (position[0], position[1] + self._height),
+            self._thick,
+        )
+        # right border
+        pygame.draw.line(
+            _globals._window,
+            self.border_color,
+            (position[0] + division * self._parts, position[1]),
+            (position[0] + division * self._parts, position[1] + self._height),
+            self._thick,
+        )
+        for part in range(self._parts):
+            # top border
+            pygame.draw.line(
+                _globals._window,
+                self.border_color,
+                (position[0] + division * part, position[1]),
+                (position[0] + division * (part+1), position[1]),
+                self._thick,
+            )
+            # inside
+            if part < self._level:
+                pygame.draw.line(
+                    _globals._window,
+                    self.fill_color,
+                    (
+                        position[0] + division * part + self._thick / 2,
+                        position[1] + int(self._height / 2)),
+                    (
+                        position[0] + division * (part + 1) - self._thick / 2,
+                        position[1] + int(self._height / 2)
+                    ),
+                    self._height,
+                )
+            # bottom border
+            pygame.draw.line(
+                _globals._window,
+                self.border_color,
+                (position[0] + division * part, position[1] + self._height),
+                (position[0] + division * (part + 1), position[1] + self._height),
+                self._thick,
+            )
+        self.rect = self.get_rect()

+ 25 - 6
jogai/videogame.py

@@ -165,18 +165,34 @@ def add_group(new_group: 'group.SquareGroup'):
     _globals.vg_groups.append(new_group)
 
 
+def add_levelbar(new_levelbar: 'texts.LevelBar'):
+    """
+    Add a new level bar to the videogame.
+
+    Parameters:
+        new_levelbar: the level bar to be added
+
+    Examples:
+        >>> lb = texts.LevelBar(3)
+        >>> add_levelbar(lb) # doctest: +SKIP
+    """
+    if not isinstance(new_levelbar, texts.LevelBar):
+        raise TypeError(_('Only LevelBar instances can be added.'))
+    _globals.vg_levelbars.append(new_levelbar)
+
+
 def add_scoreboard(new_text: 'texts.Text'):
     """
-    Add a new text to the videogame.
+    Add a new scoreboard to the videogame.
 
     Parameters:
-        new_text: the text to be added
+        new_scoreboard: the scoreboard to be added
 
     Examples:
-        >>> text = texts.Text('Test')
-        >>> add_text(text) # doctest: +SKIP
+        >>> sc = texts.Scoreboard('Test')
+        >>> add_scoreboard(sc) # doctest: +SKIP
     """
-    if not isinstance(new_scoreboard, texts.Text):
+    if not isinstance(new_scoreboard, texts.Scoreboard):
         raise TypeError(_('Only Scoreboard instances can be added.'))
     _globals.vg_scobreboards.append(new_scoreboard)
 
@@ -274,7 +290,7 @@ def get_color(x: int, y: int) -> Tuple[int, int, int]:
 def paint(
     sprite: Type['scene.Scene']
     | Type['character.Character']
-    | Type['texts.Text'],
+    | Type['texts.Text']
 ):
     """
     Paint both a scene and a character.
@@ -399,6 +415,9 @@ def update():
     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.marks:
         _globals.marks.draw()
     pygame.display.flip()

+ 2 - 0
scripts/basics.py

@@ -6,6 +6,8 @@ def test_example01():
     prepare('02.yaml')
     sq = StairsGroup(brick, 5)
     add_group(sq)
+    lb = LevelBar(15)
+    add_levelbar(lb)
 
     while is_running():
         update()