Я точно знаю, что в детстве вы все играли в игру «Змейка» и, конечно, всегда хотели выиграть. Будучи детьми, мы все любили искать баги в игре, чтобы никогда не видеть сообщение Game over, но сейчас, будучи технарями, нам наверняка хочется сделать игру так, чтобы комар носа не подточил. Именно об этом и пойдет речь в нашей статье.
Друзья, подписывайтесь на наш телеграм канал Pythonist. Там еще больше туториалов, задач и книг по Python
Перед тем как двигаться дальше, давайте посмотрим на основные разделы нашей статьи:
- Установка Pygame.
- Создание экрана.
- Создание змейки.
- Движение змейки.
- «Game over» при достижении змейкой границы.
- Добавление еды.
- Увеличение длины змейки.
- Вывод счета на экран.
Установка Pygame
Первое, что нам надо сделать, это установить библиотеку Pygame. Это можно сделать, просто выполнив следующую команду:
pip install pygame
Выполнив это, просто импортируем эту библиотеку и приступим к разработке игры. Но перед этим давайте взглянем на основные функции данной библиотеки, которые мы будем использовать при создании игры.
Функция | Описание |
init() |
Инициализирует все модули Pygame (возвращает кортеж в случае успеха или неудачи). |
display.set_mode() |
Для создания поверхности принимает в качестве параметра либо список либо кортеж (кортеж предпочтительней). |
update() |
Обновляет экран. |
quit() |
Используется для деинициализации всех модулей. |
set_caption() |
Устанавливает текст заголовка в верхней части экрана |
event.get() |
Возвращает список всех событий. |
Surface.fill() |
Заполняет пространство сплошным цветом. |
time.Clock() |
Отслеживание времени |
font.SysFont() |
Задает шрифт Pygame, используя системные ресурсы. |
Создание экрана
Для создания экрана при помощи Pygame нужно воспользоваться функцией display.set_mode()
. Также необходимо пользоваться методом init()
для инициализации экрана в начале кода и методом quit()
для его закрытия в конце. Метод update()
используется для применения каких-либо изменений на экране. Еще существует метод flip()
, который работает похожим с update()
образом. Разница заключается лишь в том, что метод flip()
переписывает весь экран целиком, а метод update()
применяет именно изменения (хотя если его использовать без параметров, то он тоже переписывает весь экран) .
import pygame pygame.init() dis=pygame.display.set_mode((400,300)) pygame.display.update() pygame.quit() quit()
Результат:
Однако, когда вы запустите данный код, экран появится лишь на мгновение, а затем исчезнет. Чтобы исправить эту ошибку, мы воспользуемся циклом while
, который будет работать до окончания игры:
import pygame pygame.init() dis=pygame.display.set_mode((400,300)) pygame.display.update() pygame.display.set_caption('Snake game by Pythonist') game_over=False while not game_over: for event in pygame.event.get(): print(event) # выводит на экран все действия игры pygame.quit() quit()
Теперь, запустив этот код, вы увидите, что экран не пропадает, как раньше. На нем будут отображаться все действия игры. Мы этого добились благодаря функции event.get()
. Также, при помощи функции display.set_caption()
, мы вывели заголовок нашего экрана — ‘Snake game by Pythonist’.
Теперь у нас есть экран для игры, но когда вы кликнете по кнопке close, экран не закроется. Это потому, что мы не предусмотрели такого поведения. Для решения этой задачи в Pygame предусмотрено событие «QIUT», которое мы используем слеудющим образом:
import pygame pygame.init() dis=pygame.display.set_mode((400,300)) pygame.display.update() pygame.display.set_caption('Snake game by Edureka') game_over=False while not game_over: for event in pygame.event.get(): if event.type==pygame.QUIT: game_over=True pygame.quit() quit()
Теперь, когда наш экран полностью подготовлен, нам предстоит нарисовать на нем змейку. Этому посвящен следующий раздел.
Кстати, есть полезная книга Impractical Python Projects, которую вы можете у нас скачать. В ней сборник проектов и примеров с модулем pygame.
Создание змейки
Перед тем как создать змейку, мы инициируем несколько цветовых переменных для раскрашивания самой змейки, еды и экрана. В Pygame используется цветовая схема RGB (RED, GREEN, BLUE). Установка всех цветов в 0
соответствует черному цвету, а в 255
— соответственно, белому.
Фактически, наша змейка является прямоугольником. Чтобы нарисовать прямоугольник в Pygame, можно воспользоваться функцией draw.rect()
, которая нарисует нам прямоугольник заданного цвета и размера.
import pygame pygame.init() dis=pygame.display.set_mode((400,300)) pygame.display.set_caption('Snake game by Pythonist') blue=(0,0,255) red=(255,0,0) game_over=False while not game_over: for event in pygame.event.get(): if event.type==pygame.QUIT: game_over=True pygame.draw.rect(dis,blue,[200,150,10,10]) pygame.display.update() pygame.quit() quit()
Результат:
Как можно увидеть, змейка создана в виде голубого прямоугольника. Теперь нам нужно научить ее двигаться.
Движение змейки
Чтобы передвигать змейку, мы будем использовать ключевые события из класса KEYDOWN
библиотеки Pygame. События K_UP
, K_DOWN
, K_LEFT
, и K_RIGHT
заставят змейку двигаться вверх, вниз, влево и вправо соответственно. Также, цвет дисплея меняется от черного (по умолчанию) до белого при помощи метода fill()
.
Для сохранения изменений координат x
и y
мы создали две новых переменные: x1_change
и y1_change
.
import pygame pygame.init() white = (255, 255, 255) black = (0, 0, 0) red = (255, 0, 0) dis = pygame.display.set_mode((800, 600)) pygame.display.set_caption('Snake game by Pythonist') game_over = False x1 = 300 y1 = 300 x1_change = 0 y1_change = 0 clock = pygame.time.Clock() while not game_over: for event in pygame.event.get(): if event.type == pygame.QUIT: game_over = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: x1_change = -10 y1_change = 0 elif event.key == pygame.K_RIGHT: x1_change = 10 y1_change = 0 elif event.key == pygame.K_UP: y1_change = -10 x1_change = 0 elif event.key == pygame.K_DOWN: y1_change = 10 x1_change = 0 x1 += x1_change y1 += y1_change dis.fill(white) pygame.draw.rect(dis, black, [x1, y1, 10, 10]) pygame.display.update() clock.tick(30) pygame.quit() quit()
Результат:
«Game over» при достижении змейкой границы
В игре змейка игрок проигрывает, если касается границы экрана. Чтобы задать такое поведение, мы должны использовать инструкцию if
, которая будет следить за тем, чтобы координаты x и y были меньше размеров экрана. Мы будем использовать для этого переменные, чтобы вы могли потом, при случае, легко внести какие-либо изменения в игру.
import pygame import time pygame.init() white = (255, 255, 255) black = (0, 0, 0) red = (255, 0, 0) dis_width = 800 dis_height = 600 dis = pygame.display.set_mode((dis_width, dis_width)) pygame.display.set_caption('Snake game by Pythonist') game_over = False x1 = dis_width/2 y1 = dis_height/2 snake_block=10 x1_change = 0 y1_change = 0 clock = pygame.time.Clock() snake_speed=30 font_style = pygame.font.SysFont(None, 50) def message(msg,color): mesg = font_style.render(msg, True, color) dis.blit(mesg, [dis_width/2, dis_height/2]) while not game_over: for event in pygame.event.get(): if event.type == pygame.QUIT: game_over = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: x1_change = -snake_block y1_change = 0 elif event.key == pygame.K_RIGHT: x1_change = snake_block y1_change = 0 elif event.key == pygame.K_UP: y1_change = -snake_block x1_change = 0 elif event.key == pygame.K_DOWN: y1_change = snake_block x1_change = 0 if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0: game_over = True x1 += x1_change y1 += y1_change dis.fill(white) pygame.draw.rect(dis, black, [x1, y1, snake_block, snake_block]) pygame.display.update() clock.tick(snake_speed) message("You lost",red) pygame.display.update() time.sleep(2) pygame.quit() quit()
Результат:
Добавление еды
Теперь мы добавим немного еды для змейки, и когда она будет ее пересекать, мы будем выводить сообщение «Yummy!!”. Помимо этого, мы внесем небольшие изменения, которые дадут возможность игроку прекращать игру, а также начинать ее заново в случае поражения.
import pygame import time import random pygame.init() white = (255, 255, 255) black = (0, 0, 0) red = (255, 0, 0) blue = (0, 0, 255) dis_width = 800 dis_height = 600 dis = pygame.display.set_mode((dis_width, dis_height)) pygame.display.set_caption('Snake Game by Edureka') clock = pygame.time.Clock() snake_block = 10 snake_speed = 30 font_style = pygame.font.SysFont(None, 30) def message(msg, color): mesg = font_style.render(msg, True, color) dis.blit(mesg, [dis_width/3, dis_height/3]) def gameLoop(): # creating a function game_over = False game_close = False x1 = dis_width / 2 y1 = dis_height / 2 x1_change = 0 y1_change = 0 foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0 foody = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0 while not game_over: while game_close == True: dis.fill(white) message("You Lost! Press Q-Quit or C-Play Again", red) 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: gameLoop() for event in pygame.event.get(): if event.type == pygame.QUIT: game_over = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: x1_change = -snake_block y1_change = 0 elif event.key == pygame.K_RIGHT: x1_change = snake_block y1_change = 0 elif event.key == pygame.K_UP: y1_change = -snake_block x1_change = 0 elif event.key == pygame.K_DOWN: y1_change = snake_block x1_change = 0 if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0: game_close = True x1 += x1_change y1 += y1_change dis.fill(white) pygame.draw.rect(dis, blue, [foodx, foody, snake_block, snake_block]) pygame.draw.rect(dis, black, [x1, y1, snake_block, snake_block]) pygame.display.update() if x1 == foodx and y1 == foody: print("Yummy!!") clock.tick(snake_speed) pygame.quit() quit() gameLoop()
Результат:
Terminal:
Увеличение длины змейки
Следующий код будет увеличивать длину змейки после поглощения ею еды. Также, если змейка сталкивается с собственным хвостом, игра заканчивается и выводится сообщение: “You Lost! Press Q-Quit or C-Play Again“. Длина змейки хранится в списке, а базовые значения заданы в следующем коде.
import pygame import time import random pygame.init() white = (255, 255, 255) yellow = (255, 255, 102) black = (0, 0, 0) red = (213, 50, 80) green = (0, 255, 0) blue = (50, 153, 213) dis_width = 600 dis_height = 400 dis = pygame.display.set_mode((dis_width, dis_height)) pygame.display.set_caption('Snake Game by Pythonist') clock = pygame.time.Clock() snake_block = 10 snake_speed = 15 font_style = pygame.font.SysFont("bahnschrift", 25) score_font = pygame.font.SysFont("comicsansms", 35) def our_snake(snake_block, snake_list): for x in snake_list: pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block]) def message(msg, color): mesg = font_style.render(msg, True, color) dis.blit(mesg, [dis_width / 6, dis_height / 3]) def gameLoop(): game_over = False game_close = False x1 = dis_width / 2 y1 = dis_height / 2 x1_change = 0 y1_change = 0 snake_List = [] Length_of_snake = 1 foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0 foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0 while not game_over: while game_close == True: dis.fill(blue) message("You Lost! Press C-Play Again or Q-Quit", red) 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: gameLoop() for event in pygame.event.get(): if event.type == pygame.QUIT: game_over = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: x1_change = -snake_block y1_change = 0 elif event.key == pygame.K_RIGHT: x1_change = snake_block y1_change = 0 elif event.key == pygame.K_UP: y1_change = -snake_block x1_change = 0 elif event.key == pygame.K_DOWN: y1_change = snake_block x1_change = 0 if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0: game_close = True x1 += x1_change y1 += y1_change dis.fill(blue) pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block]) snake_Head = [] snake_Head.append(x1) snake_Head.append(y1) snake_List.append(snake_Head) if len(snake_List) > Length_of_snake: del snake_List[0] for x in snake_List[:-1]: if x == snake_Head: game_close = True our_snake(snake_block, snake_List) pygame.display.update() if x1 == foodx and y1 == foody: foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0 foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0 Length_of_snake += 1 clock.tick(snake_speed) pygame.quit() quit() gameLoop()
Результат:
Вывод счета на экран
И последнее, но весьма важное дело: вам нужно отображать счет игрока. Для этого мы создали функцию Your_score
. Это функция будет показывать размер змейки за вычетом 1
(так как это начальный размер змейки).
import pygame import time import random pygame.init() white = (255, 255, 255) yellow = (255, 255, 102) black = (0, 0, 0) red = (213, 50, 80) green = (0, 255, 0) blue = (50, 153, 213) dis_width = 600 dis_height = 400 dis = pygame.display.set_mode((dis_width, dis_height)) pygame.display.set_caption('Snake Game by Pythonist') clock = pygame.time.Clock() snake_block = 10 snake_speed = 15 font_style = pygame.font.SysFont("bahnschrift", 25) score_font = pygame.font.SysFont("comicsansms", 35) def Your_score(score): value = score_font.render("Your Score: " + str(score), True, yellow) dis.blit(value, [0, 0]) def our_snake(snake_block, snake_list): for x in snake_list: pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block]) def message(msg, color): mesg = font_style.render(msg, True, color) dis.blit(mesg, [dis_width / 6, dis_height / 3]) def gameLoop(): game_over = False game_close = False x1 = dis_width / 2 y1 = dis_height / 2 x1_change = 0 y1_change = 0 snake_List = [] Length_of_snake = 1 foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0 foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0 while not game_over: while game_close == True: dis.fill(blue) message("You Lost! Press C-Play Again or Q-Quit", red) Your_score(Length_of_snake - 1) 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: gameLoop() for event in pygame.event.get(): if event.type == pygame.QUIT: game_over = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: x1_change = -snake_block y1_change = 0 elif event.key == pygame.K_RIGHT: x1_change = snake_block y1_change = 0 elif event.key == pygame.K_UP: y1_change = -snake_block x1_change = 0 elif event.key == pygame.K_DOWN: y1_change = snake_block x1_change = 0 if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0: game_close = True x1 += x1_change y1 += y1_change dis.fill(blue) pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block]) snake_Head = [] snake_Head.append(x1) snake_Head.append(y1) snake_List.append(snake_Head) if len(snake_List) > Length_of_snake: del snake_List[0] for x in snake_List[:-1]: if x == snake_Head: game_close = True our_snake(snake_block, snake_List) Your_score(Length_of_snake - 1) pygame.display.update() if x1 == foodx and y1 == foody: foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0 foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0 Length_of_snake += 1 clock.tick(snake_speed) pygame.quit() quit() gameLoop()
Результат:
Вот мы и дошли до конца нашей статьи. Мы надеемся, что она вам понравилась и все было понятно. Самое главное, не забывайте как можно больше практиковаться и использовать ваши знания на практике.