Как написать змейку на пайтоне

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

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

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

Установка 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() 

Результат:

Змейка Python шаг 1

Вывод счета на экран

И последнее, но весьма важное дело: вам нужно отображать счет игрока. Для этого мы создали функцию 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

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

#статьи

  • 15 июл 2022

  • 0

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

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

Антон Яценко

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

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

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

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

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

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

pip install pygame

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

Библиотека Pygame состоит из конструкций на языке Python и включает в себя несколько модулей. Модули позволяют получить доступ к определённому устройству и содержат методы для работы с ним. Например, модуль display позволяет работать с экраном, а joystick — считывать движения с джойстика.

После того как вы импортировали Pygame, необходимо инициировать библиотеку с помощью команды pygame.int(). Это поможет нам использовать любые методы любых функций, включённых в библиотеку модулей. Без инициализации код может потерять кросс-платформенность и не запускаться в другой системе.

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

В Pygame вся информация выводится на игровое поле, которому в коде соответствует класс display. Игровое поле может быть полноэкранным или занимать часть экрана. Display создаётся с помощью функции .set_mode(), которая возвращает Surface, представляющий видимую часть окна. Именно эту область вы будете передавать в функции рисования, такие как pygame.draw.circle(), а содержимое этого Surface будет выводиться на дисплей при вызове pygame.display.flip(). Звучит сложно, но на практике будет проще. Оба класса мы будем использовать при создании «Змейки».

Работать с изображениями в Pygame можно двумя способами: создавать их с нуля на экране или использовать изображения с диска. И тот и другой тип можно перезаписывать, загружать и сохранять в различных форматах — например, в PNG и JPG.

Изображения — не самостоятельные компоненты: они загружаются в объекты Surface, которые можно изменять и выводить на дисплеи различными способами.

Выше мы писали, что объекты Surface представлены прямоугольниками, подобно многим другим объектам в Pygame, в том числе изображениям и окнам. Прямоугольники используются настолько активно, что существует даже специальный класс Rect, предназначенный для работы только с ними. Объекты Rect используются для различных задач: создания фигур игрока и врагов, управления взаимодействиями между ними и так далее.

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

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

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


Запускаем Python

Писать код на Python лучше всего в специальном редакторе. Есть несколько вариантов:

  • Воспользоваться специализированными IDE: IntelliJ IDEA или Visual Studio Code. Мы рекомендуем именно этот способ — например, весь код для этой статьи мы писали в Visual Studio Code.
  • Использовать терминал на macOS или Linux или воспользоваться командной строкой в Windows. Для этого предварительно потребуется установить Python в систему. Мы подробно писали об этом в отдельном материале.

После установки и запуска Python загружаем библиотеку Pygame:

pip install pygame

Теперь у нас всё готово к работе над игрой. Для дальнейшего написания кода необходимо создать один пустой Python-файл.


Создаём игровое поле

Чтобы создать окно с игрой с помощью Pygame, необходимо использовать функцию display.set_mode() и передать в неё желаемый размер окна в пикселях. Также необходимо использовать методы init() и quit() для инициализации библиотеки в начале кода и её деинициализации в конце кода.

Метод update() используется для обновления содержимого экрана. Существует ещё метод flip(), который работает аналогично update(). Разница в том, что метод update() обновляет только внесённые изменения, а метод flip() перерисовывает экран целиком. Но если в метод update() не передавать никакие параметры, то также обновится весь экран.

import pygame
 
pygame.init()
dis=pygame.display.set_mode((500,400))  #Задаём размер игрового поля.
 
pygame.display.update()
 
pygame.quit()
quit()

Если сейчас запустить этот код, то экран игры сразу же закроется. Это связано с тем, что код сразу переходит к следующей строчке pygame.quit(), отключающей библиотеку и наше игровое поле. Чтобы избежать этого, необходимо воспользоваться циклом while — он не позволит игровому экрану закрыться:

import pygame
 
pygame.init()
 
dis=pygame.display.set_mode((500,400))
pygame.display.update()
pygame.display.set_caption('Змейка от Skillbox') #Добавляем название игры.
 
game_over=False #Создаём переменную, которая поможет нам контролировать 
статус игры — завершена она или нет. Изначально присваиваем значение False,
 то есть игра продолжается.
 
while not game_over:
   for event in pygame.event.get():
       print(event)  #Выводить в терминал все произошедшие события.
 
pygame.quit()
quit()

Кроме этого, мы добавили в код ещё две сущности: название игры и функцию для отслеживания игровых событий. Чтобы у окна с игрой появилось название, мы используем pygame.display.set_caption(») (название пишем в кавычках). А функция event.get() возвращает в терминал все события, которые происходят с игрой.

Запустим код и посмотрим, что получилось:

Скриншот: Pygame / Skillbox Media

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

import pygame
 
pygame.init()
 
dis=pygame.display.set_mode((500, 400))
pygame.display.update()
pygame.display.set_caption('Змейка от Skillbox')
 
game_over=False
while not game_over:
   for event in pygame.event.get():
       if event.type==pygame.QUIT:
           game_over=True
 
pygame.quit()
quit()

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


Создаём змейку

Для начала инициализируем переменные, которые задают цвет. Мы будем использовать их, чтобы присвоить цвет экрану, самой змейке и еде. В Pygame используется стандартная RGB-схема, то есть любой цвет представляет собой комбинацию красного, зелёного и синего цветов, интенсивность которых мы можем менять.

Наша змейка — прямоугольник, поэтому мы воспользуемся функцией создания прямоугольников draw.rect(). Она позволяет задать размер и цвет прямоугольника.

import pygame
 
pygame.init()
 
dis=pygame.display.set_mode((500, 400))
pygame.display.update()
pygame.display.set_caption('Змейка от Skillbox')
 
game_over=False
while not game_over:
   for event in pygame.event.get():
       if event.type==pygame.QUIT:
           game_over=True
 
pygame.quit()
quit()

Запустим код и посмотрим на результат.

Скриншот: Pygame / Skillbox Media

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


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

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

Кроме того, мы должны создать две переменные для хранения значений координат первой клетки нашей змейки по осям 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('Змейка от Skillbox')
 
game_over = False
x1 = 300 #Указываем начальное значение положения змейки по оси х.
y1 = 300 #Указываем начальное значение положения змейки по оси y.
x1_change = 0 #Создаём переменную, которой в цикле while будут
присваиваться значения изменения положения змейки по оси х.
y1_change = 0 #создаём переменную, которой в цикле while будут
присваиваться значения изменения положения змейки по оси y.
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 #Указываем шаг изменения положения змейки
в 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 #Записываем новое значение положения змейки по оси y.
   dis.fill(white)
   
   pygame.draw.rect(dis, black, [x1, y1, 10, 10])
   pygame.display.update()
   clock.tick(30)
 
pygame.quit()
quit()

Теперь змейка двигается по игровому полю:

Скриншот: Pygame / Skillbox Media

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

Если змейка попадает на границу экрана, то игрок терпит поражение, а игра заканчивается. Чтобы закодить это правило, можно воспользоваться оператором 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('Змейка от Skillbox')
 
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=15 #Ограничим скорость движения змейки.
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("Вы проиграли :(",red) #Сообщение, которое появляется при
проигрыше. В нашем случае — при выходе змейки за пределы игрового поля.
 
pygame.display.update()
time.sleep(2)
pygame.quit()
 
quit()

Теперь, если змейка достигнет края экрана, игра закончится, а на дисплее появится сообщение о проигрыше:

Скриншот: Pygame / Skillbox Media

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

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

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('Змейка от Skillbox')
clock = pygame.time.Clock()
snake_block = 10
snake_speed = 15
font_style = pygame.font.SysFont(None, 30)
 
def message(msg, color):
   mesg = font_style.render(msg, True, color)
   dis.blit(mesg, [dis_width/10, 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
   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 
#Создаём переменную, которая будет указывать расположение еды по оси y.
   while not game_over:
       while game_close == True:
           dis.fill(white)
           message("Вы проиграли! Нажмите Q для выхода 
или C для повторной игры", 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()
   
   pygame.quit()
   quit()
 
gameLoop()

Теперь при запуске игры кроме самой змейки будет показана еда. В нашем случае — в виде чёрного квадрата.

Скриншот: Pygame / Skillbox Media

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

Скриншот: Pygame / Skillbox Media

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

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

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 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)
           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) #Добавляем значения в список при 
изменении по оси y.
       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()

Дополнительно мы изменили цвет игрового поля и змейки, увеличив их контрастность.

Скриншот: Pygame / Skillbox Media

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

Добавим отображение счёта текущей игры. Для этого создадим функцию Your_score. Она будет отображать длину змейки, вычитая из неё 1 (ведь 1 — это начальный размер змейки, и это не является достижением игрока).

def Your_score(score):
   value = score_font.render("Ваш счёт: " + str(score), True, yellow)
   dis.blit(value, [0, 0])

И отдельно пропишем правило определения длины змейки, вычитая из текущей длины змейки единицу.

Your_score(Length_of_snake - 1)

Теперь на игровом поле будет отображаться текущий счёт:

Скриншот: Pygame / Skillbox Media

Можно считать, что наша работа над «Змейкой» закончена. Мы полностью реализовали геймплей, который запланировали на старте работы.

Наш код полностью и без комментариев:

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» Пола Винсента Крэйвена.

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

Участвовать

На самом деле строчек кода с логикой игры будет гораздо меньше, добрую половину скрипта занимает подготовка игрового поля, рисование новорождённой змеи, назначение клавиш управления и ещё парочка мелочей. Публикация может быть полезна для таких же начинающих, как и я сам. И да, в коде могут быть ошибки, которые я в настоящий момент не вижу в силу своего небольшого опыта программирования, заканчивающегося на прочтении Марка Лутца и пока ещё недописанном телеграм боте, но змейка работает исправно и делает всё, что было задумано. Писать буду с использованием модуля turtle. Погнали.

import time
import turtle
from random import randrange

BREAK_FLAG = False

Импортируем необходимые модули и задаём глобальную переменную. Модуль time понадобится для установки паузы в основном бесконечном цикле программы, turtle будет отвечать за графику в игре, из модуля random возьмём один метод randrange для генерации координат еды для нашей змеи. С помощью переменной BREAK_FLAG будем останавливать игру при укусе змейки самой себя, подробнее об этом позже.

# draw a window for the game
screen = turtle.Screen()
screen.title('Snake with turtle module')
screen.bgcolor('orange')
screen.setup(650, 650)
screen.tracer(0)

Следующим шагом создаём окно игры, назначаем название, задаём цвет фона и размеры окна. Строка screen.tracer(0) отключает анимацию, рисовать кадры будем сами в основном цикле программы. Если этого не сделать вновь созданный сегмент змейки и новый элемент еды, после поедания добычи, будет появляться в центре поля и только потом перемещаться в заданные координаты и весь этот процесс мы будем видеть. Это особенность библиотеки turtle, каждый новый объект всегда появляется в центре координат.

# draw a game field border
border = turtle.Turtle()
border.hideturtle()
border.penup()
border.goto(-311, 311)
border.pendown()
border.goto(311, 311)
border.goto(311, -311)
border.goto(-311, -311)
border.goto(-311, 311)

Для наглядности нарисуем границы игрового поля. Создаём объект черепашки border = turtle.Turtle(), делаем его невидимым border.hideturtle(), так как от него нам понадобится только линия, которую он чертит при перемещении. И опуская и поднимая перо border.penup(), border.pendown() перемещаем нашу черепашку по строго заданным координатам. На выходе получаем чёрный квадрат, границы которого нельзя будет пересекать нашей змее.

# draw a snake of three segments and
# paint the head of the snake in black
snake = []
for i in range(3):
    snake_segment = turtle.Turtle()
    snake_segment.shape('square')
    snake_segment.penup()
    if i > 0:
        snake_segment.color('gray')
    snake.append(snake_segment)

Создадим змейку. Наша вновь рождённая змея будет состоять из трёх сегментов каждый из которых будет являться новым экземпляром класса Turtle. Другими словами змея будет состоять из множества черепашек. Надеюсь контекст слова «черепашка» в этой публикации понятен всем без объяснений. Хранить змейку целиком будем в виде списка в переменной snake. Создаём змею в цикле for, который прогоняем три раза. Создаём новый сегмент snake_segment = turtle.Turtle(), задаём форму snake_segment.shape(‘square’) и поднимаем перо snake_segment.penup() так, как нам не надо, чтобы змейка оставляла после себя след. Условие if необходимо для окраски сегментов в серый цвет. Красятся все кроме первого, голова остаётся чёрной. В конце каждой итерации добавляем сегмент в список хранящий всю змею целиком snake.append(snake_segment).

# draw a food for the snake
food = turtle.Turtle()
food.shape('circle')
food.penup()
food.goto(randrange(-300, 300, 20), randrange(-300, 300, 20))

В этом блоке кода создаём объект еды, задаём ему круглую форму, генерируем координаты и перемещаем еду на определённое для неё место.

# snake control
screen.onkeypress(lambda: snake[0].setheading(90), 'Up')
screen.onkeypress(lambda: snake[0].setheading(270), 'Down')
screen.onkeypress(lambda: snake[0].setheading(180), 'Left')
screen.onkeypress(lambda: snake[0].setheading(0), 'Right')
screen.listen()

Управлять змейкой будем кнопками навигации со стрелками. За привязку клавиш отвечает метод screen.onkeypress(). Методу необходимо передать в качестве аргументов функцию и имя кнопки, которая будет вызывать функцию. Метод setheading() задаёт направление движения объекта черепашки. Использовать его будем в таком виде snake[0].setheading(90), то есть голову змейки повернуть на 90 градусов относительно направления по умолчанию. Для нас это значит вверх. Оборачиваем метод в лямбда выражение, это отложит его вызов до момента нажатия на клавишу. Имя кнопки передаём в виде строки ‘Up’ повторяем процедуру для остальных направлений. Начинаем слушать события с клавиатуры screen.listen()

Ну и наконец самое интересное. Логика игры будет обрабатываться в бесконечном цикле. Для наглядности положу его полностью здесь под

спойлером

while True:

    # creating a new segment of the snake
    # and redraw a food for the snake
    if snake[0].distance(food) < 10:
        food.goto(randrange(-300, 300, 20), randrange(-300, 300, 20))
        snake_segment = turtle.Turtle()
        snake_segment.shape('square')
        snake_segment.color('gray')
        snake_segment.penup()
        snake.append(snake_segment)

    # snake body movement
    for i in range(len(snake)-1, 0, -1):
        x = snake[i-1].xcor()
        y = snake[i-1].ycor()
        snake[i].goto(x, y)

    # snake head movement
    snake[0].forward(20)

    screen.update()

    # snake collision with border
    x_cor = snake[0].xcor()
    y_cor = snake[0].ycor()
    if x_cor > 300 or x_cor < -300:
        screen.bgcolor('red')
        break
    if y_cor > 300 or y_cor < -300:
        screen.bgcolor('red')
        break

    # snake collision with itself
    for i in snake[1:]:
        i = i.position()
        if snake[0].distance(i) < 10:
            BREAK_FLAG = True
    if BREAK_FLAG:
        screen.bgcolor('red')
        break
    time.sleep(0.2)

    # creating a new segment of the snake
    # and redraw a food for the snake
    if snake[0].distance(food) < 10:
        food.goto(randrange(-300, 300, 20), randrange(-300, 300, 20))
        snake_segment = turtle.Turtle()
        snake_segment.shape('square')
        snake_segment.color('gray')
        snake_segment.penup()
        snake.append(snake_segment)

А теперь по порядку. Если расстояние от головы змеи до еды меньше 10 if snake[0].distance(food) < 10:, то есть змейка съела добычу, генерируем и размещаем новую добычу, создаём новый сегмент змейки и помещаем его в список snake.

    # snake body movement
    for i in range(len(snake)-1, 0, -1):
        x = snake[i-1].xcor()
        y = snake[i-1].ycor()
        snake[i].goto(x, y)

Этот блок кода отвечает за перемещение тела змеи. Перебираем в цикле for сегменты змеи начиная с хвоста. Получаем координаты x и y предпоследнего сегмента методами xcor() и ycor() перемещаем на их место последний сегмент snake[i].goto(x, y) и так двигаемся до самой головы.

    # snake head movement
    snake[0].forward(20)

Саму же голову двигаем отдельно на 20 пикселей вперёд на каждой итерации бесконечного цикла while. Таким образом мы управляем только первым сегментом змейки, остальные просто повторяют его движение перебираясь в цикле for.

По правде говоря, с передвижением тела змеи у меня возникли некоторые проблемы. Текущую реализацию цикла for i in range(len(snake)-1, 0, -1) я подсмотрел на гитхабе. Но мне показалось не логичным начинать движение с хвоста. Попытки переписать цикл в обратном направлении(то есть начинать перемещение с головы) успехом не увенчались. Поэтому пользуясь случаем обращаюсь к опытным читателям показать возможную реализацию цикла в другом направлении. Если конечно в этом есть смысл, может мне просто кажется текущее решение не логичным.

screen.update()

Двигаемся дальше. screen.update() обновляет кадр, то есть по сути отвечает за анимацию, которую мы отключили в самом начале.

# snake collision with border
    x_cor = snake[0].xcor()
    y_cor = snake[0].ycor()
    if x_cor > 300 or x_cor < -300:
        screen.bgcolor('red')
        break
    if y_cor > 300 or y_cor < -300:
        screen.bgcolor('red')
        break

Эти два условия проверяют расстояние от головы змеи до граничных координат. Если голова Выходит за предельные значение окрашиваем экран в красный цвет и прерываем работу главного цикла, Game Over короче.

    # snake collision with itself
    for i in snake[1:]:
        i = i.position()
        if snake[0].distance(i) < 10:
            BREAK_FLAG = True
    if BREAK_FLAG:
        screen.bgcolor('red')
        break

В этом блоке кода реализовано поведение игры при укусе змейки самой себя. В цикле for перебираем все сегменты змеи кроме головы. Сравниваем расстояние от головы до текущего сегмента и если оно меньше 10 if snake[0].distance(i) < 10:, что равно укусу, передаём значение True глобальной переменной BREAK_FLAG. Далее проверяем на истинность BREAK_FLAG и если оно True красим экран в красный и останавливаем игру. Если False переходим к следующей строке.

time.sleep(0.2)

Метод time.sleep(0.2) останавливает цикл на 20 мс, значением аргумента метода можно управлять скоростью игры.

screen.mainloop()
И последняя строка завершает код. Метод mainloop() должен всегда завершать программу написанную с использованием модуля turtle.

На этом всё, буду рад любой критике. Надеюсь было интересно и возможно для кого-то даже полезно. Исходный код змейки можно найти в моём github аккаунте. Программа написана в ОС Ubuntu 18.04, на Windows машине графика выглядит расплывчато и слишком крупно, но змейка вполне рабочая.

Сегодня мы напишем игру змейка на Python. Это одна из самых распространенных аркад в мире. В основе ее реализации будет два класса:

  • Класс сегмента (одного блока змейки).
  • Класс змеи (по сути собрание сегментов).

В процессе написания змейки у нас будут следующие этапы:

  1. Создание графического окна приложения.
  2. Объявление вспомогательных глобальных переменных.
  3. Установка на окне области для рисования.
  4. Создание классов сегмента и змеи.
  5. Создание вспомогательных функций.

Создание графического окна приложения.

Мы будем работать с библиотекой tkinter, в котором окно задается следующим образом:

from tkinter import *

# Создаем окно
root = Tk()
# Устанавливаем название окна
root.title("PythonicWay Snake")

# Запускаем окно
root.mainloop()

 Обратите внимание, что весь остальной код должен находиться до строки root.mainloop()

Объявление вспомогательных глобальных переменных.

Тут все просто, для облегчения последующей работы создадим следующие переменные:

# ширина экрана
WIDTH = 800
# высота экрана
HEIGHT = 600
# Размер сегмента змейки
SEG_SIZE = 20
# Переменная отвечающая за состояние игры
IN_GAME = True

Установка на окне области для рисования.

Область для рисования в tkinter реализована при помощи класса Canvas, им и воспользуемся.

# создаем экземпляр класса Canvas (его мы еще будем использовать) и заливаем все зеленым цветом
c = Canvas(root, width=WIDTH, height=HEIGHT, bg="#003300")
c.grid()
# Наводим фокус на Canvas, чтобы мы могли ловить нажатия клавиш
c.focus_set()

Если вы все делали правильно, то запустив полученный код получите следующую картину

змейка на python, tkinter snake canvas

Создание классов сегмента и змеи:

Класс сегмента змейки.

Сегмент змейки будет простым прямоугольником, созданным при помощи метода create_rectangle класса Canvas модуля tkinter.

class Segment(object):
    def __init__(self, x, y):
        self.instance = c.create_rectangle(x, y,
                         x+SEG_SIZE, y+SEG_SIZE,
                         fill="white")

Класс змейки.

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

class Snake(object):
    def __init__(self, segments):
        self.segments = segments
        
        # список доступных направлений движения змейки
        self.mapping = {"Down": (0, 1), "Up": (0, -1),
                                "Left": (-1, 0), "Right": (1, 0) }
        # изначально змейка двигается вправо
        self.vector = self.mapping["Right"]
    
    def move(self):
         """ Двигает змейку в заданном направлении """
         
         # перебираем все сегменты кроме первого
         for index in range(len(self.segments)-1):
              segment = self.segments[index].instance
              x1, y1, x2, y2 = c.coords(self.segments[index+1].instance)
              # задаем каждому сегменту позицию сегмента стоящего после него
              c.coords(segment, x1, y1, x2, y2)
         
         # получаем координаты сегмента перед "головой"
         x1, y1, x2, y2 = c.coords(self.segments[-2].instance)
         
         # помещаем "голову" в направлении указанном в векторе движения
         c.coords(self.segments[-1].instance,
                       x1 + self.vector[0]*SEG_SIZE,
                       y1 + self.vector[1]*SEG_SIZE,
                       x2 + self.vector[0]*SEG_SIZE,
                       y2 + self.vector[1]*SEG_SIZE)
    
    def change_direction(self, event):
        """ Изменяет направление движения змейки """

        # event передаст нам символ нажатой клавиши
        # и если эта клавиша в доступных направлениях 
        # изменяем направление
        if event.keysym in self.mapping:
            self.vector = self.mapping[event.keysym]

    def add_segment(self):
        """ Добавляет сегмент змейке """

        # определяем последний сегмент
        last_seg = c.coords(self.segments[0].instance)
        
        # определяем координаты куда поставить следующий сегмент
        x = last_seg[2] - SEG_SIZE
        y = last_seg[3] - SEG_SIZE
        
        # добавляем змейке еще один сегмент в заданных координатах
        self.segments.insert(0, Segment(x, y))  

Если вы осилили эти два класса и более того, поняли что, как и почему, то поздравляю — самая трудная часть позади. Уже сейчас можно создавать змейку. Вставте следующие строчки, но обязательно после строк c.grid()

# создаем набор сегментов
segments = [Segment(SEG_SIZE, SEG_SIZE),
            Segment(SEG_SIZE*2, SEG_SIZE),
            Segment(SEG_SIZE*3, SEG_SIZE)]

# собственно змейка
s = Snake(segments)

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

 змейка на python, python snake

Создание вспомогательных функций.

Для начала напишем функцию создания яблок (или что там наша змея будет есть). Не забудьте импортировать модуль random, чтобы все работало

def create_block():
    """ Создает блок в случайной позиции на карте """
    global BLOCK
    posx = SEG_SIZE * (random.randint(1, (WIDTH-SEG_SIZE) / SEG_SIZE))
    posy = SEG_SIZE * (random.randint(1, (HEIGHT-SEG_SIZE) / SEG_SIZE))
    
    # блок это кружочек красного цвета
    BLOCK = c.create_oval(posx, posy,
                          posx + SEG_SIZE,
                          posy + SEG_SIZE,
                          fill="red")
    

Теперь основная функция main, которая будет управлять игровым процессом.

def main():
    global IN_GAME
    
    if IN_GAME:
        # Двигаем змейку
        s.move()
 
        # Определяем координаты головы
        head_coords = c.coords(s.segments[-1].instance)
        x1, y1, x2, y2 = head_coords
    
        # Столкновение с границами экрана
        if x1 < 0 or x2 > WIDTH or y1 < 0 or y2 > HEIGHT:
            IN_GAME = False
    
        # Поедание яблок 
        elif head_coords == c.coords(BLOCK):
            s.add_segment()
            c.delete(BLOCK)
            c.create_block()

        # Самоедство
        else:
            # Проходим по всем сегментам змеи
            for index in range(len(s.segments)-1):
                if c.coords(s.segments[index].instance) == head_coords:
                    IN_GAME = False
    
    # Если не в игре выводим сообщение о проигрыше
    else:
          c.create_text(WIDTH/2, HEIGHT/2,
                              text="GAME OVER!",
                              font="Arial 20",
                              fill="#ff0000")
    

 Последний шаг — правильно обработать нажатия клавиш. Привяжем метод класса Snake change_direction() к Canvas:

c.bind("<KeyPress>", s.change_direction)

 змейка на python, python snake

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

UPD: В репозитории добавлен вариант с перезапуском игры после проигрыша.

Полный код игры змейка на Python на GitHub

Змеиная игра – это аркадная игра-лабиринт, разработанная Gremlin Industries и опубликованная Sega в октябре 1976 года. Она считается искусной игрой и популяризируется среди людей на протяжении поколений. Змейка в игре Snake управляется с помощью четырех кнопок направления относительно направления, в котором она движется. Цель игрока в игре — набрать как можно больше очков, собирая еду или фрукты. Игрок проигрывает, когда змея ударяется о стену или сама себя.

Для новичков в Python, заинтересованных в том, чтобы сделать что-то проще в своей области, могут определенно попробовать это, и модуль Turtle был создан именно для этой цели, чтобы новички могли его попробовать и также могли представить как часть проекта. Эта программа будет выполнена на Python 3.

Итак, мы будем создавать игру на основе Python, используя следующие модули:

Следующий код можно легко выполнить с помощью среды разработки PyCharm, специально созданного для программ, написанных Python.

Также для этой программы можно использовать VSCode. Установите Python3 из расширения VSCode. Затем сохраните программу в виде your_filename.py.

Ниже приведен пошаговый подход к созданию игры «Змейка» с использованием модуля «Черепаха»:
Шаг 1: Мы будем импортировать модули в программу и задавать значения по умолчанию для игры.

import turtle
import time
import random
 
delay = 0.1
score = 0
high_score = 0

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

# Creating a window screen
wn = turtle.Screen()
wn.title("Snake Game")
wn.bgcolor("blue")
 
# the width and height can be put as user's choice
wn.setup(width=600, height=600)
wn.tracer(0)
 
 
# head of the snake
head = turtle.Turtle()
head.shape("square")
head.color("white")
head.penup()
head.goto(0, 0)
head.direction = "Stop"
 
 
# food in the game
food = turtle.Turtle()
colors = random.choice(['red', 'green', 'black'])
shapes = random.choice(['square', 'triangle', 'circle'])
food.speed(0)
food.shape(shapes)
food.color(colors)
food.penup()
food.goto(0, 100)
 
 
pen = turtle.Turtle()
pen.speed(0)
pen.shape("square")
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0, 250)
pen.write("Score : 0  High Score : 0", align="center",
          font=("candara", 24, "bold"))

Вывод:

Создаем игру-змейку, используя модуль Turtle в Python.

Шаг 3: Теперь мы будем проверять ключ для движений змеи. Нажимая на ключевые слова, обычно используемые для игр «w», «a», «s» и «d», мы можем управлять движениями змеи по экрану.

# assigning key directions
def group():
    if head.direction != "down":
        head.direction = "up"
 
 
def godown():
    if head.direction != "up":
        head.direction = "down"
 
 
def goleft():
    if head.direction != "right":
        head.direction = "left"
 
 
def goright():
    if head.direction != "left":
        head.direction = "right"
 
 
def move():
    if head.direction == "up":
        y = head.ycor()
        head.sety(y+20)
    if head.direction == "down":
        y = head.ycor()
        head.sety(y-20)
    if head.direction == "left":
        x = head.xcor()
        head.setx(x-20)
    if head.direction == "right":
        x = head.xcor()
        head.setx(x+20)
 
 
wn.listen()
wn.onkeypress(group, "w")
wn.onkeypress(godown, "s")
wn.onkeypress(goleft, "a")
wn.onkeypress(goright, "d")

Шаг 4: Теперь, наконец, мы создадим игровой процесс, в котором будет происходить следующее:

Змейка растет, когда ест плоды.
Придание цвета хвосту змеи.
После того, как фрукты будут съедены, будет рассчитан счет.
Проверка на столкновение головы змейки с телом или стенкой оконного экрана.
Автоматический перезапуск игры со старта после столкновения.
Новая форма и цвет фруктов будут вводиться каждый раз при перезапуске окна.
Счет будет возвращен к нулю, а высокий балл будет сохранен до тех пор, пока окно не будет закрыто.

segments = []
 
# Main Gameplay
while True:
    wn.update()
    if head.xcor() > 290 or head.xcor() < -290 or head.ycor() > 290 or head.ycor() < -290:
        time.sleep(1)
        head.goto(0, 0)
        head.direction = "Stop"
        colors = random.choice(['red', 'blue', 'green'])
        shapes = random.choice(['square', 'circle'])
        for segment in segments:
            segment.goto(1000, 1000)
        segments.clear()
        score = 0
        delay = 0.1
        pen.clear()
        pen.write("Score : {} High Score : {} ".format(
            score, high_score), align="center", font=("candara", 24, "bold"))
    if head.distance(food) < 20:
        x = random.randint(-270, 270)
        y = random.randint(-270, 270)
        food.goto(x, y)
 
        # Adding segment
        new_segment = turtle.Turtle()
        new_segment.speed(0)
        new_segment.shape("square")
        new_segment.color("orange")  # tail colour
        new_segment.penup()
        segments.append(new_segment)
        delay -= 0.001
        score += 10
        if score > high_score:
            high_score = score
        pen.clear()
        pen.write("Score : {} High Score : {} ".format(
            score, high_score), align="center", font=("candara", 24, "bold"))
    # Checking for head collisions with body segments
    for index in range(len(segments)-1, 0, -1):
        x = segments[index-1].xcor()
        y = segments[index-1].ycor()
        segments[index].goto(x, y)
    if len(segments) > 0:
        x = head.xcor()
        y = head.ycor()
        segments[0].goto(x, y)
    move()
    for segment in segments:
        if segment.distance(head) < 20:
            time.sleep(1)
            head.goto(0, 0)
            head.direction = "stop"
            colors = random.choice(['red', 'blue', 'green'])
            shapes = random.choice(['square', 'circle'])
            for segment in segments:
                segment.goto(1000, 1000)
            segment.clear()
 
            score = 0
            delay = 0.1
            pen.clear()
            pen.write("Score : {} High Score : {} ".format(
                score, high_score), align="center", font=("candara", 24, "bold"))
    time.sleep(delay)
 
wn.mainloop()
Полный код программы : 
# import required modules
import turtle
import time
import random
 
delay = 0.1
score = 0
high_score = 0
 
 
 
# Creating a window screen
wn = turtle.Screen()
wn.title("Snake Game")
wn.bgcolor("blue")
# the width and height can be put as user's choice
wn.setup(width=600, height=600)
wn.tracer(0)
 
# head of the snake
head = turtle.Turtle()
head.shape("square")
head.color("white")
head.penup()
head.goto(0, 0)
head.direction = "Stop"
 
# food in the game
food = turtle.Turtle()
colors = random.choice(['red', 'green', 'black'])
shapes = random.choice(['square', 'triangle', 'circle'])
food.speed(0)
food.shape(shapes)
food.color(colors)
food.penup()
food.goto(0, 100)
 
pen = turtle.Turtle()
pen.speed(0)
pen.shape("square")
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0, 250)
pen.write("Score : 0  High Score : 0", align="center",
          font=("candara", 24, "bold"))
 
 
 
# assigning key directions
def group():
    if head.direction != "down":
        head.direction = "up"
 
 
def godown():
    if head.direction != "up":
        head.direction = "down"
 
 
def goleft():
    if head.direction != "right":
        head.direction = "left"
 
 
def goright():
    if head.direction != "left":
        head.direction = "right"
 
 
def move():
    if head.direction == "up":
        y = head.ycor()
        head.sety(y+20)
    if head.direction == "down":
        y = head.ycor()
        head.sety(y-20)
    if head.direction == "left":
        x = head.xcor()
        head.setx(x-20)
    if head.direction == "right":
        x = head.xcor()
        head.setx(x+20)
 
 
         
wn.listen()
wn.onkeypress(group, "w")
wn.onkeypress(godown, "s")
wn.onkeypress(goleft, "a")
wn.onkeypress(goright, "d")
 
segments = []

Создаем игру-змейку, используя модуль Turtle в Python.

Просмотры: 6 741

В этой статье мы напишем игру змейка на Python. Это одна из самых распространенных аркад в мире. В основе ее реализации будет три класса:

  • Класс сегмента (одного блока змейки).
  • Класс змеи (по сути собрание сегментов).
  • Класс подсчета очков.

В процессе написания змейки у нас будут следующие этапы:

  1. Создание окна приложения;
  2. Объявление вспомогательных переменных;
  3. Создание игрового поля;
  4. Создание классов сегмента, змеи и очков;
  5. Создание разных дополнительных функций;
  6. Создание функций для начала новой игры и выхода из игры.

Создание окна приложения

Первым делом нужно разработать каркас для нашего приложения — главное окно. Листинг:

from tkinter import *

# Настройка главного окна
root = Tk()
root.title("Змейка")

# запускаем окно
root.mainloop()

Объявление вспомогательных переменных

Добавляем в нашу программу вспомогательные переменные. Их нужно добавить сразу после оператора импорта tkinter:

# Ширина экрана
WIDTH = 800

# Высота экрана
HEIGHT = 600

# Размер сегмента змеи
SEG_SIZE = 20

# Переменная, отвечающая за состояние игры
IN_GAME = True

Это глобальные переменные, которые мы будем использовать в процессе игры.

Создание игрового поля

Игровое поле мы реализуем с помощью Canvas. Создадим холст нужного нам размера и зальем его черным цветом. Листинг:

# Создаем экземпляр класса Canvas
c = Canvas(root, width=WIDTH, height=HEIGHT, bg="#000000")
c.grid()

# Захватываем фокус для отлавливания нажатий клавиш
c.focus_set()

Создание основных классов

Класс сегмента змеи

Первый класс — это сегмент змейки. Визуально сегмент змейки будет представлен обычным прямоугольником, созданным при помощи метода create_rectangle класса Canvas модуля tkinter. Листинг:

class Segment(object):
    """ Сегмент змейки """
    def __init__(self, x, y):
        self.instance = c.create_rectangle(x, y,
                                           x + SEG_SIZE, y + SEG_SIZE,
                                           fill="green")
Класс змейки

Змейка у нас будет набором сегментов. У нее будут методы движения, изменения направления и добавления сегмента. Листинг:

class Snake(object):
    """ Класс змейки """
    def __init__(self, segments):
        self.segments = segments

        # Варианты движения
        self.mapping = {"Down": (0, 1), "Right": (1, 0),
                        "Up": (0, -1), "Left": (-1, 0)}

        # инициируем направление движения
        self.vector = self.mapping["Right"]

    def move(self):
        """ Двигаем змейку в заданном направлении """
        for index in range(len(self.segments) - 1):
            segment = self.segments[index].instance
            x1, y1, x2, y2 = c.coords(self.segments[index + 1].instance)
            c.coords(segment, x1, y1, x2, y2)

        x1, y1, x2, y2 = c.coords(self.segments[-2].instance)
        c.coords(self.segments[-1].instance,
                 x1 + self.vector[0] * SEG_SIZE, y1 + self.vector[1] * SEG_SIZE,
                 x2 + self.vector[0] * SEG_SIZE, y2 + self.vector[1] * SEG_SIZE)

    def add_segment(self):
        """ Добавляем сегмент змейки """
        score.increment()
        last_seg = c.coords(self.segments[0].instance)
        x = last_seg[2] - SEG_SIZE
        y = last_seg[3] - SEG_SIZE
        self.segments.insert(0, Segment(x, y))

    def change_direction(self, event):
        """ Изменение направления движения змейки """
        if event.keysym in self.mapping:
            self.vector = self.mapping[event.keysym]

    # Функция обновления змейки при старте новой игры
    def reset_snake(self):
        for segment in self.segments:
            c.delete(segment.instance)

Конструктор (метод __init__) задает список доступных направлений движения змейки и задает направление по умолчанию — вправо.

Метод move() двигает змейку в заданном направлении. Метод change_direction() изменяет направление движения змейки.

За добавление нового сегмента отвечает метод add_segment(). Метод reset_snake() отвечает за обновления змейки при старте новой игры. Внимательно читайте все комментарии к коду.

Добавим в код функцию для создания сегментов и змейки:

# Создаем сегменты и змейку
def create_snake():
    segments = [Segment(SEG_SIZE, SEG_SIZE),
                Segment(SEG_SIZE * 2, SEG_SIZE),
                Segment(SEG_SIZE * 3, SEG_SIZE)]
    return Snake(segments)
Класс подсчета очков

Последний класс отвечает за счет очков при съедании змейкой сегмента:

# Подсчет очков
class Score(object):

    # функция отображения очков на экране
    def __init__(self):
        self.score = 0
        self.x = 55
        self.y = 15
        c.create_text(self.x, self.y, text="Счёт: {}".format(self.score), font="Arial 20",
                      fill="Yellow", tag="score", state='hidden')

    # функция счета очков и вывод на экран
    def increment(self):
        c.delete("score")
        self.score += 1
        c.create_text(self.x, self.y, text="Счёт: {}".format(self.score), font="Arial 20",
                      fill="Yellow", tag="score")

    # функция сброса очков при начале новой игры
    def reset(self):
        c.delete("score")
        self.score = 0

Конструктор (метод __init__) отображает очки на экране при поедании змейкой сегментов. Метод increment() ведет счет очков. Метод reset() обновляет очки при старте новой игры.

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

# Считаем очки
score = Score()

Создание разных дополнительных функций

Нам понадобятся две вспомогательные функции. Первая — create_block(), которая создает пищу для змейки. В нашем случае это будет яблоко — кружок зеленого цвета. Чтобы эта функция работала необходимо импортировать модуль random:

import random

Листинг функции:

# Вспомогательная функция
def create_block():
    """ Создаем еду для змейки """
    global BLOCK
    posx = SEG_SIZE * random.randint(1, (WIDTH - SEG_SIZE) / SEG_SIZE)
    posy = SEG_SIZE * random.randint(1, (HEIGHT - SEG_SIZE) / SEG_SIZE)
    BLOCK = c.create_oval(posx, posy,
                          posx + SEG_SIZE, posy + SEG_SIZE,
                          fill="green")

Следующая вспомогательная функция main() будет управлять игровым процессом — именно она будет управлять тем, куда пойдет змейка, обрабатывает столкновения с границами экрана, отвечает за поедание яблок и увеличение змейки. Листинг:

def main():
    """ Моделируем игровой процесс """
    global IN_GAME
    if IN_GAME:
        s.move()

        # Определяем координаты головы
        head_coords = c.coords(s.segments[-1].instance)
        x1, y1, x2, y2 = head_coords

        # столкновения с краями игрового поля
        if x2 > WIDTH or x1 < 0 or y1 < 0 or y2 > HEIGHT:
            IN_GAME = False

        # Поедание яблока
        elif head_coords == c.coords(BLOCK):
            s.add_segment()
            c.delete(BLOCK)
            create_block()

        # Поедание змейки
        else:
            for index in range(len(s.segments) - 1):
                if head_coords == c.coords(s.segments[index].instance):
                    IN_GAME = False

        # скорость змейки
        root.after(100, main)
    # Не IN_GAME -> останавливаем игру и выводим сообщения
    else:
        set_state(restart_text, 'normal')
        set_state(game_over_text, 'normal')
        set_state(close_but, 'normal')

Создание функций для начала новой игры и выхода из игры

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

# функция для вывода сообщения
def set_state(item, state):
    c.itemconfigure(item, state=state)
    c.itemconfigure(BLOCK, state='hidden')

# Функция для нажатия кнопки (новая игра)
def clicked(event):
    global IN_GAME
    s.reset_snake()
    IN_GAME = True
    c.delete(BLOCK)
    score.reset()
    c.itemconfigure(restart_text, state='hidden')
    c.itemconfigure(game_over_text, state='hidden')
    c.itemconfigure(close_but, state='hidden')
    start_game()

# Функция для старта игры
def start_game():
    global s
    create_block()
    s = create_snake()

    # Реагируем на нажатие клавиш
    c.bind("<KeyPress>", s.change_direction)
    main()

# выход из игры
def close_win(root):
    exit()

В главном окне необходимо добавить строки:

# Текст результата игры
game_over_text = c.create_text(WIDTH / 2, HEIGHT / 2, text="Ты проиграл!",
                               font='Arial 20', fill='red',
                               state='hidden')
                               
# Текст начала новой игры после проигрыша
restart_text = c.create_text(WIDTH / 2, HEIGHT - HEIGHT / 3,
                             font='Arial 25',
                             fill='green',
                             text="Начать новую игру",
                             state='hidden')

# Текст выхода из программы после проигрыша
close_but = c.create_text(WIDTH / 2, HEIGHT - HEIGHT / 5, font='Arial 25',
                          fill='green',
                          text="Выход из игры",
                          state='hidden')

# Отработка событий при нажимания кнопок
c.tag_bind(restart_text, "<Button-1>", clicked)
c.tag_bind(close_but, "<Button-1>", close_win)

# Запускаем игру
start_game()

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

Полный исходный код

В данном разделе мы оставим полный исходный код, чтобы вы смогли свериться с вашим вариантом. Листинг:

from tkinter import *
import random

# Создаем глобальные переменные
# Ширина экрана
WIDTH = 800

# Высота экрана
HEIGHT = 600

# Размер сегмента змеи
SEG_SIZE = 20

# Переменная, отвечающая за состояние игры
IN_GAME = True


# Вспомогательная функция
def create_block():
    """ Создаем еду для змейки """
    global BLOCK
    posx = SEG_SIZE * random.randint(1, (WIDTH - SEG_SIZE) / SEG_SIZE)
    posy = SEG_SIZE * random.randint(1, (HEIGHT - SEG_SIZE) / SEG_SIZE)
    BLOCK = c.create_oval(posx, posy,
                          posx + SEG_SIZE, posy + SEG_SIZE,
                          fill="green")

# Подсчет очков
class Score(object):

    # функция отображения очков на экране
    def __init__(self):
        self.score = 0
        self.x = 55
        self.y = 15
        c.create_text(self.x, self.y, text="Счёт: {}".format(self.score), font="Arial 20",
                      fill="Yellow", tag="score", state='hidden')

    # функция счета очков и вывод на экран
    def increment(self):
        c.delete("score")
        self.score += 1
        c.create_text(self.x, self.y, text="Счёт: {}".format(self.score), font="Arial 20",
                      fill="Yellow", tag="score")

    # функция сброса очков при начале новой игры
    def reset(self):
        c.delete("score")
        self.score = 0

# Функция для управления игровым процессом
def main():
    """ Моделируем игровой процесс """
    global IN_GAME
    if IN_GAME:
        s.move()

        # Определяем координаты головы
        head_coords = c.coords(s.segments[-1].instance)
        x1, y1, x2, y2 = head_coords

        # столкновения с краями игрового поля
        if x2 > WIDTH or x1 < 0 or y1 < 0 or y2 > HEIGHT:
            IN_GAME = False

        # Поедание яблока
        elif head_coords == c.coords(BLOCK):
            s.add_segment()
            c.delete(BLOCK)
            create_block()

        # Поедание змейки
        else:
            for index in range(len(s.segments) - 1):
                if head_coords == c.coords(s.segments[index].instance):
                    IN_GAME = False

        # скорость змейки
        root.after(100, main)
    # Не IN_GAME -> останавливаем игру и выводим сообщения
    else:
        set_state(restart_text, 'normal')
        set_state(game_over_text, 'normal')
        set_state(close_but, 'normal')

class Segment(object):
    """ Сегмент змейки """
    def __init__(self, x, y):
        self.instance = c.create_rectangle(x, y,
                                           x + SEG_SIZE, y + SEG_SIZE,
                                           fill="green")
                                           
class Snake(object):
    """ Класс змейки """
    def __init__(self, segments):
        self.segments = segments

        # Варианты движения
        self.mapping = {"Down": (0, 1), "Right": (1, 0),
                        "Up": (0, -1), "Left": (-1, 0)}

        # инициируем направление движения
        self.vector = self.mapping["Right"]

    def move(self):
        """ Двигаем змейку в заданном направлении """
        for index in range(len(self.segments) - 1):
            segment = self.segments[index].instance
            x1, y1, x2, y2 = c.coords(self.segments[index + 1].instance)
            c.coords(segment, x1, y1, x2, y2)

        x1, y1, x2, y2 = c.coords(self.segments[-2].instance)
        c.coords(self.segments[-1].instance,
                 x1 + self.vector[0] * SEG_SIZE, y1 + self.vector[1] * SEG_SIZE,
                 x2 + self.vector[0] * SEG_SIZE, y2 + self.vector[1] * SEG_SIZE)

    def add_segment(self):
        """ Добавляем сегмент змейки """
        score.increment()
        last_seg = c.coords(self.segments[0].instance)
        x = last_seg[2] - SEG_SIZE
        y = last_seg[3] - SEG_SIZE
        self.segments.insert(0, Segment(x, y))

    def change_direction(self, event):
        """ Изменение направления движения змейки """
        if event.keysym in self.mapping:
            self.vector = self.mapping[event.keysym]

    # Функция обновления змейки при старте новой игры
    def reset_snake(self):
        for segment in self.segments:
            c.delete(segment.instance)

# функция для вывода сообщения
def set_state(item, state):
    c.itemconfigure(item, state=state)
    c.itemconfigure(BLOCK, state='hidden')


# Функция для нажатия кнопки (новая игра)
def clicked(event):
    global IN_GAME
    s.reset_snake()
    IN_GAME = True
    c.delete(BLOCK)
    score.reset()
    c.itemconfigure(restart_text, state='hidden')
    c.itemconfigure(game_over_text, state='hidden')
    c.itemconfigure(close_but, state='hidden')
    start_game()

# Функция для старта игры
def start_game():
    global s
    create_block()
    s = create_snake()

    # Реагируем на нажатие клавиш
    c.bind("<KeyPress>", s.change_direction)
    main()


# Создаем сегменты и змейку
def create_snake():
    segments = [Segment(SEG_SIZE, SEG_SIZE),
                Segment(SEG_SIZE * 2, SEG_SIZE),
                Segment(SEG_SIZE * 3, SEG_SIZE)]
    return Snake(segments)
    
# выход из игры
def close_win(root):
    exit()

# Настройка главного окна
root = Tk()
root.title("Змейка")

# Создаем экземпляр класса Canvas
c = Canvas(root, width=WIDTH, height=HEIGHT, bg="#000000")
c.grid()

# Захватываем фокус для отлавливания нажатий клавиш
c.focus_set()

# Текст результата игры
game_over_text = c.create_text(WIDTH / 2, HEIGHT / 2, text="Ты проиграл!",
                               font='Arial 20', fill='red',
                               state='hidden')
                               
# Текст начала новой игры после проигрыша
restart_text = c.create_text(WIDTH / 2, HEIGHT - HEIGHT / 3,
                             font='Arial 25',
                             fill='green',
                             text="Начать новую игру",
                             state='hidden')

# Текст выхода из программы после проигрыша
close_but = c.create_text(WIDTH / 2, HEIGHT - HEIGHT / 5, font='Arial 25',
                          fill='green',
                          text="Выход из игры",
                          state='hidden')

# Отработка событий при нажимания кнопок
c.tag_bind(restart_text, "<Button-1>", clicked)
c.tag_bind(close_but, "<Button-1>", close_win)

# Считаем очки
score = Score()

# Запускаем игру
start_game()

# запускаем окно
root.mainloop()

Интерфейс приложения:

Библиотека Tkinter: Разработка игры "Змейка"

#!/usr/bin/python3 # coding: utf-8 »’ Игра разработана Голубых Иваном Борисовичем. Официальный сайт игры: https://github.com/ivangolubykh/python-snake »’ from tkinter import * from enum import Enum import time import random class python_snake: # Двигать тело змеюки в текущую сторону на 1 шаг # При этом тело может увеличиться (add=’add’) в размерах или нет def __init__(self, window, canv_x, canv_y, canv_width, canv_height): self.__started = 1 self.__spped = 10 self.__window = window self.__canv_x = canv_x self.__canv_y = canv_y self.canv_width = canv_width self.canv_height = canv_height self.__snake_x = self.canv_width // 2 # Координата старта змеи self.__snake_y = self.canv_height // 2 # Координата старта змеи self.canv = Canvas(self.__window, width=self.canv_width, height=self.canv_height, bg=self.CONST.CANVAS_BGCOLOR.value) self.canv.place(x=self.__canv_x, y=self.__canv_y) self.create_head_food() self.__window.bind(‘<d>’,self.right) self.__window.bind(‘<D>’,self.right) self.__window.bind(‘<Right>’,self.right) self.__window.bind(‘<s>’,self.down) self.__window.bind(‘<S>’,self.down) self.__window.bind(‘<Down>’,self.down) self.__window.bind(‘<a>’,self.left) self.__window.bind(‘<A>’,self.left) self.__window.bind(‘<Left>’,self.left) self.__window.bind(‘<w>’,self.up) self.__window.bind(‘<W>’,self.up) self.__window.bind(‘<Up>’,self.up) self.__window.bind(‘<e>’,self.move) self.__window.bind(‘<q>’,self.quit) self.__window.bind(‘<Destroy>’,self.quit) self.__window.bind(‘<plus>’,self.speed_key) self.__window.bind(‘<minus>’,self.speed_key) self.__window.bind(‘<KP_Add>’,self.speed_key) # Клавиша + на боковой клаве self.__window.bind(‘<KP_Subtract>’,self.speed_key) # Клавиша — на боковой клаве # self.__window.bind(‘<KeyPress>’,self.speed_key) # print(event.keysym) Вычислит нажатую клавишу class CONST(Enum): # Список возможных направлений движения и других констант RIGHT = 1 DOWN = 2 LEFT = 3 UP = 4 SNAKE_HCOLOR = ‘red’ # Цвет головы змейки SNAKE_BCOLOR = ‘green’ # Цвет тела змейки CANVAS_BGCOLOR = ‘#bfcff1’ # Цвет фона холста SNAKE_THICKNESS = 11 # Толщина тела змейки (нечётное число) FOOD_THICKNESS = 15 # Толщина еды (нечётное число) FOOD_COLOR = ‘#aced95’ # Цвет тела еды EXPLOSIVE = 15 # Диаметр взрыва при столкновении змеи с препятствием (нечётное число) EXPLOSIVE_BORD = 10 # толщина контура взрыва при столкновении змеи с препятствием EXPLOSIVE_BCOLOR = ‘#ff9999’ # Цвет тела взрыва EXPLOSIVE_CCOLOR = ‘#881a1a’ # Цвет контура взрыва # обработчики клавиш изменения направления движения: def right(self, event): self.__vector = self.CONST.RIGHT.value def down(self, event): self.__vector = self.CONST.DOWN.value def left(self, event): self.__vector = self.CONST.LEFT.value def up(self, event): self.__vector = self.CONST.UP.value def speed_key(self, event): # print(event.keysym) if event.keysym == ‘KP_Add’ or event.keysym == ‘plus’ : self.speed(‘+’) elif event.keysym == ‘KP_Subtract’ or event.keysym == ‘minus’ : self.speed(‘-‘) def create_head_food(self): rand_vect=random.randint(1,4) if rand_vect == 1: self.__vector = self.CONST.RIGHT.value elif rand_vect == 2: self.__vector = self.CONST.DOWN.value elif rand_vect == 3: self.__vector = self.CONST.LEFT.value else: self.__vector = self.CONST.UP.value self.head = self.element_square(self, self.__snake_x, self.__snake_y, self.CONST.SNAKE_THICKNESS.value, self.CONST.SNAKE_HCOLOR.value) self.food.add(self) self.body = [] self.body.append({‘id’: self.head.draw(), ‘x’: self.__snake_x, ‘y’: self.__snake_y}) self.step(‘add’) self.step(‘add’) self.step(‘add’) self.step(‘add’) def speed(self, way): if way == ‘+’ and self.__spped > 1: self.__spped -= 1 elif way == ‘-‘ and self.__spped < 20: self.__spped += 1 def reload(self): self.quit = ‘n’ self.__started = 1 self.__spped = 10 self.canv.delete(‘all’) del self.body self.body = [] self.create_head_food() self.start() def quit(self, event): # Возможность остановить змейку (пауза) self.quit = ‘y’ def move(self, event): if self.quit != ‘n’: self.start() def start(self): # Бесконечный цикл движения змейки if self.__started == 1: self.quit = ‘n’ i = 0 add = ‘del’ while i == 0: self.step(add) if self.food.eat(self) == 1: add = ‘add’ self.speed(‘+’) elif add == ‘add’: add = ‘del’ if self.bump_wall() == ‘the end’: break if self.bump_body() == ‘the end’: break for x in range(1, (self.__spped + 1) ): time.sleep(0.05) self.__window.update() if self.quit == ‘y’: i = 1 break def bump_wall(self): # Проверка на столкновение со стеной __head_x = self.body[1][‘x’] __head_y = self.body[1][‘y’] if ( (__head_x < ( (self.CONST.SNAKE_THICKNESS.value // 2) + 1 ) ) or (__head_y < ( (self.CONST.SNAKE_THICKNESS.value // 2) + 1 ) ) or (__head_x > ( self.canv_width (self.CONST.SNAKE_THICKNESS.value // 2) + 1 ) ) or (__head_y > ( self.canv_height (self.CONST.SNAKE_THICKNESS.value // 2) + 1 ) ) ): self.explosive() return ‘the end’ else: return 0 def bump_body(self): # Проверка на столкновение с телом змеи __head_x = self.body[1][‘x’] __head_y = self.body[1][‘y’] bump = 0 for i in range(0, (len(self.body) 1) ): if ( (__head_x == self.body[i][‘x’]) and (__head_y == self.body[i][‘y’]) ): self.explosive() bump = ‘the end’ return bump def explosive(self): self.__started = 0 self.canv.create_oval( (self.body[1][‘x’] self.CONST.EXPLOSIVE.value), (self.body[1][‘y’] self.CONST.EXPLOSIVE.value), (self.body[1][‘x’] + self.CONST.EXPLOSIVE.value), (self.body[1][‘y’] + self.CONST.EXPLOSIVE.value), fill=self.CONST.EXPLOSIVE_BCOLOR.value, outline=self.CONST.EXPLOSIVE_CCOLOR.value, width=self.CONST.EXPLOSIVE_BORD.value) def step(self, add): # Двигать тело змеюки в текущую сторону на 1 шаг # При этом тело может увеличиться (add=’add’) в размерах или нет if self.__vector == self.CONST.RIGHT.value: deltax = self.CONST.SNAKE_THICKNESS.value deltay = 0 elif self.__vector == self.CONST.DOWN.value: deltax = 0 deltay = self.CONST.SNAKE_THICKNESS.value elif self.__vector == self.CONST.LEFT.value: deltax = self.CONST.SNAKE_THICKNESS.value deltay = 0 elif self.__vector == self.CONST.UP.value: deltax = 0 deltay = self.CONST.SNAKE_THICKNESS.value self.head.x += deltax self.head.y += deltay self.head = self.element_square(self, self.head.x, self.head.y, self.CONST.SNAKE_THICKNESS.value, self.CONST.SNAKE_HCOLOR.value) self.body.append({‘id’: self.head.draw(), ‘x’: self.head.x, ‘y’: self.head.y}) # Создал новую голову self.canv.itemconfig(self.body[2][‘id’], fill=self.CONST.SNAKE_BCOLOR.value) # Перекрасил старую голову в тело if add != ‘add’: self.canv.delete(self.body[0][‘id’]) self.body.pop(0) class food: def add(self): self.food.x = random.randint(self.CONST.FOOD_THICKNESS.value // 2, self.canv_width self.CONST.FOOD_THICKNESS.value // 2) self.food.y = random.randint(self.CONST.FOOD_THICKNESS.value // 2, self.canv_height self.CONST.FOOD_THICKNESS.value // 2) self.food.body = self.element_square(self, self.food.x, self.food.y, self.CONST.FOOD_THICKNESS.value, self.CONST.FOOD_COLOR.value) self.food.id = self.food.body.draw() def eat(self): head_x = self.body[1][‘x’] head_y = self.body[1][‘y’] eat = 0 if ( (head_x + self.CONST.SNAKE_THICKNESS.value // 2 > (self.food.x self.CONST.FOOD_THICKNESS.value // 2) ) and (head_x self.CONST.SNAKE_THICKNESS.value // 2 < (self.food.x + self.CONST.FOOD_THICKNESS.value // 2) ) and (head_y + self.CONST.SNAKE_THICKNESS.value // 2 > (self.food.y self.CONST.FOOD_THICKNESS.value // 2) ) and (head_y self.CONST.SNAKE_THICKNESS.value // 2 < (self.food.y + self.CONST.FOOD_THICKNESS.value // 2) ) ): self.canv.delete(self.food.id) self.food.add(self) eat = 1 return eat class element_square: # Рисую квадратик со стороной d и центром x,y def __init__(self, self_glob, x, y, d, color): self.self_glob = self_glob self.x = x self.y = y self.d = d self.color = color if (self.d % 2) == 0: self.d +=1 # сторону квадрата делаю нечётной def draw(self): x = self.x (self.d // 2) # координата левой грани квадрата y = self.y (self.d // 2) # координата верхней грани квадрата return self.self_glob.canv.create_rectangle(x, y, x + self.d, y + self.d, fill=self.color, width=2) def main(): image1_data=»’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»’ image2_data=»’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»’ def button_press(a): reload_button[‘image’]=reload_button_img2 snake.reload() def button_unpress(a): reload_button[‘image’]=reload_button_img1 root = Tk() root.title(‘Программа Змейка на питоне в графике’) root.geometry(‘800×600+150+150’) frame = Frame(root, width=740, height=90, bg=‘#f2ffe0’) frame.place(x=30, y=5) text = Label(root, text=»’Игра Змейка написана на Python 3 Голубых Иваном Борисовичем в ноябре 2016 года для тренировки и демонстрации навыков работы с Git и Python 3. Правила: Змейка должна кушать зелёные плоды. При съедании плода, скорость змейки возрастает. Скорость можно отрегулировать вручную клавишами «+» и «-«. Нельзя выползать за границы поля и есть себя. Официальный сайт игры: https://github.com/ivangolubykh/python-snake»’, bg=‘#f2ffe0’, width=79) text.place(x=30, y=10) reload_button_img1=PhotoImage(data = image1_data) reload_button = Label(image=reload_button_img1, bg=‘#f2ffe0’) reload_button.place(x=675, y=13) reload_button_img2=PhotoImage(data = image2_data) reload_button.bind(‘<Button-1>’,button_press) reload_button.bind(‘<ButtonRelease-1>’,button_unpress) snake = python_snake(root, 30, 100, 740, 470) snake.start() root.mainloop() if __name__ == ‘__main__’: main()

Понравилась статья? Поделить с друзьями:
  • Как написать злой смайлик знаками
  • Как написать зимнюю сказку
  • Как написать зимний пейзаж маслом
  • Как написать зимний пейзаж гуашью
  • Как написать зимний пейзаж акварелью