import raylib as rl
# Определяем константы для размеров экрана, клеток и спрайтов
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
CELL_SIZE = 40
SPRITE_SIZE = 32
# Определяем константы для цветов
BLACK = rl.BLACK
WHITE = rl.WHITE
YELLOW = rl.YELLOW
BLUE = rl.BLUE
RED = rl.RED
PINK = rl.PINK
ORANGE = rl.ORANGE
# Определяем константы для направлений
UP = 0
RIGHT = 1
DOWN = 2
LEFT = 3
# Определяем константы для типов клеток
WALL = 0
DOT = 1
POWER = 2
EMPTY = 3
# Определяем константы для состояний игры
PLAYING = 0
GAME_OVER = 1
WIN = 2
# Создаем класс для игрового объекта
class GameObject:
# Конструктор класса
def __init__(self, x, y, texture, speed, direction):
# Координаты объекта
self.x = x
self.y = y
# Текстура объекта
self.texture = texture
# Скорость объекта
self.speed = speed
# Направление объекта
self.direction = direction
# Флаг, показывающий, что объект находится в движении
self.moving = False
# Флаг, показывающий, что объект находится под воздействием силы
self.powered = False
# Таймер, отсчитывающий время действия силы
self.power_timer = 0
# Метод для обновления состояния объекта
def update(self):
# Если объект находится в движении
if self.moving:
# Двигаем объект в зависимости от направления
if self.direction == UP:
self.y -= self.speed
elif self.direction == RIGHT:
self.x += self.speed
elif self.direction == DOWN:
self.y += self.speed
elif self.direction == LEFT:
self.x -= self.speed
# Проверяем, не вышел ли объект за границы экрана
if self.x < 0:
self.x = SCREEN_WIDTH - CELL_SIZE
elif self.x > SCREEN_WIDTH - CELL_SIZE:
self.x = 0
elif self.y < 0:
self.y = SCREEN_HEIGHT - CELL_SIZE
elif self.y > SCREEN_HEIGHT - CELL_SIZE:
self.y = 0
# Проверяем, не достиг ли объект центра клетки
if self.x % CELL_SIZE == 0 and self.y % CELL_SIZE == 0:
# Останавливаем объект
self.moving = False
# Если объект находится под воздействием силы
if self.powered:
# Уменьшаем таймер силы
self.power_timer -= 1
# Если таймер силы истек
if self.power_timer == 0:
# Снимаем воздействие силы
self.powered = False
# Метод для отрисовки объекта
def draw(self):
# Рисуем объект с помощью текстуры
rl.draw_texture(self.texture, self.x, self.y, WHITE)
# Создаем класс для игрового поля
class GameField:
# Конструктор класса
def __init__(self, map_file, wall_texture, dot_texture, power_texture):
# Текстура для стен
self.wall_texture = wall_texture
# Текстура для точек
self.dot_texture = dot_texture
# Текстура для сил
self.power_texture = power_texture
# Счетчик для количества собранных точек
self.dot_count = 0
# Счетчик для количества собранных сил
self.power_count = 0
# Матрица для хранения типов клеток
self.cells = []
# Открываем файл с картой
with open(map_file, "r") as file:
# Читаем строки из файла
lines = file.readlines()
# Проходим по строкам
for line in lines:
# Создаем список для хранения типов клеток в строке
row = []
# Проходим по символам в строке
for char in line:
# Если символ - знак стены
if char == "#":
# Добавляем в список тип стены
row.append(WALL)
# Если символ - знак точки
elif char == ".":
# Добавляем в список тип точки
row.append(DOT)
# Увеличиваем счетчик точек
self.dot_count += 1
# Если символ - знак силы
elif char == "*":
# Добавляем в список тип силы
row.append(POWER)
# Увеличиваем счетчик сил
self.power_count += 1
# Если символ - знак пустоты
elif char == " ":
# Добавляем в список тип пустоты
row.append(EMPTY)
# Добавляем список в матрицу
self.cells.append(row)
# Метод для обновления состояния поля
def update(self, pac_man, ghosts):
# Получаем индексы клетки, в которой находится пакман
i = pac_man.y // CELL_SIZE
j = pac_man.x // CELL_SIZE
# Получаем тип клетки
cell_type = self.cells[i][j]
# Если клетка - точка
if cell_type == DOT:
# Уменьшаем счетчик точек
self.dot_count -= 1
# Меняем тип клетки на пустоту
self.cells[i][j] = EMPTY
# Если клетка - сила
elif cell_type == POWER:
# Уменьшаем счетчик сил
self.power_count -= 1
# Меняем тип клетки на пустоту
self.cells[i][j] = EMPTY
# Включаем воздействие силы на пакмана
pac_man.powered = True
# Задаем таймер силы
pac_man.power_timer = 300
# Включаем воздействие силы на привидений
for ghost in ghosts:
ghost.powered = True
ghost.power_timer = 300
# Метод для отрисовки поля
def draw(self):
# Проходим по матрице клеток
for i in range(len(self.cells)):
for j in range(len(self.cells[i])):
# Получаем тип клетки
cell_type = self.cells[i][j]
# Получаем координаты клетки
x = j * CELL_SIZE
y = i * CELL_SIZE
# Если клетка - стена
if cell_type == WALL:
# Рисуем стену с помощью текстуры
rl.draw_texture(self.wall_texture, x, y, WHITE)
# Если клетка - точка
elif cell_type == DOT:
# Рисуем точку с помощью текстуры
rl.draw_texture(self.dot_texture, x + (CELL_SIZE - SPRITE_SIZE) // 2,
y + (CELL_SIZE - SPRITE_SIZE) // 2, WHITE)
# Если клетка - сила
elif cell_type == POWER:
# Рисуем силу с помощью текстуры
rl.draw_texture(self.power_texture, x + (CELL_SIZE - SPRITE_SIZE) // 2,
y + (CELL_SIZE - SPRITE_SIZE) // 2, WHITE)
# Создаем класс для игры
def draw():
# Начинаем рисование
rl.begin_drawing()
# Очищаем фон
rl.clear_background(BLACK)
# Рисуем поле
class Game:
# Конструктор класса
def __init__(self):
# Инициализируем библиотеку RayLib
rl.init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Pac-Man")
rl.set_target_fps(60)
# Загружаем текстуры для игровых объектов
self.pac_man_texture = rl.load_texture("pac_man.png")
self.blinky_texture = rl.load_texture("blinky.png")
self.pinky_texture = rl.load_texture("pinky.png")
self.inky_texture = rl.load_texture("inky.png")
self.clyde_texture = rl.load_texture("clyde.png")
self.wall_texture = rl.load_texture("wall.png")
self.dot_texture = rl.load_texture("dot.png")
self.power_texture = rl.load_texture("power.png")
# Создаем объекты для пакмана и привидений
self.pac_man = GameObject(360, 280, self.pac_man_texture, 2, RIGHT)
self.blinky = GameObject(360, 240, self.blinky_texture, 2, UP)
self.pinky = GameObject(360, 280, self.pinky_texture, 2, DOWN)
self.inky = GameObject(320, 280, self.inky_texture, 2, LEFT)
self.clyde = GameObject(400, 280, self.clyde_texture, 2, RIGHT)
# Создаем список для хранения привидений
self.ghosts = [self.blinky, self.pinky, self.inky, self.clyde]
# Создаем объект для игрового поля
self.field = GameField("map.txt", self.wall_texture, self.dot_texture, self.power_texture)
# Создаем переменную для хранения состояния игры
self.state = PLAYING
# Метод для обновления состояния игры
def update(self):
# Если игра продолжается
if self.state == PLAYING:
# Обновляем состояние пакмана
self.pac_man.update()
# Обновляем состояние привидений
for ghost in self.ghosts:
ghost.update()
# Обновляем состояние поля
self.field.update(self.pac_man, self.ghosts)
# Проверяем, не закончились ли точки и силы на поле
if self.field.dot_count == 0 and self.field.power_count == 0:
# Меняем состояние игры на победу
self.state = WIN
# Проверяем, не столкнулся ли пакман с привидением
for ghost in self.ghosts:
if self.pac_man.x == ghost.x and self.pac_man.y == ghost.y:
# Если пакман под воздействием силы
if self.pac_man.powered:
# Отправляем привидение в начальную позицию
ghost.x = 360
ghost.y = 280
ghost.direction = DOWN
ghost.moving = False
# Если пакман не под воздействием силы
else:
# Меняем состояние игры на проигрыш
self.state = GAME_OVER
# Обрабатываем ввод пользователя
self.handle_input()
# Если игра окончена
elif self.state == GAME_OVER or self.state == WIN:
# Обрабатываем ввод пользователя
self.handle_input()
# Метод для обработки ввода пользователя
def handle_input(self):
# Если нажата клавиша вверх
if rl.is_key_pressed(rl.KEY_UP):
# Пытаемся повернуть пакмана вверх
self.turn_pac_man(UP)
# Если нажата клавиша вправо
elif rl.is_key_pressed(rl.KEY_RIGHT):
# Пытаемся повернуть пакмана вправо
self.turn_pac_man(RIGHT)
# Если нажата клавиша вниз
elif rl.is_key_pressed(rl.KEY_DOWN):
# Пытаемся повернуть пакмана вниз
self.turn_pac_man(DOWN)
# Если нажата клавиша влево
elif rl.is_key_pressed(rl.KEY_LEFT):
# Пытаемся повернуть пакмана влево
self.turn_pac_man(LEFT)
# Если нажата клавиша пробел
elif rl.is_key_pressed(rl.KEY_SPACE):
# Если игра окончена
if self.state == GAME_OVER or self.state == WIN:
# Перезапускаем игру
self.restart()
# Метод для поворота пакмана
def turn_pac_man(self, direction):
# Если пакман не движется
if not self.pac_man.moving:
# Меняем направление пакмана
self.pac_man.direction = direction
# Проверяем, не столкнется ли пакман со стеной
if not self.check_collision(self.pac_man):
# Запускаем движение пакмана
self.pac_man.moving = True
# Если пакман движется
else:
# Запоминаем текущее направление пакмана
old_direction = self.pac_man.direction
# Меняем направление пакмана
self.pac_man.direction = direction
# Проверяем, не столкнется ли пакман со стеной
if not self.check_collision(self.pac_man):
# Запускаем движение пакмана
self.pac_man.moving = True
# Если столкнется
else:
# Возвращаем прежнее направление пакмана
self.pac_man.direction = old_direction
# Метод для проверки столкновения объекта со стеной
def check_collision(self, obj):
# Получаем индексы клетки, в которой находится объект
i = obj.y // CELL_SIZE
j = obj.x // CELL_SIZE
# Получаем тип клетки
cell_type = self.field.cells[i][j]
# Если клетка - стена
if cell_type == WALL:
# Возвращаем истину
return True
# Если клетка - не стена
else:
# Возвращаем ложь
return False
# Метод для перезапуска игры
def restart(self):
# Возвращаем пакмана и привидений в начальные позиции
self.pac_man.x = 360
self.pac_man.y = 280
self.pac_man.direction = RIGHT
self.pac_man.moving = False
self.pac_man.powered = False
self.pac_man.power_timer = 0
self.blinky.x = 360
self.blinky.y = 240
self.blinky.direction = UP
self.blinky.moving = False
self.blinky.powered = False
self.blinky.power_timer = 0
self.pinky.x = 360
self.pinky.y = 280
self.pinky.direction = DOWN
self.pinky.moving = False
self.pinky.powered = False
self.pinky.power_timer = 0
self.inky.x = 320
self.inky.y = 280
self.inky.direction = LEFT
self.inky.moving = False
self.inky.powered = False
self.inky.power_timer = 0
self.clyde.x = 400
self.clyde.y = 280
self.clyde.direction = RIGHT
self.clyde.moving = False
self.clyde.powered = False
self.clyde.power_timer = 0
# Восстанавливаем точки и силы на поле
self.field = GameField("map.txt", self.wall_texture, self.dot_texture, self.power_texture)
# Меняем состояние игры на продолжение
self.state = PLAYING
def main():
pac_man_texture = rl.load_texture("pac_man.png")
ghost_texture = rl.load_texture("ghost.png")
wall_texture = rl.load_texture("wall.png")
dot_texture = rl.load_texture("dot.png")
power_texture = rl.load_texture("power.png")
while not rl.window_should_close():
pac_man = GameObject(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2, pac_man_texture, 2, RIGHT)
ghosts = [GameObject(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2, ghost_texture, 1, LEFT)]
game_field = GameField("map.txt", wall_texture, dot_texture, power_texture)
pac_man.update()
for ghost in ghosts:
ghost.update()
game_field.update(pac_man, ghosts)
# Рисование
rl.begin_drawing()
rl.clear_background(BLACK)
pac_man.draw()
for ghost in ghosts:
ghost.draw()
game_field.draw()
rl.end_drawing()
# Очистка
rl.unload_texture(pac_man_texture)
rl.unload_texture(ghost_texture)
rl.unload_texture(wall_texture)
rl.unload_texture(dot_texture)
rl.unload_texture(power_texture)
rl.close_window()
if __name__ == "__main__":
main()