πŸ˜›πŸ‘» ПишСм ΠΈΠ³Ρ€Ρƒ Pac-Man Π½Π° Python Π² 300 строк ΠΊΠΎΠ΄Π°

Π’ Π΄Π°Π½Π½ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ напишСм Π»Π΅Π³Π΅Π½Π΄Π°Ρ€Π½ΡƒΡŽ ΠΈΠ³Ρ€Ρƒ Pac-Man Π½Π° Python, умСстив Π΅Π΅ Π² 300 строчСк ΠΊΠΎΠ΄Π°.

Данная ΡΡ‚Π°Ρ‚ΡŒΡ являСтся ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ΠΎΠΌ. Автор: Ing. Jan Jileček. Бсылка Π½Π° ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π».

Pac-Man β€” классичСский ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅Ρ€, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ, Π½Π°Π²Π΅Ρ€Π½ΠΎΠ΅, сСгодня извСстСн ΠΊΠ°ΠΆΠ΄ΠΎΠΌΡƒ. НазваниС Β«Pac-ManΒ» происходит ΠΎΡ‚ японского слова Β«pakuΒ», Ρ‡Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Π½ΠΈΠ΅ ΠΈ Π·Π°ΠΊΡ€Ρ‹Π²Π°Π½ΠΈΠ΅ Ρ€Ρ‚Π°. БоздатСля Π’ΠΎΡ€Ρƒ Π˜Π²Π°Ρ‚Π°Π½ΠΈ Π²Π΄ΠΎΡ…Π½ΠΎΠ²ΠΈΠ»Π° японская история ΠΎ сущСствС, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π·Π°Ρ‰ΠΈΡ‰Π°Π΅Ρ‚ Π΄Π΅Ρ‚Π΅ΠΉ ΠΎΡ‚ монстров, поСдая ΠΈΡ…. ΠŸΡ€ΠΈ создании ΠΈΠ³Ρ€Ρ‹ ΠΎΠ½ опирался Π½Π° ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ слова ΠΈΠ· Π»Π΅Π³Π΅Π½Π΄Ρ‹, Π° Π³Π»Π°Π³ΠΎΠ» Β«ΡΡŠΠ΅ΡΡ‚ΡŒΒ» стал основой всСго.

(Π”Π°Π½Π½ΠΎΠ΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΈ всС ΠΏΠΎΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ взяты ΠΎΡ‚ΡΡŽΠ΄Π°.)

ΠœΠΎΠ½ΡΡ‚Ρ€Ρ‹ прСдставлСны Π² Π²ΠΈΠ΄Π΅ Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅Ρ… ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π°Ρ‚Π°ΠΊΡƒΡŽΡ‚ ΠΈΠ³Ρ€ΠΎΠΊΠ° ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ Β«Π²ΠΎΠ»Π½Π°ΠΌΠΈΒ», ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΎ космичСским Π·Π°Ρ…Π²Π°Ρ‚Ρ‡ΠΈΠΊΠ°ΠΌ. ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊ Ρ‚Π°ΠΊΠΆΠ΅ ΠΈΠΌΠ΅Π΅Ρ‚ ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½ΡƒΡŽ Π»ΠΈΡ‡Π½ΠΎΡΡ‚ΡŒ. Π’ истории Π΅ΡΡ‚ΡŒ Π΅Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½ Π²Π°ΠΆΠ½Ρ‹ΠΉ элСмСнт, концСпция ΠΆΠΈΠ·Π½Π΅Π½Π½ΠΎΠΉ силы Β«ΠΊΠΎΠΊΠΎΡ€ΠΎΒ», которая позволяла сущСствам ΠΏΠΎΠ΅Π΄Π°Ρ‚ΡŒ монстров. Π’ ΠΈΠ³Ρ€Π΅ эта энСргия прСдставлСна ​​​​в Π²ΠΈΠ΄Π΅ ΠΏΠ΅Ρ‡Π΅Π½ΡŒΡ с усилСниСм, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π΄Π°Π΅Ρ‚ Pac-Man ΠΊΡ€Π°Ρ‚ΠΊΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ ΡΠΏΠΎΡΠΎΠ±Π½ΠΎΡΡ‚ΡŒ ΠΏΠΎΠ΅Π΄Π°Ρ‚ΡŒ монстров.

Π’ этом ΡƒΡ€ΠΎΠΊΠ΅ я сначала ΠΏΡ€ΠΎΠ²Π΅Π΄Ρƒ вас Ρ‡Π΅Ρ€Π΅Π· Π±Π°Π·ΠΎΠ²ΡƒΡŽ настройку, Π·Π°Ρ‚Π΅ΠΌ ΠΌΡ‹ создадим ΠΈΠ³Ρ€ΠΎΠ²Ρ‹Π΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ для стСны Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π°, Pac-Man ΠΈ ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠΎΠ², обСспСчим поиск ΠΏΡƒΡ‚ΠΈ Π² Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π΅, Π·Π°Π΄Π°Π΄ΠΈΠΌ ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠ°ΠΌ случайноС Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠ΅, Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ элСмСнты управлСния стрСлками для ΠΈΠ³Ρ€ΠΎΠΊΠ° ΠΈ Π½Π°ΠΊΠΎΠ½Π΅Ρ†, размСстим Π΅Π΄Ρƒ Π² Π²ΠΈΠ΄Π΅ ΠΏΠ΅Ρ‡Π΅Π½ΡŒΡ ΠΏΠΎ всСму Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Ρƒ.

>> basic_settings

ΠŸΠΎΠ»ΡƒΡ‡ΠΈΠ²ΡˆΠ°ΡΡΡ ΠΈΠ³Ρ€Π° содСрТит ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ 300 строк ΠΊΠΎΠ΄Π°, поэтому я ΠΏΠ΅Ρ€Π΅Ρ‡ΠΈΡΠ»ΡΡŽ здСсь Ρ‚ΠΎΠ»ΡŒΠΊΠΎ самыС Π²Π°ΠΆΠ½Ρ‹Π΅ части. ΠŸΠΎΠ»Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ доступСн Π² ΠΌΠΎΠ΅ΠΌ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ GitHub. ΠŸΠ΅Ρ€Π²Ρ‹ΠΌ Π΄Π΅Π»ΠΎΠΌ установим Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹. Нам понадобятся pygame, numpy ΠΈ tcod. УстановитС ΠΈΡ… всС с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ инструмСнта pip. Если Π²Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ IDE, Ρ‚Π°ΠΊΡƒΡŽ ​​как PyCharm (я Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΡŽ Π΅Π΅), установка ΠΏΡ€ΠΎΠΈΠ·ΠΎΠΉΠ΄Π΅Ρ‚ послС наТатия Π½Π° сообщСниС ΠΎΠ± ошибкС ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π³ΠΎ ΠΏΠ°ΠΊΠ΅Ρ‚Π°.

Π’ΠΎ-ΠΏΠ΅Ρ€Π²Ρ‹Ρ…, ΠΌΡ‹ создадим ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠ΅ ΠΎΠΊΠ½ΠΎ, Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½ΠΎ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΌΡƒ руководству ΠΏΠΎ ΠΈΠ³Ρ€Π΅ Space Invaders (Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π±Ρ‹Π»ΠΎ всСго 100 строк). Π—Π΄Π΅ΡΡŒ я ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²Π»ΡŽ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ для указания Ρ€Π°Π·ΠΌΠ΅Ρ€Π° ΠΎΠΊΠ½Π°, названия ΠΈΠ³Ρ€Ρ‹, частоты обновлСния ΠΈ нСсколько ΠΏΠΎΠ»Π΅ΠΉ Π΄Π°Π½Π½Ρ‹Ρ…, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ ссылки Π½Π° ΠΈΠ³Ρ€ΠΎΠ²Ρ‹Π΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ ΠΈ ΠΈΠ³Ρ€ΠΎΠΊΠ°. Ѐункция tick ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎ ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ ΠΏΠΎ всСм ΠΈΠ³Ρ€ΠΎΠ²Ρ‹ΠΌ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌ ΠΈ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΈΡ… Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΡŽΡŽ Π»ΠΎΠ³ΠΈΠΊΡƒ ΠΈ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³. Π—Π°Ρ‚Π΅ΠΌ остаСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠ΅Ρ€Π΅Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ всю ΠΈΠ³Ρ€ΠΎΠ²ΡƒΡŽ ΠΎΠ±Π»Π°ΡΡ‚ΡŒ ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ события Π²Π²ΠΎΠ΄Π°, Ρ‚Π°ΠΊΠΈΠ΅ ΠΊΠ°ΠΊ Ρ‰Π΅Π»Ρ‡ΠΊΠΈ ΠΌΡ‹ΡˆΡŒΡŽ ΠΈ Π²Π²ΠΎΠ΄ с ΠΊΠ»Π°Π²ΠΈΠ°Ρ‚ΡƒΡ€Ρ‹. Для этой Ρ†Π΅Π»ΠΈ Π±ΡƒΠ΄Π΅Ρ‚ ΡΠ»ΡƒΠΆΠΈΡ‚ΡŒ функция _handle_events.

import pygame # import packages (install with "pip install pygame" in cmd)
import numpy as np
import tcod

class GameRenderer:
    def __init__(self, in_width: int, in_height: int):
        pygame.init()
        self._width = in_width
        self._height = in_height
        self._screen = pygame.display.set_mode((in_width, in_height))
        pygame.display.set_caption('Pacman')
        self._clock = pygame.time.Clock()
        self._done = False
        self._game_objects = []
        self._walls = []
        self._cookies = []
        self._hero: Hero = None

    def tick(self, in_fps: int):
        black = (0, 0, 0)
        while not self._done:
            for game_object in self._game_objects:
                game_object.tick()
                game_object.draw()

            pygame.display.flip()
            self._clock.tick(in_fps)
            self._screen.fill(black)
            self._handle_events()
         print("Game over")

    def add_game_object(self, obj: GameObject):
        self._game_objects.append(obj)


    def add_wall(self, obj: Wall):
        self.add_game_object(obj)
        self._walls.append(obj)

    def _handle_events(self):
        pass # we'll implement this later
Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Ρ… ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΎΠ² Π²Ρ‹ Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Π½Π° нашСм Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-ΠΊΠ°Π½Π°Π»Π΅ Β«Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° питониста»

>> parent_game_object

Π—Π°Ρ‚Π΅ΠΌ я создаю Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ с ΠΈΠΌΠ΅Π½Π΅ΠΌ GameObject, ΠΎΡ‚ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ классы Π±ΡƒΠ΄ΡƒΡ‚ Π½Π°ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ. Π’ ΠΈΠ³Ρ€Π΅ Ρƒ нас Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ для стСны (Wall), Pac-Man (Hero), привидСния (Ghost) ΠΈ ΠΏΠ΅Ρ‡Π΅Π½ΡŒΡ (Cookie). Для упомянутых Π²Ρ‹ΡˆΠ΅ ΠΏΠΎΠ΄Π²ΠΈΠΆΠ½Ρ‹Ρ… ΠΈΠ³Ρ€ΠΎΠ²Ρ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² ΠΏΠΎΠ·ΠΆΠ΅ я создам класс MovableObject, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ΠΌ класса GameObject с функциями пСрСмСщСния.

Π’ΠΎ врСмя ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° я задаю Π΅Π³ΠΎ Ρ†Π²Π΅Ρ‚, Ρ„ΠΎΡ€ΠΌΡƒ ΠΈ ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅. ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Ρ‚Π°ΠΊΠΆΠ΅ ΠΈΠΌΠ΅Π΅Ρ‚ ссылку Π½Π° ΠΏΠΎΠ²Π΅Ρ€Ρ…Π½ΠΎΡΡ‚ΡŒ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° _surface, Ρ‚Π°ΠΊ Ρ‡Ρ‚ΠΎ ΠΎΠ½ ΠΌΠΎΠΆΠ΅Ρ‚ сам Π·Π°Π±ΠΎΡ‚ΠΈΡ‚ΡŒΡΡ ΠΎ своСм Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π΅ Π½Π° основной повСрхности. Для этой Ρ†Π΅Π»ΠΈ Ρƒ нас Π΅ΡΡ‚ΡŒ функция draw, которая вызываСтся Ρ€Π°Π½Π΅Π΅ созданным GameRenderer для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠ³ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°. Π’ зависимости ΠΎΡ‚ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° is_circle ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ отобраТаСтся Π»ΠΈΠ±ΠΎ Π² Π²ΠΈΠ΄Π΅ ΠΊΡ€ΡƒΠ³Π°, Π»ΠΈΠ±ΠΎ Π² Π²ΠΈΠ΄Π΅ ΠΏΡ€ΡΠΌΠΎΡƒΠ³ΠΎΠ»ΡŒΠ½ΠΈΠΊΠ° (Π² нашСм случаС я ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽ ΠΊΠ²Π°Π΄Ρ€Π°Ρ‚ со слСгка Π·Π°ΠΊΡ€ΡƒΠ³Π»Π΅Π½Π½Ρ‹ΠΌΠΈ ΡƒΠ³Π»Π°ΠΌΠΈ для стСн ΠΈ ΠΊΡ€ΡƒΠ³ для Pac-Man ΠΈ ΠΏΠ΅Ρ‡Π΅Π½ΡŒΡ).

class GameObject:
    def __init__(self, in_surface, x, y,
                 in_size: int, in_color=(255, 0, 0),
                 is_circle: bool = False):
        self._size = in_size
        self._renderer: GameRenderer = in_surface
        self._surface = in_surface._screen
        self.y = y
        self.x = x
        self._color = in_color
        self._circle = is_circle
        self._shape = pygame.Rect(self.x, self.y, in_size, in_size)

    def draw(self):
        if self._circle:
            pygame.draw.circle(self._surface,
                               self._color,
                               (self.x, self.y),
                               self._size)
        else:
            rect_object = pygame.Rect(self.x, self.y, self._size, self._size)
            pygame.draw.rect(self._surface,
                             self._color,
                             rect_object,
                             border_radius=4)

    def tick(self):
        pass

Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ класс стСны Π±ΡƒΠ΄Π΅Ρ‚ просто. Для стСн Π²Ρ‹Π±ΠΈΡ€Π°ΡŽ синий Ρ†Π²Π΅Ρ‚ согласно ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΌΡƒ Pac-Man (ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ Ρ†Π²Π΅Ρ‚Π° β€” Blue 255, ΠΎΡΡ‚Π°Π»ΡŒΠ½ΠΎΠ΅ 0).

class Wall(GameObject):
    def __init__(self, in_surface, x, y, in_size: int, in_color=(0, 0, 255)):
        super().__init__(in_surface, x * in_size, y * in_size, in_size, in_color)

ΠŸΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²Π»Π΅Π½ ΠΊΠΎΠ΄ для Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ для стСн. ΠŸΡ€ΠΈ написании слСдитС Π·Π° Ρ‚Π΅ΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ классы Wall ΠΈ GameObject Π±Ρ‹Π»ΠΈ Π²Ρ‹ΡˆΠ΅ класса GameRenderer, Ρ‡Ρ‚ΠΎΠ±Ρ‹ класс ΠΈΡ… Β«Π²ΠΈΠ΄Π΅Π»Β». Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ шагом являСтся визуализация Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π° Π½Π° экранС. Но ΠΏΠ΅Ρ€Π΅Π΄ этим ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½ Π²ΡΠΏΠΎΠΌΠΎΠ³Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ класс.

>> the_game_controller_class

Π― ΡΠΎΡ…Ρ€Π°Π½ΡŽ Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚ Π² символах ASCII Π² ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ Π² Π½ΠΎΠ²ΠΎΠΌ классС PacmanGameController. Π― Π±ΡƒΠ΄Ρƒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ исходный Ρ€Π°Π·ΠΌΠ΅Ρ€ Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π° β€” 28x31 Ρ‚Π°ΠΉΠ». ПозТС ΠΌΠ½Π΅ Π½ΡƒΠΆΠ½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΠ±Π΅Π΄ΠΈΡ‚ΡŒΡΡ, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠΈ смогут ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ ΠΏΡ€ΠΎΠΉΡ‚ΠΈ Ρ‡Π΅Ρ€Π΅Π· Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚ ΠΈ, Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, Π½Π°ΠΉΡ‚ΠΈ ΠΈΠ³Ρ€ΠΎΠΊΠ°. Π‘Π½Π°Ρ‡Π°Π»Π° я ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°ΡŽ Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚ ΠΊΠ°ΠΊ символы ΠΈ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΡŽ Π΅Π³ΠΎ Π² ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρƒ Π΅Π΄ΠΈΠ½ΠΈΡ† ΠΈ Π½ΡƒΠ»Π΅ΠΉ, Π³Π΄Π΅ стСна Ρ€Π°Π²Π½Π° Π½ΡƒΠ»ΡŽ, Π° ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΠΌΠΎΠ΅ пространство Ρ€Π°Π²Π½ΠΎ Π΅Π΄ΠΈΠ½ΠΈΡ†Π΅. Π­Ρ‚ΠΈ значСния слуТат Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΡƒ поиска ΠΏΡƒΡ‚ΠΈ Π² качСствС Ρ‚Π°ΠΊ Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ стоимости. Ноль ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ Π±Π΅ΡΠΊΠΎΠ½Π΅Ρ‡Π½ΡƒΡŽ ΡΡ‚ΠΎΠΈΠΌΠΎΡΡ‚ΡŒ прохоТдСния, поэтому элСмСнты Π² массивС, ΠΎΡ‚ΠΌΠ΅Ρ‡Π΅Π½Π½Ρ‹Π΅ Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Π½Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒΡΡ ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΠΌΡ‹ΠΌΠΈ. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° массив reachable_spaces, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ содСрТит ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ части Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π°. Но ΠΎΠ± этом ΠΏΠΎΠ·ΠΆΠ΅, сначала я Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΈΡ‚ΡŒ структуры классов. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚ Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ ASCII с ΠΌΠΎΠ΅Π³ΠΎ GitHub. Π’ ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡Π΅Π½ΠΈΠΈ пСрсонаТа я использовал X для стСны, P для Pac-Man ΠΈ G для ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠ°.

class PacmanGameController:
    def __init__(self):
        self.ascii_maze = [
            "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "XP           XX            X",
            "X XXXX XXXXX XX XXXXX XXXX X",
            "X XXXX XXXXX XX XXXXX XXXX X",
            "X XXXX XXXXX XX XXXXX XXXX X",
            "X                          X",
            "X XXXX XX XXXXXXXX XX XXXX X",
            "X XXXX XX XXXXXXXX XX XXXX X",
            "X      XX    XX    XX      X",
            "XXXXXX XXXXX XX XXXXX XXXXXX",
            "XXXXXX XXXXX XX XXXXX XXXXXX",
            "XXXXXX XX          XX XXXXXX",
            "XXXXXX XX XXXXXXXX XX XXXXXX",
            "XXXXXX XX X   G  X XX XXXXXX",
            "          X G    X          ",
            "XXXXXX XX X   G  X XX XXXXXX",
            # shortened for article, full ascii on my github
            "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        ]

        self.numpy_maze = []
        self.cookie_spaces = []
        self.reachable_spaces = []
        self.ghost_spawns = []

        self.size = (0, 0)
        self.convert_maze_to_numpy()
        #self.p = Pathfinder(self.numpy_maze) # use later


    def convert_maze_to_numpy(self):
        for x, row in enumerate(self.ascii_maze):
            self.size = (len(row), x + 1)
            binary_row = []
            for y, column in enumerate(row):
                if column == "G":
                    self.ghost_spawns.append((y, x))

                if column == "X":
                    binary_row.append(0)
                else:
                    binary_row.append(1)
                    self.cookie_spaces.append((y, x))
                    self.reachable_spaces.append((y, x))
            self.numpy_maze.append(binary_row)

>> rendering_the_maze

ВсС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ΅ для Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π° ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²Π»Π΅Π½ΠΎ, поэтому ΠΎΡΡ‚Π°Π»ΠΎΡΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ экзСмпляры Π½Π°ΡˆΠΈΡ… классов PacmanGameController, ΠΏΡ€ΠΎΠΉΡ‚ΠΈΡΡŒ ΠΏΠΎ 2D-массиву с позициями стСн ΠΈ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π² этих мСстах ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Wall (я ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ add_wall, которая Π½Π΅ ΠΏΠΎΠΊΠ°Π·Π°Π½Π° здСсь, Π΅Ρ‰Π΅ Ρ€Π°Π· взглянитС Π½Π° ΠΏΠΎΠ»Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π½Π° ΠΌΠΎΠ΅ΠΌ GitHub). Π― установил частоту обновлСния 120 ΠΊΠ°Π΄Ρ€ΠΎΠ² Π² сСкунду.

if __name__ == "__main__":
    unified_size = 32
    pacman_game = PacmanGameController()
    size = pacman_game.size
    game_renderer = GameRenderer(size[0] * unified_size, size[1] * unified_size)

    for y, row in enumerate(pacman_game.numpy_maze):
        for x, column in enumerate(row):
            if column == 0:
                game_renderer.add_wall(Wall(game_renderer, x, y, unified_size))

    game_renderer.tick(120)

>> let’s_add_ghosts!

Π’ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΌ Pac-Man Π±Ρ‹Π»ΠΎ Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅ ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠ° ΠΏΠΎ ΠΈΠΌΠ΅Π½ΠΈ Π‘Π»ΠΈΠ½ΠΊΠΈ, Пинки, Инки ΠΈ Клайд, ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ со своим Ρ…Π°Ρ€Π°ΠΊΡ‚Π΅Ρ€ΠΎΠΌ ΠΈ способностями. ΠšΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΡ ΠΈΠ³Ρ€Ρ‹ основана Π½Π° японской сказкС (ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅ здСсь ΠΈ здСсь), Π° ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹Π΅ названия Π½Π° японском языкС Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»Π°Π³Π°ΡŽΡ‚ ΠΈΡ… способности (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Ρƒ Пинки японскоС имя Π’ΠΎΡ€, Ρƒ Π‘Π»ΠΈΠ½ΠΊΠΈ β€” ВСнь). Однако для нашСй ΠΈΠ³Ρ€Ρ‹ ΠΌΡ‹ Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ Π²Π΄Π°Π²Π°Ρ‚ΡŒΡΡ Π² Ρ‚Π°ΠΊΠΈΠ΅ подробности, ΠΈ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ повСдСнчСский Ρ†ΠΈΠΊΠ», ΠΊΠ°ΠΊ ΠΈ Π² ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π΅, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ Ρ€Π΅ΠΆΠΈΠΌΡ‹ «прСслСдованиС», «рассСиваниС» ΠΈ «испуг». ΠœΡ‹ опишСм ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ эти Ρ€Π΅ΠΆΠΈΠΌΡ‹ ИИ Π²ΠΎ Π²Ρ‚ΠΎΡ€ΠΎΠΉ части.

Класс-ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊ Π±ΡƒΠ΄Π΅Ρ‚ простым, унаслСдовав Π±ΠΎΠ»ΡŒΡˆΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ своСго повСдСния ΠΎΡ‚ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ класса MovableObject (посмотритС ΠΌΠΎΠΉ GitHub, этот класс Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ слоТнСС ΠΈ Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Π»ΠΎΠ³ΠΈΠΊΡƒ для двиТСния Π² Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅Ρ… направлСниях, слСдования ΠΏΠΎ ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚Ρƒ ΠΈ ​​провСрки Π½Π° столкновСния со стСнами).

class Ghost(MovableObject):
    def __init__(self, in_surface, x, y, in_size: int, in_game_controller, in_color=(255, 0, 0)):
        super().__init__(in_surface, x, y, in_size, in_color, False)
        self.game_controller = in_game_controller

Π― добавлю значСния RGB для Ρ†Π²Π΅Ρ‚ΠΎΠ² ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠ° Π² класс PacmanGameController ΠΈ ΡΠ³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΡŽ Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅ Ρ†Π²Π΅Ρ‚Π½Ρ‹Ρ… ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠ° Π² основной Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ. Π― Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²Π»ΡŽ ΡΡ‚Π°Ρ‚ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ для прСобразования ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚, которая просто ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅Ρ‚ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π° (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, x=16 y=16 ΠΏΡ€ΠΈΠ±Π»ΠΈΠ·ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ соотвСтствуСт Ρ†Π΅Π½Ρ‚Ρ€Ρƒ Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π°, ΠΈ ΡƒΠΌΠ½ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° Ρ€Π°Π·ΠΌΠ΅Ρ€ ячСйки ΠΈΠ»ΠΈ Ρ‚Π°ΠΉΠ»Π° Π΄Π°Π΅Ρ‚ ΠΌΠ½Π΅ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρƒ Π½Π° ΠΏΠΎΠ²Π΅Ρ€Ρ…Π½ΠΎΡΡ‚ΡŒ ΠΈΠ³Ρ€Ρ‹ Π² пиксСлях).

# inPacmanGameController
self.ghost_colors = [
        (255, 184, 255),
        (255, 0, 20),
        (0, 255, 255),
        (255, 184, 82)
    ]

# in main
for i, ghost_spawn in enumerate(pacman_game.ghost_spawns):
    translated = translate_maze_to_screen(ghost_spawn)
    ghost = Ghost(game_renderer, translated[0], translated[1], unified_size, pacman_game,
                  pacman_game.ghost_colors[i % 4])
    game_renderer.add_game_object(ghost)

# General functions for coordinate conversion, place at the beginning of the code
def translate_screen_to_maze(in_coords, in_size=32):
    return int(in_coords[0] / in_size), int(in_coords[1] / in_size)

def translate_maze_to_screen(in_coords, in_size=32):
    return in_coords[0] * in_size, in_coords[1] * in_size

На этом этапС Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅ ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠ° Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒΡΡ Π² Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π΅ ΠΏΡ€ΠΈ запускС ΠΈΠ³Ρ€Ρ‹. Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Π·Π°ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΈΡ… Π΄Π²ΠΈΠ³Π°Ρ‚ΡŒΡΡ.

>> maze_pathfinding

Π’Π΅ΠΏΠ΅Ρ€ΡŒ наступаСт, ΠΏΠΎΠΆΠ°Π»ΡƒΠΉ, самая слоТная Ρ‡Π°ΡΡ‚ΡŒ. Поиск ΠΏΡƒΡ‚ΠΈ Π² Π΄Π²ΡƒΠΌΠ΅Ρ€Π½ΠΎΠΌ пространствС ΠΈΠ»ΠΈ Π³Ρ€Π°Ρ„Π΅ β€” слоТная Π·Π°Π΄Π°Ρ‡Π°. РСализация Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ° Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ Ρ‚Π°ΠΊΠΎΠΉ Π·Π°Π΄Π°Ρ‡ΠΈ заняла Π±Ρ‹ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΡƒΡŽ ΡΡ‚Π°Ρ‚ΡŒΡŽ, поэтому Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡΡ Π³ΠΎΡ‚ΠΎΠ²Ρ‹ΠΌ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ΠΌ. НаиболСС эффСктивным Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠΎΠΌ поиска ΠΏΡƒΡ‚ΠΈ являСтся Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ A*. Π­Ρ‚ΠΎ обСспСчиваСтся ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠΌ tcod, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ установили Π²Π½Π°Ρ‡Π°Π»Π΅.

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠΎΠ², я создам класс с ΠΈΠΌΠ΅Π½Π΅ΠΌ Pathfinder. Π’ конструкторС я ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΡŽ массив numpy со ΡΡ‚ΠΎΠΈΠΌΠΎΡΡ‚ΡŒΡŽ прохоТдСния (массив Π΅Π΄ΠΈΠ½ΠΈΡ† ΠΈ Π½ΡƒΠ»Π΅ΠΉ, описанный Ρ€Π°Π½Π΅Π΅) ΠΈ создам ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ класса pf, которая Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ экзСмпляр Π½Π°Π²ΠΈΠ³Π°Ρ‚ΠΎΡ€Π° A*. Π—Π°Ρ‚Π΅ΠΌ функция get_path рассчитаСт ΠΈ Π²Π΅Ρ€Π½Π΅Ρ‚ ΠΏΡƒΡ‚ΡŒ Π² Π²ΠΈΠ΄Π΅ сСрии шагов Π² массивС ΠΏΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ с ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π°ΠΌΠΈ Π² Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π΅ (ΠΎΡ‚ΠΊΡƒΠ΄Π°, ΠΊΡƒΠ΄Π°).

class Pathfinder:
    def __init__(self, in_arr):
        cost = np.array(in_arr, dtype=np.bool_).tolist()
        self.pf = tcod.path.AStar(cost=cost, diagonal=0)

    def get_path(self, from_x, from_y, to_x, to_y) -> object:
        res = self.pf.get_path(from_x, from_y, to_x, to_y)
        return [(sub[1], sub[0]) for sub in res]

Π’Π΅ΠΏΠ΅Ρ€ΡŒ я добавлю Ρ€Π°Π·Π΄Π΅Π» ΠΊ основной Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ поиск ΠΏΡƒΡ‚ΠΈ. Π― Π²Ρ‹Π±ΠΈΡ€Π°ΡŽ Π½Π°Ρ‡Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ [1,1] ΠΈ ΠΏΡƒΠ½ΠΊΡ‚ назначСния ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚Π° [24,24]. Π­Ρ‚ΠΎ Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΊΠΎΠ΄.

# draw path - optional
red = (255, 0, 0)
green = (0, 255, 0)
_from = (1, 1)
_to = (24, 24)
path_array = pacman_game.p.get_path(_from[1], _from[0], _to[1], _to[0])

print(path_array)
# [(1, 2), (1, 3), (1, 4), (1, 5), (2, 5), (3, 5), (4, 5), (5, 5), (6, 5), (6, 6), (6, 7) ...

white = (255, 255, 255)
for path in path_array:
    game_renderer.add_game_object(Wall(game_renderer, path[0], path[1], unified_size, white))

from_translated = translate_maze_to_screen(_from)
game_renderer.add_game_object(
    GameObject(game_renderer, from_translated[0], from_translated[1], unified_size, red))

to_translated = translate_maze_to_screen(_to)
game_renderer.add_game_object(
    GameObject(game_renderer, to_translated[0], to_translated[1], unified_size, green))

Π’ ΠΈΠ³Ρ€Π΅ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³ ΠΊΡ€Π°Ρ‚Ρ‡Π°ΠΉΡˆΠ΅Π³ΠΎ ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚Π° выглядит Ρ‚Π°ΠΊ:

>> randomized_ghost_movement

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ собираСмся ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ Π² классС PacmanGameController для Π²Ρ‹Π±ΠΎΡ€Π° случайной Ρ‚ΠΎΡ‡ΠΊΠΈ ΠΈΠ· массива reachable_spaces. ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ эту Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ послС Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ достигнСт мСста назначСния. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠΈ Π±ΡƒΠ΄ΡƒΡ‚ просто Π²Ρ‹Π±ΠΈΡ€Π°Ρ‚ΡŒ ΠΏΡƒΡ‚ΡŒ ΠΎΡ‚ своСго Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ полоТСния Π² Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π΅ Π΄ΠΎ случайного мСста назначСния Π½Π° Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹ΠΉ срок. Π’ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ части ΠΌΡ‹ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ Π±ΠΎΠ»Π΅Π΅ слоТноС ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅, Ρ‚Π°ΠΊΠΎΠ΅ ΠΊΠ°ΠΊ погоня ΠΈ бСгство ΠΎΡ‚ ΠΈΠ³Ρ€ΠΎΠΊΠ°.

def request_new_random_path(self, in_ghost: Ghost):
    random_space = random.choice(self.reachable_spaces)
    current_maze_coord = translate_screen_to_maze(in_ghost.get_position())

    path = self.p.get_path(current_maze_coord[1], current_maze_coord[0], random_space[1],
                           random_space[0])
    test_path = [translate_maze_to_screen(item) for item in path]
    in_ghost.set_new_path(test_path)

Π’ классС Ghost ΠΌΡ‹ добавляСм Π½ΠΎΠ²ΡƒΡŽ Π»ΠΎΠ³ΠΈΠΊΡƒ для слСдования ΠΏΠΎ ΠΏΡƒΡ‚ΠΈ. Ѐункция reached_target Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΊΠ°Π΄Ρ€ ΠΈ провСряСт, достиг Π»ΠΈ ΡƒΠΆΠ΅ ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊ своСй Ρ†Π΅Π»ΠΈ. Если Π΄Π°, Ρ‚ΠΎ ΠΎΠ½ опрСдСляСт, Π² ΠΊΠ°ΠΊΠΎΠΌ Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠΈ находится ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ шаг ΠΏΡƒΡ‚ΠΈ Ρ‡Π΅Ρ€Π΅Π· Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚, ΠΈ Π½Π°Ρ‡ΠΈΠ½Π°Π΅Ρ‚ ΠΌΠ΅Π½ΡΡ‚ΡŒ своС ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π²Π²Π΅Ρ€Ρ…, Π²Π½ΠΈΠ·, Π²Π»Π΅Π²ΠΎ ΠΈΠ»ΠΈ Π²ΠΏΡ€Π°Π²ΠΎ (Π»ΠΎΠ³ΠΈΠΊΠ° двиТСния вызываСтся Π² Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠΌ классС MovableObject).

def reached_target(self):
    if (self.x, self.y) == self.next_target:
        self.next_target = self.get_next_location()
    self.current_direction = self.calculate_direction_to_next_target()

def set_new_path(self, in_path):
    for item in in_path:
        self.location_queue.append(item)
    self.next_target = self.get_next_location()

def calculate_direction_to_next_target(self) -> Direction:
    if self.next_target is None:
        self.game_controller.request_new_random_path(self)
        return Direction.NONE
    diff_x = self.next_target[0] - self.x
    diff_y = self.next_target[1] - self.y
    if diff_x == 0:
        return Direction.DOWN if diff_y > 0 else Direction.UP
    if diff_y == 0:
        return Direction.LEFT if diff_x < 0 else Direction.RIGHT
    self.game_controller.request_new_random_path(self)
    return Direction.NONE

def automatic_move(self, in_direction: Direction):
    if in_direction == Direction.UP:
        self.set_position(self.x, self.y - 1)
    elif in_direction == Direction.DOWN:
        self.set_position(self.x, self.y + 1)
    elif in_direction == Direction.LEFT:
        self.set_position(self.x - 1, self.y)
    elif in_direction == Direction.RIGHT:
        self.set_position(self.x + 1, self.y)

ΠŸΡ€ΠΈΠ·Ρ€Π°ΠΊΠΈ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ Π² позициях, ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡Π΅Π½Π½Ρ‹Ρ… Π±ΡƒΠΊΠ²ΠΎΠΉ G Π² исходном Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π΅ ASCII, ΠΈ Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‚ ΠΈΡΠΊΠ°Ρ‚ΡŒ случайный ΠΏΡƒΡ‚ΡŒ. Π― Π·Π°ΠΏΠ΅Ρ€ Π² ΠΊΠ»Π΅Ρ‚ΠΊΠ΅ Ρ‚Ρ€Π΅Ρ… ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠΎΠ² β€” ΠΊΠ°ΠΊ ΠΈ Π² ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΌ Pacman, ΠΎΠ½ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒΡΡ ΠΏΠΎ ΠΎΠ΄Π½ΠΎΠΌΡƒ β€” ΠΈ ΠΎΠ΄ΠΈΠ½ Π±Ρ€ΠΎΠ΄ΠΈΡ‚ ΠΏΠΎ Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Ρƒ:

>> player_controls

Π§Ρ‚ΠΎΠ±Ρ‹ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ ΠΏΠ»Π΅Π΅Ρ€Π°, я создам класс ΠΏΠΎΠ΄ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ Hero. Π‘ΠΎΠ»ΡŒΡˆΠ°Ρ Ρ‡Π°ΡΡ‚ΡŒ Π»ΠΎΠ³ΠΈΠΊΠΈ управлСния ΠΊΠ°ΠΊ ΠΈΠ³Ρ€ΠΎΠΊΠΎΠΌ, Ρ‚Π°ΠΊ ΠΈ ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠ°ΠΌΠΈ обрабатываСтся Π² классС MovableObject, поэтому Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ всСго нСсколько Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ для опрСдСлСния повСдСния ΠΈΠ³Ρ€ΠΎΠΊΠ°. Π’ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΌ Pacman ΠΈΠ³Ρ€ΠΎΠΊ ΠΌΠΎΠΆΠ΅Ρ‚ Π΄Π²ΠΈΠ³Π°Ρ‚ΡŒΡΡ Π² Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅Ρ… направлСниях, управляСмых клавишами со стрСлками. Если Π½ΠΈ ΠΎΠ΄Π½Π° клавиша со стрСлкой Π½Π΅ Π½Π°ΠΆΠ°Ρ‚Π°, ΠΈΠ³Ρ€ΠΎΠΊ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠ΅ Π² послСднСм допустимом Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠΈ. Если клавиша Π½Π°ΠΆΠ°Ρ‚Π° Π² Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠΈ, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΈΠ³Ρ€ΠΎΠΊ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π΄Π²ΠΈΠ³Π°Ρ‚ΡŒΡΡ, это Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ сохраняСтся ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌ доступном Ρ…ΠΎΠ΄Π΅. Π― воспроизвСду это ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π² нашСй ΠΈΠ³Ρ€Π΅, Π° Ρ‚Π°ΠΊΠΆΠ΅ добавлю ΡΠΏΠΎΡΠΎΠ±Π½ΠΎΡΡ‚ΡŒ Пакмана Ρ‚Π΅Π»Π΅ΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΈΠ· ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ½Ρ†Π° Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π° Π² Π΄Ρ€ΡƒΠ³ΠΎΠΉ β€” я просто ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡŽ, находится Π»ΠΈ ΠΈΠ³Ρ€ΠΎΠΊ Π²Π½Π΅ ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠΉ Π·ΠΎΠ½Ρ‹ с Π»Π΅Π²ΠΎΠΉ ΠΈΠ»ΠΈ ΠΏΡ€Π°Π²ΠΎΠΉ стороны, ΠΈ ΡƒΡΡ‚Π°Π½ΠΎΠ²Π»ΡŽ Π΅Π³ΠΎ ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° ΠΏΡ€ΠΎΡ‚ΠΈΠ²ΠΎΠΏΠΎΠ»ΠΎΠΆΠ½ΡƒΡŽ сторону Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π° соотвСтствСнно. Π’ Pacman Ρ‚Π°ΠΊΠΆΠ΅ Π΅ΡΡ‚ΡŒ модифицированная функция Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°, Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒ Π΅Π³ΠΎ Π²Π΄Π²ΠΎΠ΅ мСньшС, Ρ‡Π΅ΠΌ ΠΎΠ½ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ Π·Π°Π½ΠΈΠΌΠ°Π΅Ρ‚ (ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ pygame.rect).

class Hero(MovableObject):
    def __init__(self, in_surface, x, y, in_size: int):
        super().__init__(in_surface, x, y, in_size, (255, 255, 0), False)
        self.last_non_colliding_position = (0, 0)

    def tick(self):
        # TELEPORT
        if self.x < 0:
            self.x = self._renderer._width

        if self.x > self._renderer._width:
            self.x = 0

        self.last_non_colliding_position = self.get_position()

        if self.check_collision_in_direction(self.direction_buffer)[0]:
            self.automatic_move(self.current_direction)
        else:
            self.automatic_move(self.direction_buffer)
            self.current_direction = self.direction_buffer

        if self.collides_with_wall((self.x, self.y)):
            self.set_position(self.last_non_colliding_position[0], self.last_non_colliding_position[1])

        self.handle_cookie_pickup()

    def automatic_move(self, in_direction: Direction):
        collision_result = self.check_collision_in_direction(in_direction)

        desired_position_collides = collision_result[0]
        if not desired_position_collides:
            self.last_working_direction = self.current_direction
            desired_position = collision_result[1]
            self.set_position(desired_position[0], desired_position[1])
        else:
            self.current_direction = self.last_working_direction

    def handle_cookie_pickup(self):
        collision_rect = pygame.Rect(self.x, self.y, self._size, self._size)
        cookies = self._renderer.get_cookies()
        game_objects = self._renderer.get_game_objects()
        for cookie in cookies:
            collides = collision_rect.colliderect(cookie.get_shape())
            if collides and cookie in game_objects:
                game_objects.remove(cookie)

    def draw(self):
        half_size = self._size / 2
        pygame.draw.circle(self._surface, self._color, (self.x + half_size, self.y + half_size), half_size)

Π― создаю экзСмпляр класса Hero Π² ΠΊΠΎΠ½Ρ†Π΅ основной Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ. Π—Π°Π΄Π°ΡŽ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ с ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π°ΠΌΠΈ [1,1] β€” unified_size β€” Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ‚Π°ΠΉΠ»Π°. Π’Π°ΠΊΠΆΠ΅ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… событий Π² класс GameRenderer, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΌΡ‹ ΠΌΠΎΠ³Π»ΠΈ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΈΠ³Ρ€ΠΎΠ²Ρ‹ΠΌ пСрсонаТСм.

# in GameRenderer class
def add_hero(self, in_hero):
        self.add_game_object(in_hero)
        self._hero = in_hero

def _handle_events(self):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            self._done = True

    pressed = pygame.key.get_pressed()
    if pressed[pygame.K_UP]:
        self._hero.set_direction(Direction.UP)
    elif pressed[pygame.K_LEFT]:
        self._hero.set_direction(Direction.LEFT)
    elif pressed[pygame.K_DOWN]:
        self._hero.set_direction(Direction.DOWN)
    elif pressed[pygame.K_RIGHT]:
        self._hero.set_direction(Direction.RIGHT)


# at the end of main function
pacman = Hero(game_renderer, unified_size, unified_size, unified_size)
game_renderer.add_hero(pacman)
game_renderer.tick(120)

ПослС запуска ΠΈΠ³Ρ€Ρ‹ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΈΠ³Ρ€ΠΎΠΊΠΎΠΌ β€” Pacman!

>> adding_cookies

Π­Ρ‚ΠΎ Π±Ρ‹Π» Π±Ρ‹ Π½Π΅ Пакман Π±Π΅Π· ΠΏΠ΅Ρ‡Π΅Π½ΡŒΡ Π² Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚Π΅. Π‘ Ρ‚ΠΎΡ‡ΠΊΠΈ зрСния ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠ³ΠΎ процСсса ΠΎΠ½ΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ ΡΡ‚Π΅ΠΏΠ΅Π½ΡŒ исслСдования ΠΌΠΈΡ€Π°, Π° Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ cookie Π΄Π°ΠΆΠ΅ ΠΌΠ΅Π½ΡΡŽΡ‚ способности ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠΎΠ² ΠΈ Пакмана. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, ΠΎΠ½ΠΈ ΡΠ²Π»ΡΡŽΡ‚ΡΡ Π²Ρ‹ΡΡˆΠ΅ΠΉ Π½Π°Π³Ρ€Π°Π΄ΠΎΠΉ для ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ² ΠΈ основным ΠΏΠΎΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΌ ΠΈΡ… прогрСсса Π² уровнях. Π’ соврСмСнных ΠΈΠ³Ρ€Π°Ρ… ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π³Π΅ΠΉΠΌΠ΄ΠΈΠ·Π°ΠΉΠ½Π΅Ρ€ Ρ…ΠΎΡ‡Π΅Ρ‚ ΠΏΠΎΠΎΡ‰Ρ€ΡΡ‚ΡŒ Π² ΠΈΠ³Ρ€ΠΎΠΊΠ΅, ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ вознаграТдаСтся. ΠŸΡ€Π΅ΠΊΡ€Π°ΡΠ½Ρ‹ΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠΌ являСтся Elden Ring, Π³Π΄Π΅ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ, ΠΊΡ‚ΠΎ исслСдуСт ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΡƒΠ³ΠΎΠ»ΠΎΠΊ ΠΌΠΈΡ€Π°, ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ Π²ΠΎΠ·Π½Π°Π³Ρ€Π°ΠΆΠ΄Π΅Π½ΠΈΠ΅. Π§Π΅ΠΌ опаснСС ΠΈ ΠΎΡ‚Π΄Π°Π»Π΅Π½Π½Π΅Π΅, Ρ‚Π΅ΠΌ большС Π½Π°Π³Ρ€Π°Π΄Π°. Π‘ Π΄Ρ€ΡƒΠ³ΠΎΠΉ стороны, Ρ‚Π°ΠΊΠΈΠ΅ ΠΈΠ³Ρ€Ρ‹, ΠΊΠ°ΠΊ Assassin's Creed, ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π·Π°Π΄Π°Ρ‡, поэтому Π²ΠΎ врСмя ΠΈΠ³Ρ€Ρ‹ Ρƒ вас Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ ΠΎΡ‰ΡƒΡ‰Π΅Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ Π²Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚Π΅, Π° Π½Π΅ ΠΈΠ³Ρ€Π°Π΅Ρ‚Π΅.

Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»ΠΎΠ² cookie Π±ΡƒΠ΄Π΅Ρ‚ самым простым Π²ΠΎ всСм ΡƒΡ€ΠΎΠΊΠ΅, поэтому я оставил Π΅Π³ΠΎ Π½Π° ΠΊΠΎΠ½Π΅Ρ†, ΠΊΠ°ΠΊ Π²ΠΈΡˆΠ΅Π½ΠΊΡƒ Π½Π° Ρ‚ΠΎΡ€Ρ‚Π΅. Π― создам класс ΠΏΠΎΠ΄ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ Cookie. Π•Π³ΠΎ экзСмпляр всСгда Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΠΌΠ΅Ρ‚ΡŒ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅ пиксСля, ΠΆΠ΅Π»Ρ‚Ρ‹ΠΉ Ρ†Π²Π΅Ρ‚ ΠΈ ΠΊΡ€ΡƒΠ³Π»ΡƒΡŽ Ρ„ΠΎΡ€ΠΌΡƒ. Π’ основной Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ я создам ΠΊΡƒΠΊΠΈ Π½Π° всСх Ρ‚Π°ΠΉΠ»Π°Ρ…, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ Π²Π½Π°Ρ‡Π°Π»Π΅ сохранили Π² массивС cookie_spaces (Ρ‚ΠΎΡ‚ ΠΆΠ΅, Ρ‡Ρ‚ΠΎ ΠΈ reachable_spaces). Π― добавлю Π² ΠΏΠ»Π΅Π΅Ρ€ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ с ΠΈΠΌΠ΅Π½Π΅ΠΌ handle_cookie_pickup, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ я постоянно ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡŽ, Π½Π΅ сталкиваСтся Π»ΠΈ ΠΏΠ»Π΅Π΅Ρ€ с ΠΊΠ°ΠΊΠΈΠΌ-Π»ΠΈΠ±ΠΎ cookie. Если это Ρ‚Π°ΠΊ, я ΡƒΠ΄Π°Π»ΡŽ Ρ„Π°ΠΉΠ» cookie ΠΈΠ· массива, ΠΈ ΠΎΠ½ большС Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒΡΡ.

class Cookie(GameObject):
    def __init__(self, in_surface, x, y):
        super().__init__(in_surface, x, y, 4, (255, 255, 0), True)

# in GameRenderer class 
def add_cookie(self, obj: GameObject):
        self._game_objects.append(obj)
        self._cookies.append(obj)

# in Hero class
def handle_cookie_pickup(self):
    collision_rect = pygame.Rect(self.x, self.y, self._size, self._size)
    cookies = self._renderer.get_cookies()
    game_objects = self._renderer.get_game_objects()
    for cookie in cookies:
        collides = collision_rect.colliderect(cookie.get_shape())
        if collides and cookie in game_objects:
            game_objects.remove(cookie)

# in main function:
for cookie_space in pacman_game.cookie_spaces:
    translated = translate_maze_to_screen(cookie_space)
    cookie = Cookie(game_renderer, translated[0] + unified_size / 2, translated[1] + unified_size / 2)
    game_renderer.add_cookie(cookie)

А Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ Π½Π°ΡˆΠΈΡ… стараний:

НСбольшой интСрСсный Ρ„Π°ΠΊΡ‚ напослСдок β€” Π² ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΉ ΠΈΠ³Ρ€Π΅ Пакман останавливаСтся Π½Π° ΠΎΠ΄ΠΈΠ½ ΠΊΠ°Π΄Ρ€ послС Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΡΡŠΠ΅ΡΡ‚ ΠΊΠ°ΠΆΠ΄ΠΎΠ΅ ΠΏΠ΅Ρ‡Π΅Π½ΡŒΠ΅, поэтому ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠ°ΠΌ Π»Π΅Π³Ρ‡Π΅ Π΅Π³ΠΎ ΠΏΠΎΠΉΠΌΠ°Ρ‚ΡŒ Π² Π½Π°Ρ‡Π°Π»Π΅ ΠΈΠ³Ρ€Ρ‹, ΠΊΠΎΠ³Π΄Π° ΠΏΠΎΠ»Π΅ Π΅Ρ‰Π΅ Π·Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΎ. Π’ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ части ΠΌΡ‹ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½ΡƒΡŽ ΠΈΠ³Ρ€ΠΎΠ²ΡƒΡŽ ΠΌΠ΅Ρ…Π°Π½ΠΈΠΊΡƒ, ΠΈ Π²Ρ‹ Ρ‚Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Ρ€Π°ΡΡΡ‡ΠΈΡ‚Ρ‹Π²Π°Ρ‚ΡŒ Π½Π° искусствСнный ΠΈΠ½Ρ‚Π΅Π»Π»Π΅ΠΊΡ‚ для ΠΏΡ€ΠΈΠ·Ρ€Π°ΠΊΠΎΠ², отслСТиваниС ΠΎΡ‡ΠΊΠΎΠ², Π·Π²ΡƒΠΊΠΈ, Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΡŽ, тСкстуры, бонусы, эффСкты дроТания экрана, ΠΆΠΈΠ·Π½ΠΈ ΠΈ ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Π΅ состояния ΠΈΠ³Ρ€Ρ‹.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊΠΈ

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•

admin
11 дСкабря 2018

ООП Π½Π° Python: ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠΈ, ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python допускаСт Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ»ΠΎΠ³ΠΈΠΈ, Π½ΠΎ Π² Π΅Π³ΠΎ основС...
admin
28 июня 2018

3 самых Π²Π°ΠΆΠ½Ρ‹Ρ… сфСры примСнСния Python: возмоТности языка

БущСствуСт мноТСство областСй примСнСния Python, Π½ΠΎ Π² Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΎΠ½ особСнно...
admin
13 фСвраля 2017

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python: ΠΎΡ‚ Π½ΠΎΠ²ΠΈΡ‡ΠΊΠ° Π΄ΠΎ профСссионала

Пошаговая инструкция для всСх, ΠΊΡ‚ΠΎ Ρ…ΠΎΡ‡Π΅Ρ‚ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒΒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python...