فهرست منبع

Jump logic added to character.

mdo 1 سال پیش
والد
کامیت
08556f0445
5فایلهای تغییر یافته به همراه115 افزوده شده و 50 حذف شده
  1. 1 0
      data/02.yaml
  2. 81 35
      jogai/character.py
  3. 12 8
      jogai/settings.py
  4. 1 1
      scripts/basics.py
  5. 20 6
      tests/test_character.py

+ 1 - 0
data/02.yaml

@@ -11,6 +11,7 @@ characters:
       down: s
       increase: e
       decrease: q
+      jump: SPACE
   jett:
     speed: 5
     width: 150

+ 81 - 35
jogai/character.py

@@ -20,6 +20,7 @@ class Character(pygame.sprite.Sprite):
         _('down'),
         _('forward'),
         _('increase'),
+        _('jump'),
         _('up'),
     ]
 
@@ -49,6 +50,9 @@ class Character(pygame.sprite.Sprite):
         self.name = name
         self.x = 0
         self.y = 0
+        self.is_jumping = False
+        self.jump_force = settings.DEFAULT_JUMP_FORCE
+        self._jump_counter = self.jump_force
 
         super().__init__()
         self.load(image_filename)
@@ -90,39 +94,6 @@ class Character(pygame.sprite.Sprite):
 
         eval(f'self.{function}({processed_arguments})')
 
-    def _update_rect_position(
-        self, vg_scene: Type['scene.Scene'], tracking: bool = False
-    ) -> int:
-        """
-        Calculate and update the position where the character must be painted.
-        Only one character can be tracked.
-
-        Parameters:
-            vg_scene: The scene information.
-            tracking: True if the character must be followed, False otherwise.
-        """
-        # TODO: check vg_scene type
-        if not isinstance(tracking, bool):
-            raise TypeError(_('The tracking parameter must be a boolean.'))
-
-        if tracking:
-            if self.x < settings.WINDOW_WIDTH // 2:
-                self._rect.x = self.x
-            elif (
-                settings.WINDOW_WIDTH // 2
-                < self.x
-                < vg_scene.width - settings.WINDOW_WIDTH
-            ):
-                self._rect.x = settings.WINDOW_WIDTH // 2
-            elif self.x > vg_scene.width - settings.WINDOW_WIDTH:
-                self._rect.x = settings.WINDOW_WIDTH * 3 / 2 - (
-                    -self.x % vg_scene.width
-                )
-            self._rect.y = self.y
-        else:
-            self._rect.x = self.x + vg_scene.x
-            self._rect.y = self.y
-
     def move(
         self,
         x: int | None = None,
@@ -210,7 +181,9 @@ class Character(pygame.sprite.Sprite):
         """
         if amount is None:
             amount = self.speed
-        self.move(0, amount, key)
+
+        if not self.is_jumping:
+            self.move(0, amount, key)
 
     def forward(self, amount: int | None = None, key: str = ''):
         """
@@ -244,7 +217,30 @@ class Character(pygame.sprite.Sprite):
         """
         if amount is None:
             amount = self.speed
-        self.move(0, -amount, key)
+
+        if not self.is_jumping:
+            self.move(0, -amount, key)
+
+    def jump(self, force: float | None = None, key: str = ''):
+        if force is None:
+            force = settings.DEFAULT_JUMP_FORCE
+
+        if isinstance(force, int):
+            force = float(force)
+
+        if not isinstance(force, float):
+            raise TypeError(_('The jump force must be a float number.'))
+
+        if force < 0:
+            raise ValueError(_('The jump force must be a non-negative float.'))
+
+        self.jump_force = force
+        self.jump_counter = force
+
+        if not self.is_jumping and (
+            not key or _get_keys()[utils.eval_key(key)]
+        ):
+            self.is_jumping = True
 
     def decrease(self, decrement: float | int = 0.001, key: str = ''):
         """
@@ -452,6 +448,56 @@ class Character(pygame.sprite.Sprite):
         if self._image:
             _window.blit(self._image, self._rect)
 
+    def _update_jump(self):
+        """
+        Calculate and update the character position during the jump.
+        """
+        if self.is_jumping:
+            if self._jump_counter >= -self.jump_force:
+                self.move(
+                    0,
+                    -int((self._jump_counter * abs(self._jump_counter)) * 0.5),
+                )
+                self._jump_counter -= 1
+            else:
+                self._jump_counter = settings.DEFAULT_JUMP_FORCE
+                self.is_jumping = False
+
+    def _update_rect_position(
+        self, vg_scene: Type['scene.Scene'], tracking: bool = False
+    ):
+        """
+        Calculate and update the position where the character must be painted.
+        Only one character can be tracked.
+
+        Parameters:
+            vg_scene: The scene information.
+            tracking: True if the character must be followed, False otherwise.
+        """
+        # TODO: check vg_scene type
+        if not isinstance(tracking, bool):
+            raise TypeError(_('The tracking parameter must be a boolean.'))
+
+        if tracking:
+            if self.x < settings.WINDOW_WIDTH // 2:
+                self._rect.x = self.x
+            elif (
+                settings.WINDOW_WIDTH // 2
+                < self.x
+                < vg_scene.width - settings.WINDOW_WIDTH
+            ):
+                self._rect.x = settings.WINDOW_WIDTH // 2
+            elif self.x > vg_scene.width - settings.WINDOW_WIDTH:
+                self._rect.x = settings.WINDOW_WIDTH * 3 / 2 - (
+                    -self.x % vg_scene.width
+                )
+            self._rect.y = self.y
+        else:
+            self._rect.x = self.x + vg_scene.x
+            self._rect.y = self.y
+
     def update(self):
         for action, key in self.predefined_keys.items():
             eval(f'self.{action}(key="{key}")')
+
+        self._update_jump()

+ 12 - 8
jogai/settings.py

@@ -6,19 +6,23 @@ import os
 
 import jogai
 
+LANGUAGE_CODE = 'gl'
+
 KEY_DELAY = 1
 KEY_INTERVAL = 25
-FPS = 60
-
-BASE_DIR = os.path.dirname((os.path.abspath(__file__)))
-DEFAULT_DATA_FILENAME = 'default_data.yaml'
+FPS = 40
 
-DATA_DIR = 'data'
+WINDOW_WIDTH = 800
+WINDOW_HEIGHT = 600
 SCENE_DEFAULT_BACKGROUND = (0, 0, 0)
+
+# PATHS
+BASE_DIR = os.path.dirname((os.path.abspath(__file__)))
 SCENES_DIR = os.path.join('images', 'scenes')
 CHARACTERS_DIR = os.path.join('images', 'characters')
 
-WINDOW_WIDTH = 800
-WINDOW_HEIGHT = 600
+DEFAULT_DATA_FILENAME = 'default_data.yaml'
+DATA_DIR = 'data'
 
-LANGUAGE_CODE = 'gl'
+# DEFAULT CHARACTER FEATURES
+DEFAULT_JUMP_FORCE = 10.0

+ 1 - 1
scripts/basics.py

@@ -5,7 +5,7 @@ def test_example01():
     def move():
         ...
 
-    prepare('no_characters.yaml')
+    prepare('02.yaml')
 
     while is_running():
         update()

+ 20 - 6
tests/test_character.py

@@ -1,7 +1,7 @@
 import pygame
 import pytest
 
-from jogai import character
+from jogai import character, settings
 from jogai import videogame as vg
 from jogai.translations import gettext as _
 
@@ -36,11 +36,6 @@ def test_wrong_predefined_keys_type():
         ch = character.Character('protagonist.png', predefined_keys=[])
 
 
-def test_update_rect_position_with_wrong_type(prepare_videogame):
-    with pytest.raises(TypeError):
-        protagonist._update_rect_position(vgscene, 'foo')
-
-
 def test_move_with_wrong_coordinates(prepare_videogame):
     with pytest.raises(TypeError):
         protagonist.move('foo', 'bar')
@@ -112,3 +107,22 @@ def test_set_width_with_wrong_type(prepare_videogame):
 def test_set_width_with_a_negative_amount(prepare_videogame):
     with pytest.raises(ValueError):
         protagonist.set_width(-1)
+
+
+def test_update_rect_position_with_wrong_type(prepare_videogame):
+    with pytest.raises(TypeError):
+        protagonist._update_rect_position(vgscene, 'foo')
+
+
+def test_jump_counter_when_updating_jump(prepare_videogame):
+    protagonist.jump()
+    previous_jump_counter = protagonist._jump_counter
+    protagonist._update_jump()
+    assert protagonist._jump_counter == previous_jump_counter - 1
+
+
+def test_jump_counter_when_jump_finishes():
+    protagonist.jump()
+    while protagonist.is_jumping:
+        protagonist._update_jump()
+    assert protagonist._jump_counter == settings.DEFAULT_JUMP_FORCE