- Введение
- Установка pygame
- Инициализация pygame и определение цветов
- Установка размеров окна и свойств сегментов
- Создание игрового окна и часов
- Определение функций для отображения текста и проверки столкновений
- Функция для отображения текста
- Функция для проверки столкновений
- Добавление функций в код
- Реализация логики игры
- Добавление функции в код
- Проверка работы кода
- Заключение
Введение
В ходе данной статьи мы напишем код игры «Змейка» на Python с использованием библиотеки pygame.
Установка pygame
Перед написанием кода нам понадобится установить библиотеку pygame. Для этого нужно перейти в терминал/командную строку и прописать pip install pygame, нажать Enter и ждать установки.
Инициализация pygame и определение цветов
После инсталляции мы импортируем pygame, а также модуль random.
import pygame
import random
Далее проинициализируем pygame и определим цвета, которые будут использоваться в игре.
import pygame
import random
pygame.init()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
Установка размеров окна и свойств сегментов
Теперь укажем размеры окна. В переменную window_width сохраним ширину окна, а в window_height — высоту.
import pygame
import random
pygame.init()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
window_width = 800
window_height = 600
Также определим размеры сегментов змейки и её скорости. В переменную segment_size сохраним размер змейки, а в segment_speed — её скорость.
import pygame
import random
pygame.init()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
window_width = 800
window_height = 600
segment_size = 20
segment_speed = 20
Создание игрового окна и часов
Создадим игровое окно указав в качестве ширины и высоты переменные window_width и window_height соответственно. Также в качестве заголовка окна укажем «Змейка» и создадим объект часов для управлением частотой кадров.
import pygame
import random
pygame.init()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
window_width = 800
window_height = 600
segment_size = 20
segment_speed = 20
window = pygame.display.set_mode((window_width, window_height))
pygame.display.set_caption("Змейка")
clock = pygame.time.Clock()
Определение функций для отображения текста и проверки столкновений
Функция для отображения текста
Создадим функцию для отображения текста, которую назовём show_text(). В неё будет передаваться 5 параметров, а именно:
- surface — параметр, представляющий окно pygame, на котором будет отображен текст;
- text — текст, который будет отображен на поверхности;
- size — размер шрифта отображаемого текста;
- x, y — определяют координаты, где текст будет размещен на поверхности.
def show_text(surface, text, size, x, y):
Внутри функции сначала инициализируем объект шрифта обратившись к функции SysFont(), в которую в качестве первого аргумента будет передано значение None (указывает, что будет использован шрифт по умолчанию), а в качестве второго — размер шрифта (параметр size).
def show_text(surface, text, size, x, y):
font = pygame.font.SysFont(None, size)
Далее обратимся к методу render() для создания поверхности с указанным текстом, с параметром сглаживания установленным как True, и цветом установленным как WHITE (он был определён в самом начале нашего кода).
def show_text(surface, text, size, x, y):
font = pygame.font.SysFont(None, size)
text_surface = font.render(text, True, WHITE)
И последнее что мы сделаем, так это отрисуем наш текст на окне при помощи метода blit().
Синтаксис метода pygame.blit():
pygame.blit(source, dest, area=None, special_flags=0)
Где:
- source — отображает исходную поверхность на целевой поверхности;
- dest — позиция для отображения;
- area — можно также передать объект Rect в качестве позиции назначения, и верхний левый угол прямоугольника будет использоваться в качестве позиции для отображения.
def show_text(surface, text, size, x, y):
font = pygame.font.SysFont(None, size)
text_surface = font.render(text, True, WHITE)
surface.blit(text_surface, (x, y))
Функция для проверки столкновений
Создадим функцию для проверки столкновений, которую назовём check_collision(). В неё будет передаваться параметр segment_list:
def check_collision(segment_list):
Внутри функции в переменную head сохраним первый элемент списка.
def check_collision(segment_list):
head = segment_list[0]
Добавим условие, что если x-координата головы меньше 0 или больше или равна window_width, или если y-координата головы меньше 0 или больше или равна window_height, то функция вернёт True, указывая на столкновение с границами окна.
def check_collision(segment_list):
head = segment_list[0]
if head[0] < 0 or head[0] >= window_width or head[1] < 0 or head[1] >= window_height:
return True
Если же условие не сработало, то далее будет идти следующее условие, что если голова найдена в списке сегментов, начиная со второго элемента (segment_list[1:]), функция также вернёт True, указывая на столкновение змейки с самой собой.
def check_collision(segment_list):
head = segment_list[0]
if head[0] < 0 or head[0] >= window_width or head[1] < 0 or head[1] >= window_height:
return True
if head in segment_list[1:]:
return True
Если же ни одно условие не сработает, то будет возвращено значение False.
def check_collision(segment_list):
head = segment_list[0]
if head[0] < 0 or head[0] >= window_width or head[1] < 0 or head[1] >= window_height:
return True
if head in segment_list[1:]:
return True
return False
Добавление функций в код
Добавим наши функции в код:
import pygame
import random
pygame.init()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
window_width = 800
window_height = 600
segment_size = 20
segment_speed = 20
window = pygame.display.set_mode((window_width, window_height))
pygame.display.set_caption("Змейка")
clock = pygame.time.Clock()
def show_text(surface, text, size, x, y):
font = pygame.font.SysFont(None, size)
text_surface = font.render(text, True, WHITE)
surface.blit(text_surface, (x, y))
def check_collision(segment_list):
head = segment_list[0]
if head[0] < 0 or head[0] >= window_width or head[1] < 0 or head[1] >= window_height:
return True
if head in segment_list[1:]:
return True
return False
Реализация логики игры
Создадим функцию, которую назовём run_game(). В ней будет находиться логика игры.
def run_game():
Внутри функции создадим переменные game_over и game_close равные False. Они будут предназначена для определения, была ли игра завершена. Также зададим начальное положение и направление змейки.
def run_game():
game_over = False
game_close = False
head_x = window_width // 2
head_y = window_height // 2
dx = 0
dy = 0
Создадим список для хранения сегментов змейки и инициализируем длину сегментов. Также зададим начальную позицию яблока сохранив координаты по x и y в соответствующие переменные (apple_x и apple_y). Координаты будут определяться случайным образом, чтобы во время начала новой игры яблоко всегда появлялось в случайном месте.
def run_game():
game_over = False
game_close = False
head_x = window_width // 2
head_y = window_height // 2
dx = 0
dy = 0
segment_list = []
segment_length = 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
Создадим бесконечный цикл while, а внутри него цикл while, который будет работать, пока game_close является True. Внутри вложенного цикла сначала будет производиться заполнение игрового поля (окна) в чёрный цвет при помощи метода fill(). Далее будет отображаться текст оповещающий о конце игры, а также текст с предложением закрыть окно или начать новую игру. Также будет произведено обновление содержимое окна, чтобы отобразить все изменения, произошедшие внутри цикла.
def run_game():
game_over = False
game_close = False
head_x = window_width // 2
head_y = window_height // 2
dx = 0
dy = 0
segment_list = []
segment_length = 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
while not game_over:
while game_close:
window.fill(BLACK)
show_text(window, f"Конец игры! Ваш счёт: {segment_length - 1}", 30, 250, 300)
show_text(window, "Нажмите 'Q' для выхода или 'C' для начала новой игры", 30, 110, 350)
pygame.display.update()
Далее внутри вложенного цикла будет располагаться вложенный цикл for, который будет проходиться по всем событиям, произошедшим с момента последней проверки очереди событий. Внутри него будет производиться проверка, что если пользователь нажал на клавишу q, то игра будет завершена, а если на клавишу c, то игра будет начата сначала.
def run_game():
game_over = False
game_close = False
head_x = window_width // 2
head_y = window_height // 2
dx = 0
dy = 0
segment_list = []
segment_length = 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
while not game_over:
while game_close:
window.fill(BLACK)
show_text(window, f"Конец игры! Ваш счёт: {segment_length - 1}", 30, 250, 300)
show_text(window, "Нажмите 'Q' для выхода или 'C' для начала новой игры", 30, 110, 350)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
run_game()
Далее в основном цикле while будет идти цикл for, предназначенный для проверки всех событий игры. Внутри него будет идти условие, что если происходит событие выхода из игры (например, нажатие на крестик в углу окна), то игра завершается. Также, если будет происходить событие нажатия клавиши, то в зависимости от нажатой клавиши будут выполняться определенные действия (например при нажатии определённой стрелочки змейка повернёт в указанную строну).
def run_game():
game_over = False
game_close = False
head_x = window_width // 2
head_y = window_height // 2
dx = 0
dy = 0
segment_list = []
segment_length = 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
while not game_over:
while game_close:
window.fill(BLACK)
show_text(window, f"Конец игры! Ваш счёт: {segment_length - 1}", 30, 250, 300)
show_text(window, "Нажмите 'Q' для выхода или 'C' для начала новой игры", 30, 110, 350)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
run_game()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
dx = -segment_speed
dy = 0
elif event.key == pygame.K_RIGHT:
dx = segment_speed
dy = 0
elif event.key == pygame.K_UP:
dx = 0
dy = -segment_speed
elif event.key == pygame.K_DOWN:
dx = 0
dy = segment_speed
Далее, в цикле while будет происходить обновление позиции головы змейки и добавление нового сегмента.
def run_game():
game_over = False
game_close = False
head_x = window_width // 2
head_y = window_height // 2
dx = 0
dy = 0
segment_list = []
segment_length = 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
while not game_over:
while game_close:
window.fill(BLACK)
show_text(window, f"Конец игры! Ваш счёт: {segment_length - 1}", 30, 250, 300)
show_text(window, "Нажмите 'Q' для выхода или 'C' для начала новой игры", 30, 110, 350)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
run_game()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
dx = -segment_speed
dy = 0
elif event.key == pygame.K_RIGHT:
dx = segment_speed
dy = 0
elif event.key == pygame.K_UP:
dx = 0
dy = -segment_speed
elif event.key == pygame.K_DOWN:
dx = 0
dy = segment_speed
head_x += dx
head_y += dy
segment_list.insert(0, (head_x, head_y))
После этого будут идти условия. В первом условии, если змейка не съела яблоко, то лишняя часть хвоста будет удаляться. Далее идёт проверка на столкновения и проверка на съедение яблока.
После условий будет произведена очистка окна.
def run_game():
game_over = False
game_close = False
head_x = window_width // 2
head_y = window_height // 2
dx = 0
dy = 0
segment_list = []
segment_length = 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
while not game_over:
while game_close:
window.fill(BLACK)
show_text(window, f"Конец игры! Ваш счёт: {segment_length - 1}", 30, 250, 300)
show_text(window, "Нажмите 'Q' для выхода или 'C' для начала новой игры", 30, 110, 350)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
run_game()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
dx = -segment_speed
dy = 0
elif event.key == pygame.K_RIGHT:
dx = segment_speed
dy = 0
elif event.key == pygame.K_UP:
dx = 0
dy = -segment_speed
elif event.key == pygame.K_DOWN:
dx = 0
dy = segment_speed
head_x += dx
head_y += dy
segment_list.insert(0, (head_x, head_y))
if len(segment_list) > segment_length:
segment_list.pop()
if check_collision(segment_list):
game_close = True
if head_x == apple_x and head_y == apple_y:
segment_length += 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
window.fill(BLACK)
Далее будет идти цикл for для отрисовки змейки. После него будет производиться отрисовка яблока, отображение счёта, обновление отображения и ограничение скорости до 15 кадров.
def run_game():
game_over = False
game_close = False
head_x = window_width // 2
head_y = window_height // 2
dx = 0
dy = 0
segment_list = []
segment_length = 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
while not game_over:
while game_close:
window.fill(BLACK)
show_text(window, f"Конец игры! Ваш счёт: {segment_length - 1}", 30, 250, 300)
show_text(window, "Нажмите 'Q' для выхода или 'C' для начала новой игры", 30, 110, 350)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
run_game()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
dx = -segment_speed
dy = 0
elif event.key == pygame.K_RIGHT:
dx = segment_speed
dy = 0
elif event.key == pygame.K_UP:
dx = 0
dy = -segment_speed
elif event.key == pygame.K_DOWN:
dx = 0
dy = segment_speed
head_x += dx
head_y += dy
segment_list.insert(0, (head_x, head_y))
if len(segment_list) > segment_length:
segment_list.pop()
if check_collision(segment_list):
game_close = True
if head_x == apple_x and head_y == apple_y:
segment_length += 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
window.fill(BLACK)
for segment in segment_list:
pygame.draw.rect(window, GREEN, (segment[0], segment[1], segment_size, segment_size))
pygame.draw.rect(window, RED, (apple_x, apple_y, segment_size, segment_size))
show_text(window, "Очки: {}".format(segment_length - 1), 30, 10, 10)
pygame.display.update()
clock.tick(15)
После выхода из основного цикла while будет производиться завершение работы pygame.
def run_game():
game_over = False
game_close = False
head_x = window_width // 2
head_y = window_height // 2
dx = 0
dy = 0
segment_list = []
segment_length = 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
while not game_over:
while game_close:
window.fill(BLACK)
show_text(window, f"Конец игры! Ваш счёт: {segment_length - 1}", 30, 250, 300)
show_text(window, "Нажмите 'Q' для выхода или 'C' для начала новой игры", 30, 110, 350)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
run_game()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
dx = -segment_speed
dy = 0
elif event.key == pygame.K_RIGHT:
dx = segment_speed
dy = 0
elif event.key == pygame.K_UP:
dx = 0
dy = -segment_speed
elif event.key == pygame.K_DOWN:
dx = 0
dy = segment_speed
head_x += dx
head_y += dy
segment_list.insert(0, (head_x, head_y))
if len(segment_list) > segment_length:
segment_list.pop()
if check_collision(segment_list):
game_close = True
if head_x == apple_x and head_y == apple_y:
segment_length += 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
window.fill(BLACK)
for segment in segment_list:
pygame.draw.rect(window, GREEN, (segment[0], segment[1], segment_size, segment_size))
pygame.draw.rect(window, RED, (apple_x, apple_y, segment_size, segment_size))
show_text(window, "Очки: {}".format(segment_length - 1), 30, 10, 10)
pygame.display.update()
clock.tick(15)
pygame.quit()
quit()
Добавление функции в код
Добавим функцию run_game() в основной код.
import pygame
import random
pygame.init()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
window_width = 800
window_height = 600
segment_size = 20
segment_speed = 20
window = pygame.display.set_mode((window_width, window_height))
pygame.display.set_caption("Змейка")
clock = pygame.time.Clock()
def show_text(surface, text, size, x, y):
font = pygame.font.SysFont(None, size)
text_surface = font.render(text, True, WHITE)
surface.blit(text_surface, (x, y))
def check_collision(segment_list):
head = segment_list[0]
if head[0] < 0 or head[0] >= window_width or head[1] < 0 or head[1] >= window_height:
return True
if head in segment_list[1:]:
return True
return False
def run_game():
game_over = False
game_close = False
head_x = window_width // 2
head_y = window_height // 2
dx = 0
dy = 0
segment_list = []
segment_length = 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
while not game_over:
while game_close:
window.fill(BLACK)
show_text(window, f"Конец игры! Ваш счёт: {segment_length - 1}", 30, 250, 300)
show_text(window, "Нажмите 'Q' для выхода или 'C' для начала новой игры", 30, 110, 350)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
run_game()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
dx = -segment_speed
dy = 0
elif event.key == pygame.K_RIGHT:
dx = segment_speed
dy = 0
elif event.key == pygame.K_UP:
dx = 0
dy = -segment_speed
elif event.key == pygame.K_DOWN:
dx = 0
dy = segment_speed
head_x += dx
head_y += dy
segment_list.insert(0, (head_x, head_y))
if len(segment_list) > segment_length:
segment_list.pop()
if check_collision(segment_list):
game_close = True
if head_x == apple_x and head_y == apple_y:
segment_length += 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
window.fill(BLACK)
for segment in segment_list:
pygame.draw.rect(window, GREEN, (segment[0], segment[1], segment_size, segment_size))
pygame.draw.rect(window, RED, (apple_x, apple_y, segment_size, segment_size))
show_text(window, "Очки: {}".format(segment_length - 1), 30, 10, 10)
pygame.display.update()
clock.tick(15)
pygame.quit()
quit()
Проверка работы кода
Т.к. наша функция run_game() готова, вызовем её.
import pygame
import random
pygame.init()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
window_width = 800
window_height = 600
segment_size = 20
segment_speed = 20
window = pygame.display.set_mode((window_width, window_height))
pygame.display.set_caption("Змейка")
clock = pygame.time.Clock()
def show_text(surface, text, size, x, y):
font = pygame.font.SysFont(None, size)
text_surface = font.render(text, True, WHITE)
surface.blit(text_surface, (x, y))
def check_collision(segment_list):
head = segment_list[0]
if head[0] < 0 or head[0] >= window_width or head[1] < 0 or head[1] >= window_height:
return True
if head in segment_list[1:]:
return True
return False
def run_game():
game_over = False
game_close = False
head_x = window_width // 2
head_y = window_height // 2
dx = 0
dy = 0
segment_list = []
segment_length = 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
while not game_over:
while game_close:
window.fill(BLACK)
show_text(window, f"Конец игры! Ваш счёт: {segment_length - 1}", 30, 250, 300)
show_text(window, "Нажмите 'Q' для выхода или 'C' для начала новой игры", 30, 110, 350)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
run_game()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
dx = -segment_speed
dy = 0
elif event.key == pygame.K_RIGHT:
dx = segment_speed
dy = 0
elif event.key == pygame.K_UP:
dx = 0
dy = -segment_speed
elif event.key == pygame.K_DOWN:
dx = 0
dy = segment_speed
head_x += dx
head_y += dy
segment_list.insert(0, (head_x, head_y))
if len(segment_list) > segment_length:
segment_list.pop()
if check_collision(segment_list):
game_close = True
if head_x == apple_x and head_y == apple_y:
segment_length += 1
apple_x = random.randint(0, (window_width // segment_size) - 1) * segment_size
apple_y = random.randint(0, (window_height // segment_size) - 1) * segment_size
window.fill(BLACK)
for segment in segment_list:
pygame.draw.rect(window, GREEN, (segment[0], segment[1], segment_size, segment_size))
pygame.draw.rect(window, RED, (apple_x, apple_y, segment_size, segment_size))
show_text(window, f"Очки: {segment_length - 1}", 30, 10, 10)
pygame.display.update()
clock.tick(15)
pygame.quit()
quit()
run_game()
![](https://it-start.online/wp-content/uploads/2024/03/output-1.gif)
Заключение
В ходе статьи мы с Вами написали игру «Змейка» на Python используя библиотеку pygame. Надеюсь Вам понравилась статья, желаю удачи и успехов! 🙂