Как сделать змейку на python
Перейти к содержимому

Как сделать змейку на python

  • автор:

«Змейка» на Python

Snake (Питон, Удав, Змейка, Червяк и др.) — компьютерная игра, уходящая корнями в системы 1970-х.

Игрок управляет длинным, тонким существом, напоминающим змею, которое ползает по плоскости (как правило, ограниченной стенками), собирая еду (или другие предметы), избегая столкновения с собственным хвостом и краями игрового поля (существуют варианты где при прохождении через край змея выходит из противоположного края поля). Каждый раз, когда змея съедает кусок пищи, она становится длиннее, что постепенно усложняет игру.

Мои правила игры «Змейка»

  • Стартовой позицией является одна клетка («Голова»), которая находится в центральном положении.
  • В моей версии нельзя умереть (при столкновении стеной змейка выходит из противоположной стены, при столкновении с самим собой («самоедство») змейка возвращается к стартовой позиции, сохраняя координаты «Головы»).
  • При поедании «Яблока» добавляется новая клетка змеи.

Алгоритм «Оторванный ‘Хвост’ «

Порядок выполнения данного алгоритма:

  • Первое. Для начала определяется координаты для новой «Головы» (направление уже определено).
  • Второе. Выходит ли новая «Голова» за пределы карты? Если да, меняются координаты новой «Головы» на противоположные.
  • Третье. Сталкивается ли змейка с «Яблоком»? Если да, то меняется положение «Яблока». Иначе, хвост отрезается.
  • Четвертое. Съедает ли себя змейка? Если да, то змейка умирает и оставляет потомство (новая «Голова»)
  • Пятое. Добавляется новая «Голова»

Третье и Четвертое я объединил в единое условие.

#snake хранит двумерный массив, положение клеток змейки def severed_tail(snake, apple, direction, x_max, y_max): x_apple, y_apple = apple x_snake, y_snake = snake[0][0] + direction[0], snake[0][1] + direction[1] x_snake = 0 if x_snake > x_max else x_max if x_snake < 0 else x_snake y_snake = 0 if y_snake >y_max else y_max if y_snake < 0 else y_snake if x_snake == x_apple and y_snake == y_apple: set_new_coords_apple(apple) elif [x_snake, y_snake] in snake: snake = [] else: snake.pop() snake.insert(0, [x_snake, y_snake])

В этом алгоритме заключена основная логика игры "Змейка"

Код игры "Змейка"

#Вызов библиотек from tkinter import * from random import randint class Game: #Инициализация def __init__(self, canvas): self.canvas = canvas self.snake_coords = [[14, 14]] self.apple_coords = [randint(0, 29) for i in range(2)] self.vector = self.direction = self.vector["Right"] self.canvas.focus_set() self.canvas.bind("", self.set_direction) self.GAME() #Метод для нового положения "Яблока" def set_apple(self): self.apple_coords = [randint(0, 29) for i in range(2)] #Условие, для того чтобы яблоко не лежало на змейке if self.apple_coords in self.snake_coords: self.set_apple() #Установка нового направления змейки def set_direction(self, event): #Условие, которое проверяет нажатие кнопки if event.keysym in self.vector: self.direction = self.vector[event.keysym] #Отрисовка игры def draw(self): self.canvas.delete(ALL) x_apple, y_apple = self.apple_coords self.canvas.create_rectangle(x_apple*10, y_apple*10, (x_apple+1)*10, (y_apple+1)*10, fill="red", width=0) for x, y in self.snake_coords: self.canvas.create_rectangle(x*10, y*10, (x+1)*10, (y+1)*10, fill="green", width=0) #Метод, который возращает координаты на интервале [0, 29] @staticmethod def coord_check(coord): return 0 if coord > 29 else 29 if coord < 0 else coord #Алгоритм "Оторванный Хвост\Логика игры" def GAME(self): self.draw() x,y = self.snake_coords[0] x += self.direction[0]; y += self.direction[1] x = self.coord_check(x) y = self.coord_check(y) if x == self.apple_coords[0] and y == self.apple_coords[1]: self.set_apple() elif [x, y] in self.snake_coords: self.snake_coords = [] else: self.snake_coords.pop() self.snake_coords.insert(0, [x,y]) self.canvas.after(100, self.GAME) #Каркас игры root = Tk() canvas = Canvas(root, width=300, height=300, bg="black") canvas.pack() game = Game(canvas) root.mainloop()

Змейка на Python

Я точно знаю, что в детстве вы все играли в игру «Змейка» и, конечно, всегда хотели выиграть. Будучи детьми, мы все любили искать баги в игре, чтобы никогда не видеть сообщение Game over, но сейчас, будучи технарями, нам наверняка хочется сделать игру так, чтобы комар носа не подточил. Именно об этом и пойдет речь в нашей статье.

Перед тем как двигаться дальше, давайте посмотрим на основные разделы нашей статьи:

  1. Установка Pygame.
  2. Создание экрана.
  3. Создание змейки.
  4. Движение змейки.
  5. «Game over» при достижении змейкой границы.
  6. Добавление еды.
  7. Увеличение длины змейки.
  8. Вывод счета на экран.

Установка Pygame

Первое, что нам надо сделать, это установить библиотеку Pygame. Это можно сделать, просто выполнив следующую команду:

pip install 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()

Результат:

Змейка Python шаг 2

Вот мы и дошли до конца нашей статьи. Мы надеемся, что она вам понравилась и все было понятно. Самое главное, не забывайте как можно больше практиковаться и использовать ваши знания на практике.

Как создать простую игру «Змейка» на Python и Pygame

Как создать простую игру «Змейка» на Python и Pygame

Игра «Змейка» существует уже почти 50 лет. За это время программисты успели разработать множество модификаций для разных платформ. В этой статье подробно разбираем процесс создания игры на Python с помощью библиотеки Pygame.

История

Прообраз классической «Змейки» появился в 1976 году в виде игры Blockade для аркадных автоматов. В нее могли играть сразу два пользователя, каждому из которых надо было передвигать по игровому полю длинную фигуру, похожую на змею. Фигура отставляла за собой шлейф, в который другому игроку нельзя было врезаться. Если все же врезаться, то игра начиналась снова, а проигрывал тот, кто первым совершит шесть столкновений с противником.

Интерфейс игры Blockade-змейка в 1976

После этого разработчики начали выпускать свои версии «Змеек» и сформировали отдельный жанр игр, в котором змея передвигается по полю и собирает объекты. За более чем 50 лет на свет вышли «Змейки» с разными правилами и режимами игры. В одних версиях направление змеи меняется каждый раз, когда она собирает объект, в других игроку приходится управлять сразу двумя змейками и следить, чтобы они не соприкасались друг с другом.

Python-разработчик
Освойте Python, самый популярный язык программирования
4 030 ₽/мес 6 717 ₽/мес

dffsdd (3)

Инструменты

Разрабатывать игру будем на Python с помощью открытого набора модулей Pygame, который построен на мультимедийной библиотеке Simple DirectMedia Layer (SDL). Pygame содержит в себе все необходимые модули для разработки игр на Python, включая работу с графикой, воспроизведение звука, управление с клавиатуры, взаимодействие с вибрацией и акселерометром. Готовые игры можно собирать под разные платформы, включая мобильный Android. Код Pygame открыт и опубликован на GitHub, поэтому более опытные разработчики могут присоединиться к развитию проекта. Из дополнительных инструментов понадобится редактор кода на Python. Чаще всего разработчики выбирают бесплатный редактор Visual Studio Code от Microsoft или полноценную среду разработки Pycharm от JetBrains. Visual Studio Code — полностью бесплатный редактор кода, доступный для Windows, macOS и Linux. Специальную версию VS Code можно запускать в браузере. Вначале компания позиционировала редактор в качестве инструмента для веб-разработки. После релиза магазина расширений появилась возможность адаптировать VS Code практически под любые современные технологии. Редактор поддерживает подсветку синтаксиса, запуск кода и отладку. Скачать установочный файл можно на официальном сайте проекта. PyCharm — полноценная среда разработки на языке Python. Включает в себя все необходимые инструменты для создания, отладки и тестирования приложений. Возможности среды можно расширять плагинами. Если с помощью VS Code можно писать код на нескольких языках, то в PyCharm есть полноценная поддержка только Python, а для других языков JetBrains выпускает отдельные среды. PyCharm доступна на Windows, macOS и Linux. Пользователи могут выбрать между бесплатным и ограниченным выпуском Community Edition или полноценным Professional с ежемесячной подпиской. Для проекта «Змейки» хватит бесплатной версии.

Установка библиотек

Установка Python 3

Сперва надо убедиться, что на компьютере установлен язык программирования Python 3. Для этого в терминале следует ввести команду python3 —version. В случае успеха система выведет номер установленной версии. Если в терминале появится ошибка или сообщение о том, что команда python3 не найдена, то Python надо будет установить. Для macOS и Linux это можно сделать с помощью одной команды в том же окне терминала.

macOS

На macOS установить Python можно из репозитория Homebrew. Сам Homebrew можно установить по инструкции с официального сайта. После этого в терминале следует ввести команду brew install python3 и дождаться завершения операции. В конце можно еще раз ввести python3 —version и убедиться, что установка прошла успешно.

Linux

В Linux установка Python производится с помощью команды sudo apt install python3. Этого хватит для автоматического скачивания актуальной версии.

Windows

В Windows язык программирования Python доступен в фирменном магазине приложений Microsoft Store. Для установки надо перейти по ссылке на страницу пакета и нажать кнопку «Получить», а затем — «Установить». Для корректной работы следует перезагрузить компьютер. Библиотека Pygame устанавливается из репозитория PyPI с помощью пакетного менеджера Pip. Он загружается вместе с Python, поэтому для установки Pygame достаточно выполнить в терминале команду pip install pygame. Если Python и Pygame уже установлены, то следует скачать редактор кода. Можно выбрать любой удобный из предложенных выше, перейти на его официальный сайт и пройти процесс установки.

Станьте разработчиком на Python и решайте самые разные задачи: от написания кода до автоматизации процессов

Дизайн

Цвета для дизайна «Змейки»

В больших студиях над играми работает множество отделов: сценаристы, режиссеры, дизайнеры, программисты, художники, тестировщики и другие высококвалифицированные специалисты. Мы разрабатываем проект в одиночку, поэтому задачи целой студии ложатся на наши плечи. Перед тем как начинать писать код, надо определиться с дизайном нашей «Змейки». Сейчас есть огромное количество вариантов этой классической игры, но мы повторим тот, который был популярен на заре зарождения жанра. Экраны тогда были монохромными, и разработчики не могли использовать обилие цветов. Мы тоже возьмем ограниченную палитру в зеленых оттенках, которая хорошо знакома по игровой консоли Game Boy от Nintendo. Всего в проекте будем использовать четыре цвета. Их коды в форматах RGB и Hex указаны на изображении.

Правила

  • игрок управляет змеей, которая собирает объекты на поле;
  • повороты змеи возможны на 90 градусов;
  • при каждом запуске змейка появляется в случайном месте игрового поля;
  • каждый собранный объект увеличивает длину змейки на один блок;
  • столкновение змеи со своим телом или границей игрового поля приводит к проигрышу;
  • игроку надо как можно дольше продержаться и собрать как можно больше объектов.

Управление реализуем с помощью клавиш WASD. Такая схема управления уже успела стать стандартом в разработке игр, поэтому пользователям не надо будет привыкать к специфическим кнопкам.

Разработка

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

Шаг 1 — создаем новый проект и импортируем библиотеки

Для начал необходимо создать новый проект в редакторе кода. Будем рассматривать все на примере PyCharm, но все операции в таком же порядке можно проделать и в VS Code.

Для начала запускаем среду разработки и выбираем пункт меню File → New Project. В открывшемся меню указываем имя проекта и задаем директорию хранения файлов. В нашем случае проект называется snake, а все файлы хранятся в стандартной папке. Остальные пункты меню можно оставить по умолчанию.

Создание проекта игры в Python

В созданном проекте переходим к файлу main.py: если в проекте его нет, то создаем. В самом начале файла импортируем все необходимые для работы библиотеки:

  • Pygame — для доступа к основным модулям Pygame;
  • Randrange — для выбора случайного числа из заданного диапазона.
# Импортируем библиотеки import pygame as pg from random import randrange

Шаг 2 — задаем константы и инициализируем объекты

Некоторые переменные будут постоянными во всем проекте — константами. К ним будут относиться размер окна в пикселях и частота кадров (frame per second, FPS). Зададим их сразу после импорта библиотек. Важно отметить, что среди разработчиков Python константы принято писать заглавными буквами, а если в названии содержится больше одного слова, то отделять их следует символом нижнего подчеркивания. К примеру, некоторые названия констант могут выглядеть как HEIGHT или MAIN_COLOR .

В проекте «Змейки» на Python будут следующие константы:

  • WINDOW — размер окна, равный 1000 пикселей;
  • FPS — частота кадров, равная 60 кадрам в секунду.
# Константы WINDOW = 1000 FPS = 60

Теперь можно проинициализировать объекты игры. Сперва создадим объект экрана с помощью вызова функции set_mode модуля display . Функция set_mode принимает три аргумента: размер окна, флаги дополнительных параметров и глубину цвета. Последние два аргумента можно опустить и задать позже. В нашем случае создадим окно размером 1000×1000 пикселей. У нас уже есть константа размера окна, поэтому просто умножим ее на два: [WINDOW] * 2 . Также сразу же инициализируем объект, который поможет нам задать частоту обновления экрана.

# Инициализация объектов gameScreen = pg.display.set_mode([WINDOW] * 2) clock = pg.time.Clock()

Шаг 3 — создаем окно игры

Мы сделали все необходимое для того, чтобы нарисовать на экране компьютера окно нашей «Змейки». Перед этим важно отметить, что игры на Pygame работают в рамках бесконечного цикла, который существует до тех пор, пока пользователь его не закроет. В этом цикле находятся уже другие циклы и условия, предназначенные для реализации управления, обновления экрана и отрисовки объектов.

Создадим такой цикл while True , сразу же в нем установим ограничение частоты кадров, использовав константу FPS :

# Главный цикл игры while True: # Частота обновления экрана clock.tick(FPS)

Теперь мы хотим получать события и обрабатывать их. Создадим для этого цикл for . В нем будем отслеживать действия пользователя и реагировать на них. Сразу же пропишем обнаружение закрытия окна с помощью условия if event.type == pg.QUIT — если объект Pygame закрывается, то мы закрываем игровое окно.

После этого воспользуемся функцией fill() и закрасим ранее созданный экран самым светлым цветом из палитры. Это позволит поверх разместить более темную змейку и объекты, которые она будет собирать. Цвет укажем в RGB-формате. В конце добавим функцию обновления экрана flip() .

# Цикл обработки событий for event in pg.event.get(): if event.type == pg.QUIT: exit() gameScreen.fill((155, 188, 15)) pg.display.flip()

Окно создано, для него установлен цвет, и выставлены параметры обновления экрана. Теперь можно запустить код. После запуска на экране появится наше окно. Его можно закрыть с помощью нажатия на крестик или горячих клавиш операционной системы.

Окно для игры «Змейка» на Python

Шаг 4 — создаем змейку

Наша змейка должна как-то передвигаться по игровому полю, для этого ей понадобятся координаты. В коде уже есть константа WINDOW S, обозначающая размер одной стороны окна; значит теперь мы сможем задать константу TILE_SIZE для размера стороны одной плитки сетки и после задать сразу всю сетку. Далее с помощью кортежа поместим в константу RANGE разметку всего поля. Так мы сможем задавать змейке координаты для передвижения и спауна объектов.

Координаты и размеры шага для игры «Змейка» на Python

TILE_SIZE = 50 RANGE = (TILE_SIZE // 2, WINDOW - TILE_SIZE // 2, TILE_SIZE)

Теперь создадим функцию, которая определяет координаты случайной плитки на игровом поле. Вспомним из школы, что координаты на плоскости задаются с помощью двух значений — по оси X и Y. Поэтому наша функция должна находить два таких значения, основываясь на данных о разметке поля.

Обозначим лямбда-функцию get_random_position() и с помощью константы RANGE получим координаты X и Y. Префиксная запись символа звездочки (*) перед RANGE означает, что мы хотим передать в функцию randrange() все элементы кортежа. Мы не знаем, сколько их там хранится, можем заранее посчитать и сохранить количество в отдельную переменную, а можем просто воспользоваться префиксной записью перед константой и доверить это дело Python.

# Функция для определения координат (X:Y) случайной позиции на игровом поле get_random_position = lambda: [randrange(*RANGE), randrange(*RANGE)]

Убедимся, что get_random_position() каждый раз дает нам случайные координаты. Вызовем функцию и посмотрим на вывод:

> [825, 175] > [925, 925] > [725, 825] > [25, 175] > [325, 625]

Теперь у нас есть все необходимое для того, чтобы задать параметры змейки и нарисовать ее на экране. Для начала создадим переменную snake, в которой определим голову змеи с помощью экземпляра класса Rect() , который в Pygame отвечает за обозначение прямоугольных областей. В качестве параметров в конструктор класса следует передать координаты X и Y, высоту и ширину. Сразу после зададим случайную позицию головы змеи на сетке игрового поля с помощью функции get_random_position() .

Теперь нам надо создать переменные для хранения длины змеи и всех ее сегментов. Для этого создадим переменную length со значением 1 и список segments , в который поместим первый сегмент.

# Параметры змейки snake = pg.rect.Rect([0, 0, TILE_SIZE - 2, TILE_SIZE - 2]) snake.center = get_random_position() length = 1 segments = [snake.copy()]

Перейдем в цикл обработки событий и отобразим змейку на экране. В качестве цвета возьмем второй зеленый оттенок из определенной ранее палитры. Зададим его в RGB-формате.

[pg.draw.rect(gameScreen, (120, 149, 12), segment) for segment in segments]

Теперь при каждом запуске кода на игровом поле будет появляться голова змейки. Также можно заметить, что каждый раз змейка появляется в случайном месте.

Варианты появления змейки в случайном месте на игровом поле

Шаг 5 — управляем змейкой

Для управления змейкой реализуем классическую для игр схему WASD. Такая раскладка для перемещения персонажем успела стать стандартной, поэтому пользователю будет привычно играть в нашу «Змейку». Клавиши WASD обозначают:

  • W — движение вперед;
  • A — движение влево;
  • S — движение назад;
  • D — движение вправо.

Для начала перейдем к части кода, в которой до этого задавали параметры змейки, и добавим новую переменную snake_dir . В ней будем хранить координаты головы змеи. Зададим значение (0, 0).

Теперь необходимо описать в коде обработку нажатий клавиш. Для этого в разделе цикла обработки событий пропишем изменение значения переменной snake_dir при нажатии:

# Обработка нажатий WASD if event.type == pg.KEYDOWN: if event.key == pg.K_w: snake_dir = (0, -TILE_SIZE) if event.key == pg.K_s: snake_dir = (0, TILE_SIZE) if event.key == pg.K_a: snake_dir = (-TILE_SIZE, 0) if event.key == pg.K_d: snake_dir = (TILE_SIZE, 0)

В коде игры уже есть обработка нажатий клавиш, поэтому можно реализовать логику управления. На каждом шаге змейки мы будем перемещать ее на один сегмент игрового поля и убирать из списка сегментов лишний:

# Управляем змейкой snake.move_ip(snake_dir) segments.append(snake.copy()) segments = segments[-length:]

Сейчас можно запустить код и попробовать поуправлять змейкой. Важно отметить, что в Pygame есть неприятная особенность. Если задать в коде управление на латинской раскладке, то библиотека будет обрабатывать только нажатие латинских клавиш. Поэтому необходимо переключить язык на английский. Исправить это можно с помощью добавления кода для обработки клавиш в Unicode, но в этом проекте мы просто будем следить за раскладкой.

Также можно заметить, что змейка передвигается по игровому полю слишком быстро. Исправим это, добавив код для контроля скорости. Сперва перейдем в раздел параметров переменной и создадим переменные времени и задержки между шагами змейки:

time = 0 time_step = 110

После этого модифицируем часть кода с управлением:

# Управляем змейкой time_now = pg.time.get_ticks() if time_now - time > time_step: time = time_now snake.move_ip(snake_dir) segments.append(snake.copy()) segments = segments[-length:]

Шаг 6 — добавляем еду для змейки

У нас уже есть змейка, и мы даже можем ей управлять. Теперь на игровом поле должны появляться объекты еды, которые змейка будет собирать и увеличиваться. Сам объект еды идентичен по размерам с головой змеи и также появляется в случайном месте экрана. Поэтому создадим переменную food с копией головы змеи и назначим ей случайную точку для появления с помощью функции get_random_position() :

# Параметры объектов еды food = snake.copy() food.center = get_random_position()

Отобразим еду на экране так же, как это делали со змеей. В качестве цвета возьмем самый темный из обозначенной палитры:

# Рисуем объект еды pg.draw.rect(gameScreen, (15, 56, 15), food)

При запуске кода хорошо видно, что голова змеи и еда всегда появляются в случайных местах на игровом поле:

Варианты появления еды для змейки на игровом поле

Теперь научим змейку есть еду. Для этого создадим условие, в котором будем проверять положение головы змеи и объекта еды. Если они совпадают, то будем задавать новое случайное положение для еды и увеличивать длину на единицу:

# Поедание if snake.center == food.center: food.center = get_random_position() length += 1

Шаг 7 — определяем столкновения

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

Для этого мы должны проверять положение координат головы змеи с размерами окна. Если змейка соприкасается с границами, то устанавливаем новые случайные позиции для головы и еды, уменьшаем размер змеи на исходный и обнуляем координаты передвижения:

# Столкновение с границами if snake.left < 0 or snake.right >WINDOW or snake.top < 0 or snake.bottom >WINDOW: snake.center, food.center = get_random_position(), get_random_position() length, snake_dir = 1, (0, 0) segments = [snake.copy()]

Также змейка может столкнуться со своим телом. В этом случае игра тоже должна завершиться. Для этого создадим переменную snake_collision, в которой будем определять, пересекается ли хоть один прямоугольник тела змеи с ее головой. Воспользуемся готовой функцией collidelist() класса Rect из Pygame. А после добавим переменную в условие проверки столкновения с границами:

# Столкновение с границами и телом змейки snake_collision = pg.Rect.collidelist(snake, segments[:-1]) != -1 if snake.left < 0 or snake.right >WINDOW or snake.top < 0 or snake.bottom >WINDOW or snake_collision: snake.center, food.center = get_random_position(), get_random_position() length, snake_dir = 1, (0, 0) segments = [snake.copy()]

В итоге у нас получилась классическая игра «Змейка» на Python и Pygame. Мы научились рисовать объекты на экране, менять их параметры, управлять ими с помощью клавиатуры и обрабатывать события в игровом цикле.

Весь код игры с комментариями занимает всего 78 строк:

# Импортируем библиотеки import pygame as pg from random import randrange # Константы WINDOW = 1000 FPS = 60 TILE_SIZE = 50 RANGE = (TILE_SIZE // 2, WINDOW - TILE_SIZE // 2, TILE_SIZE) # Функция для определения координат (X:Y) случайной позиции на игровом поле get_random_position = lambda: [randrange(*RANGE), randrange(*RANGE)] # Параметры змейки snake = pg.rect.Rect([0, 0, TILE_SIZE - 2, TILE_SIZE - 2]) snake.center = get_random_position() length = 1 segments = [snake.copy()] snake_dir = (0, 0) # Параметры времени и задержки time = 0 time_step = 110 # Параметры объектов еды food = snake.copy() food.center = get_random_position() # Инициализация объектов gameScreen = pg.display.set_mode([WINDOW] * 2) clock = pg.time.Clock() # Главный цикл игры while True: # Частота обновления экрана clock.tick(FPS) # Цикл обработки событий for event in pg.event.get(): if event.type == pg.QUIT: exit() # Обработка нажатий WASD if event.type == pg.KEYDOWN: if event.key == pg.K_w: snake_dir = (0, -TILE_SIZE) if event.key == pg.K_s: snake_dir = (0, TILE_SIZE) if event.key == pg.K_a: snake_dir = (-TILE_SIZE, 0) if event.key == pg.K_d: snake_dir = (TILE_SIZE, 0) gameScreen.fill((155, 188, 15)) # Столкновение с границами и телом змейки snake_collision = pg.Rect.collidelist(snake, segments[:-1]) != -1 if snake.left < 0 or snake.right >WINDOW or snake.top < 0 or snake.bottom >WINDOW or snake_collision: snake.center, food.center = get_random_position(), get_random_position() length, snake_dir = 1, (0, 0) segments = [snake.copy()] # Поедание if snake.center == food.center: food.center = get_random_position() length += 1 # Рисуем объект еды pg.draw.rect(gameScreen, (15, 56, 15), food) # Рисуем змейку [pg.draw.rect(gameScreen, (120, 149, 12), segment) for segment in segments] # Управляем змейкой time_now = pg.time.get_ticks() if time_now - time > time_step: time = time_now snake.move_ip(snake_dir) segments.append(snake.copy()) segments = segments[-length:] pg.display.flip()

Что дальше

Игру «Змейка» на Python можно продолжать улучшать и модифицировать. К примеру, в проект можно добавить следующее:

  • В игре не хватает главного меню, меню проигрыша и отображения счета. Все это можно добавить с помощью модуля pygame.font , предназначенного для работы с текстом и шрифтами. Содержимое переменной length , в которой храним длину змейки, можно выводить в углу игрового поля и обнулять при проигрыше.
  • Наша «Змейка» получилась безмолвной, и ее надо оживить звуками. Сделать это можно с помощью модуля pygame.mixer , добавив фоновую музыку, звуковые эффекты при поворотах, поедании объектов и столкновении. Так игра будет более живой и увлекательной.
  • В старых играх, а особенно в аркадных автоматах, была возможность сохранять лучшие результаты, чтобы всегда можно было понять, кого из игроков можно считать абсолютным чемпионом. В нашу «Змейку» тоже можно добавить таблицу рекордов. Для этого надо разобраться с принципами хранения данных и сортировки. К примеру, в меню можно добавить отдельное всплывающее окно с пятью лучшими результатами и имена игроков.
  • Обычная змейка довольно быстро надоедает, поэтому можно добавить несколько новых режимов. К примеру, змейка может менять направление движения каждый раз, когда съедает блок еды. А еще ей можно увеличивать скорость или добавить жизни, дающие право на ошибку.
  • Одному играть тоже скучно, поэтому можно сделать игровое поле больше и добавить на него сразу двух змеек. Управление первой настроить на клавиши WASD, а второй — на стрелки. Тогда за одним компьютером в игру смогут играть сразу два пользователя. Только важно сделать змеек разных цветов, иначе игроки будут путаться.

Python-разработчик

Освойте Python с нуля. Подготовим к трудоустройству: дадим много практики, реальные проекты для портфолио, поможем с резюме. Лучшие студенты пройдут стажировки в проектах компаний-партнеров.

Создаём «Змейку» — первую игру на Python и Pygame

Учимся программировать через разработку игр. Сегодня напишем знакомую всем «Змейку» — вспомним правила игры и реализуем их на Python.

Иллюстрация: Оля Ежак для Skillbox Media

Антон Яценко

Антон Яценко
Изучает Python, его библиотеки и занимается анализом данных. Любит путешествовать в горах.

Pygame — популярная библиотека для создания игр под различные устройства на Windows, macOS, Linux или Android. Она помогает разработчику не только описать геймплей, но и работать с клавиатурой, мышью, акселерометром, звуком и видео.

Первая версия Pygame была представлена Питом Шиннерсом в октябре 2000 года. За 22 года вокруг библиотеки сложилось большое комьюнити, а о работе с ней написано несколько десятков книг. Последняя стабильная версия на июль 2022 года — 2.1.2.

Давайте разберёмся в том, как устроена Pygame, и напишем свою первую игру — классическую «Змейку» на Python, которую студенты часто берут для курсовой работы по программированию.

Устанавливаем Pygame и разбираемся

Pygame — не самостоятельная библиотека. На самом деле это обёртка для библиотеки SDL, Simple DirectMedia Layer. Именно SDL позволяет задействовать любые внешние устройства — например, мышь или клавиатуру. А Pygame делает работу с ними удобной для Python-разработчика.

Установить Pygame просто. Для этого воспользуемся терминалом или командной строкой и командой pip:

Теперь игровое окно не закрывается само по себе. Однако и закрыть его мы тоже не сможем — если нажать на кнопку «Выход», ничего не произойдёт. Исправляем это с помощью кода: добавляем событие QUIT, закрывающее окно.

Всё получилось. Ближе к центру экрана появился синий квадрат, который и будет нашей змейкой.

Шаг 3

Описываем движения змейки

Управлять перемещением змейки можно с помощью специального класса Pygame KEYDOWN. Класс позволяет использовать четыре стандартных события, получая их с клавиавтуры: K_UP, K_DOWN, K_LEFT и K_RIGHT — они соответствуют движениям змейки вверх, вниз, влево и вправо. Срабатывание любого события из класса KEYDOWN приводит к изменению положения змейки. Зададим шаг этого движения в 10 пикселей.

Кроме того, мы должны создать две переменные для хранения значений координат первой клетки нашей змейки по осям x и y. Назовём их x1_change и y1_change.

Шаг 4

Учитываем препятствия — границы игрового поля

Если змейка попадает на границу экрана, то игрок терпит поражение, а игра заканчивается. Чтобы закодить это правило, можно воспользоваться оператором if, который определяет координаты x и y для змейки и анализирует, выходят ли они за границы игрового поля. Добавим необходимый код.

Шаг 5

Добавляем еду для змейки

Теперь добавим «еду». Используем библиотеку random, чтобы она появлялась в случайном месте на игровом поле. Когда наша змейка будет проходить через еду, то её длина будет увеличиваться. Это мы добавим на следующем шаге. Кроме того, дадим возможность игроку выйти из игры или начать игру заново после проигрыша.

А если выполнить условие для завершения игры, то появится сообщение с предложением выйти из игры или начать её заново:

Шаг 6

Увеличиваем длину змейки

Дополним наш код, чтобы длина змейки увеличивалась при поглощении еды. Для этого нам понадобится список, в котором будет храниться текущая длина змейки. Учтём ещё важный момент из правил: при столкновении головы змейки с её телом игра завершается.

Шаг 7

Добавляем отображение счёта

Добавим отображение счёта текущей игры. Для этого создадим функцию Your_score. Она будет отображать длину змейки, вычитая из неё 1 (ведь 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 = 800 dis_height = 600 dis = pygame.display.set_mode((dis_width, dis_height)) pygame.display.set_caption('Змейка от Skillbox') 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("Ваш счёт: " + 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("Вы проиграли! Нажмите Q для выхода или C для повторной игры", 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()

Что дальше?

Узнать об особенностях работы с Pygame и возможностях библиотеки можно в официальной документации. Углубиться в разработку и попробовать другие игры можно благодаря специализированным книгам:

  • «Учим Python, делая крутые игры» Эла Свейгарта;
  • «Beginning Game Development with Python and Pygame: From Novice to Professional» Уилла Макгугана;
  • «Program Arcade Games: With Python and Pygame» Пола Винсента Крэйвена.

Больше интересного про код в нашем телеграм-канале. Подписывайтесь!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *