Эх сурвалжийг харах

fixed bug in move() character and Marks added to utils.

Zero! Studio 1 жил өмнө
parent
commit
29734d46c9

+ 3 - 3
data/02.yaml

@@ -3,7 +3,7 @@ characters:
   protagonist:
     speed: 20
     width: 50
-    position: [50, 300]
+    position: [465, 300]
     keys:
       forward: RIGHT
       backward: LEFT
@@ -15,7 +15,7 @@ characters:
   secondary:
     speed: 5
     width: 150
-    position: [600, 200]
+    position: [700, 200]
     keys:
       forward: d
       backward: a
@@ -23,4 +23,4 @@ characters:
       down: s
   brick:
     height: 40
-    position: [600, 230]
+    position: [520, 310]

+ 2 - 0
jogai/__init__.py

@@ -6,3 +6,5 @@ from jogai.scene import Scene
 from jogai.videogame import *
 
 pygame.init()
+pygame.font.init()
+_globals.mark_font = pygame.font.SysFont('FreeMono', 10)

+ 6 - 2
jogai/_globals.py

@@ -1,13 +1,15 @@
 import pygame
 
-from jogai import settings, utils
+from jogai import settings
+from jogai.utils import _load_yaml_from_filename
 
 _clock = pygame.time.Clock()
 
-_default_data = utils._load_yaml_from_filename(
+_default_data = _load_yaml_from_filename(
     settings.DEFAULT_DATA_FILENAME, directory=settings.BASE_DIR
 )
 
+character_focus = None
 _events = []
 _keys = []
 _window = None
@@ -15,3 +17,5 @@ _window = None
 vg_scene = None
 vg_characters = []
 vg_groups = []
+marks = None
+mark_font = None

+ 33 - 9
jogai/character.py

@@ -7,8 +7,8 @@ import pygame
 import jogai
 import jogai._globals as _globals
 from jogai import logger, settings, utils
-from jogai.utils import _get_keys
 from jogai.translations import gettext as _
+from jogai.utils import _get_keys
 
 
 class Velocity:
@@ -154,7 +154,14 @@ class Character(pygame.sprite.Sprite):
                     'The position must be a tuple or a list of integers with the coordinates (x, y).'
                 )
             )
-        offset_rect = self._update_rect_position(simulate=position)
+        tracking = (
+            True
+            if self == _globals.character_focus and not position
+            else False
+        )
+        offset_rect = self._update_rect_position(
+            simulate=position, tracking=tracking
+        )
         collisions = []
         for collidable in self._get_all_collidables():
             if offset_rect.colliderect(collidable):
@@ -196,10 +203,27 @@ class Character(pygame.sprite.Sprite):
         if not key or _get_keys()[utils.eval_key(key)]:
             if relative:
                 updated_x, updated_y = self.x + x, self.y + y
+                self.velocity.x, self.velocity.y = x, y
             else:
                 updated_x, updated_y = x, y
-
-            self.x, self.y = updated_x, updated_y
+            collisions = self.calculate_collisions((updated_x, updated_y))
+            if collisions:
+                collisions.sort(key=lambda c: c.rect.y)
+                if self.velocity.y > 0:
+                    self.y = collisions[0].y - self.height
+                    self.velocity.y = 0
+                elif self.velocity.y < 0:
+                    self.y = collisions[0].y + collisions[0].height
+                    self.velocity.y = 0
+                collisions.sort(key=lambda c: c.rect.x)
+                if self.velocity.x > 0:
+                    self.x = collisions[0].x - self.width
+                    self.velocity.x = 0
+                elif self.velocity.x < 0:
+                    self.x = collisions[0].x + collisions[0].width
+                    self.velocity.x = 0
+            else:
+                self.x, self.y = updated_x, updated_y
 
     def move_to(self, x: int, y: int, key: str = ''):
         """
@@ -706,7 +730,6 @@ class Character(pygame.sprite.Sprite):
 
         if not _globals.vg_scene:
             return None
-
         if simulate:
             offset_rect = self.rect.copy()
             x, y = simulate
@@ -714,21 +737,22 @@ class Character(pygame.sprite.Sprite):
             offset_rect = self.rect
             x, y = self.x, self.y
         if tracking:
-            if x < settings.WINDOW_WIDTH // 2:
+            if x <= settings.WINDOW_WIDTH // 2 or x > _globals.vg_scene.width:
                 offset_rect.x = x
             elif (
                 settings.WINDOW_WIDTH // 2
                 < x
-                < _globals.vg_scene.width - settings.WINDOW_WIDTH
+                < _globals.vg_scene.width - settings.WINDOW_WIDTH // 2
             ):
                 offset_rect.x = settings.WINDOW_WIDTH // 2
-            elif x > _globals.vg_scene.width - settings.WINDOW_WIDTH:
-                offset_rect.x = settings.WINDOW_WIDTH * 3 / 2 - (
+            elif x >= _globals.vg_scene.width - settings.WINDOW_WIDTH // 2:
+                offset_rect.x = settings.WINDOW_WIDTH - (
                     -x % _globals.vg_scene.width
                 )
         else:
             offset_rect.x = x + _globals.vg_scene.x
         offset_rect.y = y
+
         return offset_rect
 
     def update(self):

+ 48 - 0
jogai/utils.py

@@ -9,6 +9,7 @@ import pygame
 import yaml
 from pygame.locals import *
 
+from jogai import _globals
 from jogai import exceptions as exc
 from jogai import logger, settings
 from jogai.translations import gettext as _
@@ -125,3 +126,50 @@ def eval_key(key: str) -> int:
             return eval(f'K_{key}')
     except NameError:
         raise exc.KeyPressedNotFoundError
+
+
+class Marks:
+    def __init__(self, x_gap, y_gap, x_color, y_color, width, debug=False):
+        self.x_gap = x_gap
+        self.y_gap = y_gap
+        self.x_color = x_color
+        self.y_color = y_color
+        self.width = width
+        self.debug = debug
+
+    def draw(self):
+        if self.x_gap:
+            for gap in range(0, _globals.vg_scene.width, self.x_gap):
+                draw_gap = gap + _globals.vg_scene.x
+                pygame.draw.line(
+                    _globals._window,
+                    self.x_color,
+                    (draw_gap, 0),
+                    (draw_gap, settings.WINDOW_HEIGHT),
+                    self.width,
+                )
+                _globals._window.blit(
+                    _globals.mark_font.render(str(gap), False, (0, 0, 0)),
+                    (draw_gap, 0),
+                )
+                if self.debug:
+                    _globals._window.blit(
+                        _globals.mark_font.render(
+                            str(draw_gap), False, (100, 100, 100)
+                        ),
+                        (draw_gap, 20),
+                    )
+        if self.y_gap:
+            for gap in range(0, _globals.vg_scene.height, self.y_gap):
+                draw_gap = gap
+                pygame.draw.line(
+                    _globals._window,
+                    self.y_color,
+                    (0, draw_gap),
+                    (settings.WINDOW_WIDTH, draw_gap),
+                    self.width,
+                )
+                _globals._window.blit(
+                    _globals.mark_font.render(str(gap), False, (0, 0, 0)),
+                    (0, draw_gap),
+                )

+ 25 - 13
jogai/videogame.py

@@ -9,8 +9,8 @@ import jogai
 import jogai._globals as _globals
 import jogai.settings as settings
 from jogai import character, group, logger, scene, utils
-from jogai.utils import _get_events, _get_keys
 from jogai.translations import gettext as _
+from jogai.utils import _get_events, _get_keys
 
 # --------------- #
 #    GLOBALS      #
@@ -152,6 +152,7 @@ def init():
     """
     if not pygame.get_init():
         pygame.init()
+
     _globals._window = pygame.display.set_mode(
         (settings.WINDOW_WIDTH, settings.WINDOW_HEIGHT)
     )
@@ -213,7 +214,7 @@ def get_color(x: int, y: int) -> Tuple[int, int, int]:
         raise ValueError(
             _('The coordinates of the point must be a non-negative integers.')
         )
-    return tuple(_window.get_at((x, y))[:-1])
+    return tuple(_globals._window.get_at((x, y))[:-1])
 
 
 def paint(sprite: Type['scene.Scene'] | Type['character.Character']):
@@ -234,6 +235,17 @@ def paint_group(group: Type['group.SquareGroup']):
     group.draw(_globals._window)
 
 
+def set_marks(
+    x_gap=0,
+    y_gap=0,
+    x_color=(255, 180, 30),
+    y_color=(0, 0, 255),
+    width=1,
+    debug=False,
+):
+    _globals.marks = utils.Marks(x_gap, y_gap, x_color, y_color, width, debug)
+
+
 def prepare(data_filename: str = ''):
     """
     Prepare the game environment before entering the main loop.
@@ -248,11 +260,14 @@ def prepare(data_filename: str = ''):
     if data_filename:
         vg_data = utils._load_yaml_from_filename(data_filename)
     else:
-        vg_data = _default_data
+        vg_data = _globals._default_data
 
     _globals.vg_scene = _load_scene(vg_data)
     _globals.vg_characters = _load_characters(vg_data)
 
+    if _globals.vg_characters:
+        _globals.character_focus = _globals.vg_characters[0]
+
     # TODO: Check and filter variable names added to builtins
     setattr(builtins, 'vgscene', _globals.vg_scene)
     for vg_character in _globals.vg_characters:
@@ -273,18 +288,14 @@ def update():
     """
     if _globals.vg_scene:
         if _globals.vg_characters:
-            _globals.vg_scene.set_position(_globals.vg_characters[0].x)
+            _globals.vg_scene.set_position(_globals.character_focus.x)
         paint(_globals.vg_scene)
     if _globals.vg_characters:
         for pos, vg_character in enumerate(_globals.vg_characters):
-            if vg_character.collidable:
-                rest_of_characters = _globals.vg_characters.copy()
-                rest_of_characters.remove(vg_character)
-                for other_character in rest_of_characters:
-                    if other_character.collidable:
-                        vg_character.touch(other_character)
-
-            vg_character._update_rect_position(False if pos else True)
+            tracking = (
+                True if vg_character == _globals.character_focus else False
+            )
+            vg_character._update_rect_position(tracking=tracking)
             paint(vg_character)
             vg_character.update()
     if _globals.vg_groups:
@@ -292,7 +303,8 @@ def update():
             for e in g.sprites():
                 e._update_rect_position()
                 paint(e)
-
+    if _globals.marks:
+        _globals.marks.draw()
     pygame.display.flip()
     _globals._clock.tick(settings.FPS)
     listen_events()

+ 1 - 1
scripts/basics.py

@@ -6,9 +6,9 @@ def test_example01():
     prepare('02.yaml')
     sq = StairsGroup(brick, 5)
     add_group(sq)
+    # set_marks(25, debug=True)
 
     while is_running():
         update()
-        #print(protagonist.calculate_collisions((0, 0)))
         if _get_keys()[eval_key('o')]:
             protagonist.move_to(sq.sprites()[0].x, sq.sprites()[0].y)

+ 3 - 7
tests/test_character.py

@@ -192,15 +192,11 @@ def test_jump_counter_when_jump_finishes():
 
 def test_update_rect_position_with_wrong_traking_type(prepare_videogame):
     with pytest.raises(TypeError):
-        protagonist._update_rect_position(vgscene, tracking='foo')
-
-
-def test_update_rect_position_with_no_scene(prepare_videogame):
-    protagonist._update_rect_position(None)
+        protagonist._update_rect_position(tracking='foo')
 
 
 def test_update_rect_position_when_character_moved(prepare_videogame):
     protagonist.move_to(1000, 0)
-    protagonist._update_rect_position(vgscene, tracking=True)
+    protagonist._update_rect_position(tracking=True)
     protagonist.move_to(3000, 0)
-    protagonist._update_rect_position(vgscene, tracking=True)
+    protagonist._update_rect_position(tracking=True)