Browse Source

set_angle added to character

mdo 1 năm trước cách đây
mục cha
commit
73aedf8ff0
3 tập tin đã thay đổi với 117 bổ sung17 xóa
  1. 91 11
      jogai/character.py
  2. 2 2
      scripts/basics.py
  3. 24 4
      tests/test_character.py

+ 91 - 11
jogai/character.py

@@ -56,6 +56,8 @@ class Character(pygame.sprite.Sprite):
         self.is_jumping = False
         self.jump_force = settings.DEFAULT_JUMP_FORCE
         self._jump_counter = self.jump_force
+        self.angle = 0
+        self.flipped = {'horizontal': False, 'vertical': False}
 
         super().__init__()
         self.load(image_filename)
@@ -159,7 +161,7 @@ class Character(pygame.sprite.Sprite):
 
     def backward(self, amount: int | None = None, key: str = ''):
         """
-        Moves the character in the negative direction of the abscissa.
+        Move the character in the negative direction of the abscissa.
 
         Parameters:
             amount: Number of pixels to move
@@ -176,7 +178,7 @@ class Character(pygame.sprite.Sprite):
 
     def down(self, amount: int | None = None, key: str = ''):
         """
-        Moves the character in the positive direction of the ordinate.
+        Move the character in the positive direction of the ordinate.
 
         Parameters:
             amount: Number of pixels to move
@@ -195,7 +197,7 @@ class Character(pygame.sprite.Sprite):
 
     def forward(self, amount: int | None = None, key: str = ''):
         """
-        Moves the character in the positive direction of the abscissa.
+        Move the character in the positive direction of the abscissa.
 
         Parameters:
             amount: Number of pixels to move
@@ -212,7 +214,7 @@ class Character(pygame.sprite.Sprite):
 
     def up(self, amount: int | None = None, key: str = ''):
         """
-        Moves the character in the negative direction of the ordinate.
+        Move the character in the negative direction of the ordinate.
 
         Parameters:
             amount: Number of pixels to move
@@ -230,6 +232,17 @@ class Character(pygame.sprite.Sprite):
             self.move(0, -amount, key)
 
     def jump(self, force: float | None = None, key: str = ''):
+        """
+        Jump the character.
+
+        Parameters:
+            force: Jump force
+            key: Optional key to perform the action
+
+        Examples:
+            >>> protagonist = Character('protagonist.png')
+            >>> protagonist.jump()
+        """
         if force is None:
             force = settings.DEFAULT_JUMP_FORCE
 
@@ -242,6 +255,9 @@ class Character(pygame.sprite.Sprite):
         if force < 0:
             raise ValueError(_('The jump force must be a non-negative float.'))
 
+        if not isinstance(key, str):
+            raise TypeError(_('Key pressed must be a string.'))
+
         self.jump_force = force
         self.jump_counter = force
 
@@ -250,12 +266,30 @@ class Character(pygame.sprite.Sprite):
         ):
             self.is_jumping = True
 
+    def rotate(self, increment: int = 1):
+        """
+        Rotate the character clockwise.
+
+        Parameters:
+            increment: Amount to be rotated
+
+        Examples:
+            >>> protagonist = Character('protagonist.png')
+            >>> protagonist.rotate(90)
+        """
+        # TODO: rotate from the center
+        if not isinstance(increment, int):
+            raise TypeError(_('The rotation increment must be an integer.'))
+
+        self.angle -= increment
+        self.set_angle()
+
     def decrease(self, decrement: float | int = 0.001, key: str = ''):
         """
         Decreases the size of the character.
 
         Parameters:
-            decrement: amount to increase to the scale factor
+            decrement: Amount to increase to the scale factor
             key: Optional key to perform the action
 
         Examples:
@@ -275,7 +309,7 @@ class Character(pygame.sprite.Sprite):
         Increases the size of the character.
 
         Parameters:
-            increment: amount to increase to the scale factor
+            increment: Amount to increase to the scale factor
             key: Optional key to perform the action
 
         Examples:
@@ -299,7 +333,7 @@ class Character(pygame.sprite.Sprite):
         Scale the character according to the scale factor.
 
         Parameters:
-            scale_factor: factor to scale
+            scale_factor: Factor to scale
 
         Examples:
             >>> protagonist = Character('protagonist.png')
@@ -328,12 +362,58 @@ class Character(pygame.sprite.Sprite):
         self.scale_factor = scale_factor
         self.rect = self.image.get_rect()
 
-    def set_height(self, height: int = 0):
+    def flip(self, horizontal: bool = True, vertical: bool = True):
+        """
+        Flip the character on horizontal and/or vertical axis.
+
+        Parameters:
+            horizontal: Flipped on horizontal axis
+            vertical: Flipped on vertical axis
+
+        Examples:
+            >>> protagonist = Character('protagonist.png')
+            >>> protagonist.flip(True, False)
+        """
+        if not isinstance(horizontal, bool) or not isinstance(vertical, bool):
+            raise TypeError(
+                _('Both the horizontal and vertical axis must be booleans.')
+            )
+
+        self.image = pygame.transform.flip(
+            self.image,
+            self.flipped['horizontal'] ^ horizontal,
+            self.flipped['vertical'] ^ vertical,
+        )
+        self.flipped['horizontal'] = horizontal
+        self.flipped['vertical'] = vertical
+
+    def set_angle(self, angle: int | None = None):
+        """
+        Set the character rotation.
+
+        Parameters:
+            angle: Angle to be rotated.
+
+        Examples:
+            >>> protagonist = Character('protagonist.png')
+            >>> protagonist.set_angle(90)
+        """
+        # TODO: rotate from the center
+        if not isinstance(angle, int) and angle is not None:
+            raise TypeError(_('The rotation angle must be an integer.'))
+
+        if angle is not None:
+            self.angle = 360 - angle
+        self.image = pygame.transform.rotozoom(
+            self._original_image, self.angle, self.scale_factor
+        )
+
+    def set_height(self, height: int):
         """
         Set the character height.
 
         Parameters:
-            height: the character height in pixels
+            height: The character height in pixels
 
         Examples:
             >>> protagonist = Character('protagonist.png')
@@ -394,7 +474,7 @@ class Character(pygame.sprite.Sprite):
 
         self.move(position[0], position[1], key, relative=False)
 
-    def set_speed(self, speed: int = 0):
+    def set_speed(self, speed: int):
         """
         Set the character speed.
 
@@ -408,7 +488,7 @@ class Character(pygame.sprite.Sprite):
         if isinstance(speed, int):
             self.speed = speed
 
-    def set_width(self, width: int = 0):
+    def set_width(self, width: int):
         """
         Set the character width.
 

+ 2 - 2
scripts/basics.py

@@ -10,6 +10,6 @@ def test_example01():
     add_group(sq)
 
     while is_running():
-        if protagonist.touch(sq):
-            secondary.move_to(0, 0)
         update()
+        if protagonist.touch(sq):
+            secondary.flip(True, False)

+ 24 - 4
tests/test_character.py

@@ -52,9 +52,14 @@ def test_move_with_wrong_coordinates(prepare_videogame):
         protagonist.move('foo', 'bar')
 
 
-def test_move_with_wrong_key(prepare_videogame):
+def test_move_with_wrong_key_type(prepare_videogame):
     with pytest.raises(TypeError):
-        protagonist.move(5, 3, 1)
+        protagonist.move(5, 3, key=-1)
+
+
+def test_rotate_with_wrong_type(prepare_videogame):
+    with pytest.raises(TypeError):
+        protagonist.rotate('foo')
 
 
 def test_decrease_with_integer_argument(prepare_videogame):
@@ -85,6 +90,16 @@ def test_scale_with_a_negative_factor(prepare_videogame):
         protagonist.scale_to(-1)
 
 
+def test_flip_with_wrong_type(prepare_videogame):
+    with pytest.raises(TypeError):
+        protagonist.flip('foo', 'bar')
+
+
+def test_set_angle_with_wrong_type(prepare_videogame):
+    with pytest.raises(TypeError):
+        protagonist.set_angle('foo')
+
+
 def test_set_height_with_wrong_type(prepare_videogame):
     with pytest.raises(TypeError):
         protagonist.set_height('foo')
@@ -132,7 +147,7 @@ def test_touch_with_list_not_all_characters(prepare_videogame):
 
 def test_touch_with_wrong_key_type(prepare_videogame):
     with pytest.raises(TypeError):
-        protagonist.touch(secondary, -1)
+        protagonist.touch(secondary, key=-1)
 
 
 def test_touch_without_sprites_colliding(prepare_videogame):
@@ -146,7 +161,7 @@ def test_jump_with_force_as_integer(prepare_videogame):
     protagonist.jump(5)
 
 
-def test_jump_with_wrong_type(prepare_videogame):
+def test_jump_with_wrong_force_type(prepare_videogame):
     with pytest.raises(TypeError):
         protagonist.jump('foo')
 
@@ -156,6 +171,11 @@ def test_jump_with_negative_force(prepare_videogame):
         protagonist.jump(-5)
 
 
+def test_jump_with_wrong_key_type(prepare_videogame):
+    with pytest.raises(TypeError):
+        protagonist.jump(5, key=-1)
+
+
 def test_jump_counter_when_updating_jump(prepare_videogame):
     protagonist.jump()
     previous_jump_counter = protagonist._jump_counter