Введение
В этом проекте мы создадим игру в лабиринт с использованием библиотеки Pygame на Python. В игре игрок должен перемещаться по лабиринту, собирая продукты питания, и избегать стен. Мы разделим процесс разработки на несколько этапов, чтобы сделать его легче понять и следовать.
👀 Предпросмотр

🎯 Задачи
В этом проекте вы научитесь:
- настраивать игровую среду с использованием Pygame;
- создавать лабиринт с использованием клеток и стен;
- добавлять продукты питания для сбора игроком;
- реализовывать движение игрока и обнаружение столкновений;
- обрабатывать игровую логику, включая подсчет очков и условия окончания игры;
- отслеживать рекорд игрока;
- отображать игровые статистики, такие как время, счет и рекорд, на экране.
🏆 Достижения
После завершения этого проекта вы сможете:
- использовать библиотеку Pygame для разработки игр;
- применять концепции объектно-ориентированного программирования для создания игровых элементов;
- демонстрировать алгоритмическое мышление и способность решать проблемы при генерации лабиринта;
- обрабатывать события и ввод игрока;
- реализовывать обнаружение столкновений и механику движения в игровой среде;
- управлять обработкой файлов для хранения и извлечения игровых рекордов;
- отображать игровые статистики и информацию на экране.
Настройка среды
Сначала мы создадим файлы проекта для игры в Лабиринт.
cd ~/project
touch maze.py
sudo pip install pygame
В этом шаге мы настроим среду Pygame и опишем константы.
import pygame
from random import choice, randrange
## Константы для размеров экрана и размера тайла
RES = WIDTH, HEIGHT = 1202, 902
TILE = 100
cols, rows = WIDTH // TILE, HEIGHT // TILE
## Остальной код будет располагаться здесь...
В этом шаге:
- Мы импортируем необходимые библиотеки (Pygame и random).
- Определяем константы для размеров экрана и размера тайла.
- Инициализируем Pygame и настраиваем игровое окно.
- Загружаем изображения фона для игры.
Создание класса Cell
В этом шаге мы определим класс Cell для представления клеток лабиринта.
## Определите класс для представления клеток в лабиринте
class Cell:
def __init__(self, x, y):
self.x, self.y = x, y
## Стены представляют границы клетки
self.walls = {"top": True, "right": True, "bottom": True, "left": True}
self.visited = False
self.thickness = 4
## Нарисуйте стены клетки
def draw(self, sc):
x, y = self.x * TILE, self.y * TILE
if self.walls["top"]:
pygame.draw.line(
sc, pygame.Color("darkorange"), (x, y), (x + TILE, y), self.thickness
)
if self.walls["right"]:
pygame.draw.line(
sc,
pygame.Color("darkorange"),
(x + TILE, y),
(x + TILE, y + TILE),
self.thickness,
)
if self.walls["bottom"]:
pygame.draw.line(
sc,
pygame.Color("darkorange"),
(x + TILE, y + TILE),
(x, y + TILE),
self.thickness,
)
if self.walls["left"]:
pygame.draw.line(
sc, pygame.Color("darkorange"), (x, y + TILE), (x, y), self.thickness
)
## Получите прямоугольники, представляющие каждую стену клетки
def get_rects(self):
rects = []
x, y = self.x * TILE, self.y * TILE
if self.walls["top"]:
rects.append(pygame.Rect((x, y), (TILE, self.thickness)))
if self.walls["right"]:
rects.append(pygame.Rect((x + TILE, y), (self.thickness, TILE)))
if self.walls["bottom"]:
rects.append(pygame.Rect((x, y + TILE), (TILE, self.thickness)))
if self.walls["left"]:
rects.append(pygame.Rect((x, y), (self.thickness, TILE)))
return rects
## Проверьте, существует ли соседняя клетка
def check_cell(self, x, y):
find_index = lambda x, y: x + y * cols
if x < 0 or x > cols - 1 or y < 0 or y > rows - 1:
return False
return self.grid_cells[find_index(x, y)]
## Получите соседние клетки, которые не были посещены
def check_neighbors(self, grid_cells):
self.grid_cells = grid_cells
neighbors = []
top = self.check_cell(self.x, self.y - 1)
right = self.check_cell(self.x + 1, self.y)
bottom = self.check_cell(self.x, self.y + 1)
left = self.check_cell(self.x - 1, self.y)
if top and not top.visited:
neighbors.append(top)
if right and not right.visited:
neighbors.append(right)
if bottom and not bottom.visited:
neighbors.append(bottom)
if left and not left.visited:
neighbors.append(left)
return choice(neighbors) if neighbors else False
## Остальной код будет располагаться здесь...
В этом шаге:
- Мы определяем класс
Cellс его свойствами и методами для рисования стен и проверки соседей.
Удаление стен и генерация лабиринта
В этом шаге мы создадим функции для удаления стен и генерации лабиринта.
## Функция для удаления стен между двумя соседними клетками
def remove_walls(current, next):
dx = current.x - next.x
if dx == 1:
current.walls["left"] = False
next.walls["right"] = False
elif dx == -1:
current.walls["right"] = False
next.walls["left"] = False
dy = current.y - next.y
if dy == 1:
current.walls["top"] = False
next.walls["bottom"] = False
elif dy == -1:
current.walls["bottom"] = False
next.walls["top"] = False
## Функция для генерации лабиринта
def generate_maze():
grid_cells = [Cell(col, row) for row in range(rows) for col in range(cols)]
current_cell = grid_cells[0]
array = []
break_count = 1
while break_count!= len(grid_cells):
current_cell.visited = True
next_cell = current_cell.check_neighbors(grid_cells)
if next_cell:
next_cell.visited = True
break_count += 1
array.append(current_cell)
remove_walls(current_cell, next_cell)
current_cell = next_cell
elif array:
current_cell = array.pop()
return grid_cells
## Остальной код будет располагаться здесь...
В этом шаге:
- Мы определяем функцию
remove_wallsдля удаления стен между соседними клетками. - Мы создаем функцию
generate_mazeдля генерации лабиринта с использованием алгоритма поиска в глубину.
Добавление еды в игру
В этом шаге мы создадим класс Food, чтобы добавить предметы еды в игру.
## Класс для представления еды в игре
class Food:
def __init__(self):
## Загрузить изображение еды
self.img = pygame.image.load("img/food.png").convert_alpha()
self.img = pygame.transform.scale(self.img, (TILE - 10, TILE - 10))
self.rect = self.img.get_rect()
self.set_pos()
## Установить позицию еды случайным образом
def set_pos(self):
self.rect.topleft = randrange(cols) * TILE + 5, randrange(rows) * TILE + 5
## Нарисовать еду на экране
def draw(self):
game_surface.blit(self.img, self.rect)
## Остальной код будет располагаться здесь...
В этом шаге:
- Мы определяем класс
Foodс методами для установки позиции и рисования предметов еды.
Движение игрока и обнаружение столкновений
В этом шаге мы настроим управление игроком, его движение и обнаружение столкновений.
## Проверить, сталкивается ли игрок с стенами
def is_collide(x, y):
tmp_rect = player_rect.move(x, y)
if tmp_rect.collidelist(walls_collide_list) == -1:
return False
return True
## Остальной код будет располагаться здесь...
В этом шаге:
- Мы определяем функцию
is_collideдля проверки, сталкивается ли игрок с стенами.
Игра и подсчет очков
В этом шаге мы реализуем игровую логику, включая поедание еды и подсчет очков.
## Проверить, съел ли игрок какую-либо еду
def eat_food():
for food in food_list:
if player_rect.collidepoint(food.rect.center):
food.set_pos()
return True
return False
## Проверить, закончился ли игра (закончилось время)
def is_game_over():
global time, score, record, FPS
if time < 0:
pygame.time.wait(700)
player_rect.center = TILE // 2, TILE // 2
[food.set_pos() for food in food_list]
set_record(record, score)
record = get_record()
time, score, FPS = 60, 0, 60
## Остальной код будет располагаться здесь...
В этом шаге:
- Мы определяем функцию
eat_foodдля проверки, съел ли игрок какую-либо еду. - Мы создаем функцию
is_game_overдля проверки, закончился ли игра, когда время вышло.
Обработка рекордов
В этом шаге мы реализуем сохранение рекордов для игры.
## Функция для получения текущего рекорда из файла
def get_record():
try:
with open("record") as f:
return f.readline()
except FileNotFoundError:
with open("record", "w") as f:
f.write("0")
return "0"
## Функция для установки и обновления рекорда в файле
def set_record(record, score):
rec = max(int(record), score)
with open("record", "w") as f:
f.write(str(rec))
## Остальной код будет располагаться здесь...
В этом шаге:
- Мы определяем функции для получения текущего рекорда из файла и его обновления.
Инициализация игры
В этом шаге мы выполним задачи инициализации игры.
## Initialize Pygame and set up the game window
FPS = 60
pygame.init()
game_surface = pygame.Surface(RES)
surface = pygame.display.set_mode((WIDTH + 300, HEIGHT))
clock = pygame.time.Clock()
## Load background images
bg_game = pygame.image.load("img/bg_1.jpg").convert()
bg = pygame.image.load("img/bg_main.jpg").convert()
## Generate the maze
maze = generate_maze()
## Player settings
player_speed = 5
player_img = pygame.image.load("img/0.png").convert_alpha()
player_img = pygame.transform.scale(
player_img, (TILE - 2 * maze[0].thickness, TILE - 2 * maze[0].thickness)
)
player_rect = player_img.get_rect()
player_rect.center = TILE // 2, TILE // 2
directions = {
"a": (-player_speed, 0),
"d": (player_speed, 0),
"w": (0, -player_speed),
"s": (0, player_speed),
}
keys = {"a": pygame.K_LEFT, "d": pygame.K_RIGHT, "w": pygame.K_UP, "s": pygame.K_DOWN}
direction = (0, 0)
## Food settings
food_list = [Food() for i in range(3)]
## Create a list of rectangles representing walls for collision detection
walls_collide_list = sum([cell.get_rects() for cell in maze], [])
## Timer, score, and record
pygame.time.set_timer(pygame.USEREVENT, 1000)
time = 60
score = 0
record = get_record()
## Fonts
font = pygame.font.SysFont("Impact", 150)
text_font = pygame.font.SysFont("Impact", 80)
## The rest of your code will go here...
В этом шаге:
- Мы выполняем различные задачи инициализации, включая настройку Pygame, загрузку изображений, генерацию лабиринта и инициализацию переменных, связанных с игроком и едой.
Основной игровой цикл
В этом шаге мы настроим основной игровой цикл и отобразим игровые элементы.
## Основной игровой цикл
while True:
## Вывести на экран фоновые изображения
surface.blit(bg, (WIDTH, 0))
surface.blit(game_surface, (0, 0))
game_surface.blit(bg_game, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
if event.type == pygame.USEREVENT:
time -= 1
## Обработать управление игроком и его движение
pressed_key = pygame.key.get_pressed()
for key, key_value in keys.items():
if pressed_key[key_value] and not is_collide(*directions[key]):
direction = directions[key]
break
if not is_collide(*direction):
player_rect.move_ip(direction)
## Нарисовать лабиринт
[cell.draw(game_surface) for cell in maze]
## Игровой процесс: проверить, съел ли игрок еду и закончился ли игра
if eat_food():
FPS += 10
score += 1
is_game_over()
## Нарисовать игрока
game_surface.blit(player_img, player_rect)
## Нарисовать элементы еды
[food.draw() for food in food_list]
## Остальной код будет располагаться здесь...
В этом шаге:
- Мы настроим основной игровой цикл, который обрабатывает события, движение игрока и рендеринг игры.
Отображение игровой статистики
В этом шаге мы будем отображать игровую статистику на экране.
## Draw game statistics
surface.blit(
text_font.render("TIME", True, pygame.Color("cyan"), True), (WIDTH + 70, 30)
)
surface.blit(font.render(f"{time}", True, pygame.Color("cyan")), (WIDTH + 70, 130))
surface.blit(
text_font.render("score:", True, pygame.Color("forestgreen"), True),
(WIDTH + 50, 350),
)
surface.blit(
font.render(f"{score}", True, pygame.Color("forestgreen")), (WIDTH + 70, 430)
)
surface.blit(
text_font.render("record:", True, pygame.Color("magenta"), True),
(WIDTH + 30, 620),
)
surface.blit(
font.render(f"{record}", True, pygame.Color("magenta")), (WIDTH + 70, 700)
)
pygame.display.flip()
clock.tick(FPS)
В этом шаге:
- Мы используем шрифты для отображения игровой информации, такой как время, счет и рекорд.
- Мы используем метод
blit()для рисования текста на экране. - Мы используем метод
flip()для обновления отображения.
Запустить игру
Теперь, когда мы завершили все шаги, мы можем запустить игру Лабиринт с помощью следующей команды:
cd ~/project
python maze.py

Резюме
В этом проекте мы разделили процесс создания игры Лабиринт с использованием Pygame на десять четких и управляемых шагов. Вы научитесь настраивать игровую среду, создавать ячейки лабиринта, генерировать лабиринт, обрабатывать движение игрока и обнаружение столкновений, реализовывать игровой процесс и подсчет очков, управлять рекордами и многое другое. Следуя этим шагам, вы сможете создать полностью функциональную игру Лабиринт на Python.



