Как написать игру змейка на python

Я точно знаю, что в детстве вы все играли в игру «Змейка» и, конечно, всегда хотели выиграть. Будучи детьми, мы все любили искать баги в игре, чтобы никогда не видеть сообщение 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

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

Сегодня мы напишем игру змейка на 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

На самом деле строчек кода с логикой игры будет гораздо меньше, добрую половину скрипта занимает подготовка игрового поля, рисование новорождённой змеи, назначение клавиш управления и ещё парочка мелочей. Публикация может быть полезна для таких же начинающих, как и я сам. И да, в коде могут быть ошибки, которые я в настоящий момент не вижу в силу своего небольшого опыта программирования, заканчивающегося на прочтении Марка Лутца и пока ещё недописанном телеграм боте, но змейка работает исправно и делает всё, что было задумано. Писать буду с использованием модуля 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 или Pygame. Это один из лучших проектов для начинающих, который каждый начинающий программист должен принять как вызов. Научиться создавать видеоигры довольно интересно и весело.

Мы будем использовать Pygame для создания этой игры . Pygame — это библиотека с открытым исходным кодом, предназначенная для создания видеоигр. Она имеет встроенные графические и звуковые библиотеки.

Установка
Чтобы установить Pygame, вам нужно открыть терминал или командную строку и ввести следующую команду:

pip install pygame

Шаг 1: Сначала мы импортируем необходимые библиотеки.

После этого мы определяем ширину и высоту окна, в котором будет проходить игра.
И определим цвет в формате RGB, который мы будем использовать в нашей игре для отображения текста.

# importing libraries
import pygame
import time
import random
 
snake_speed = 15
 
# Window size
window_x = 720
window_y = 480
 
# defining colors
black = pygame.Color(0, 0, 0)
white = pygame.Color(255, 255, 255)
red = pygame.Color(255, 0, 0)
green = pygame.Color(0, 255, 0)
blue = pygame.Color(0, 0, 255)

Шаг 2: После импорта библиотек нам нужно инициализировать Pygame с помощью метода pygame.init().

Создадим игровое окно, используя ширину и высоту, определенные на предыдущем шаге.
Здесь pygame.time.Clock() будет использоваться дальше в основной логике игры для изменения скорости змейки.

# Initialising pygame
pygame.init()
 
# Initialise game window
pygame.display.set_caption('GeeksforGeeks Snakes')
game_window = pygame.display.set_mode((window_x, window_y))
 
# FPS (frames per second) controller
fps = pygame.time.Clock()

Шаг 3: Инициализируем положение змейки и ее размер.

После инициализации положения змейки инициализируем положение фруктов случайным образом в любом месте заданной высоты и ширины.
Установив направление ВПРАВО, мы гарантируем, что всякий раз, когда пользователь запускает программу/игру, змейка должна двигаться вправо к экрану.

# defining snake default position
snake_position = [100, 50]
 
# defining first 4 blocks of snake
# body
snake_body = [  [100, 50],
                [90, 50],
                [80, 50],
                [70, 50]
            ]
# fruit position
fruit_position = [random.randrange(1, (window_x//10)) * 10,
                  random.randrange(1, (window_y//10)) * 10]
fruit_spawn = True
 
# setting default snake direction
# towards right
direction = 'RIGHT'
change_to = direction

Шаг 4: Создадим функцию для отображения счета игрока.

В этой функции, во-первых, мы создаем объект шрифта.
Затем мы используем рендеринг для создания фоновой поверхности, которую мы будем менять при каждом обновлении нашей игры.
Создадим прямоугольный объект для объекта текстовой поверхности (где текст будет обновляться)
Затем мы отобразим счет, используя blit. blit , который принимает два аргумента screen.blit(background,(x,y))

# initial score
score = 0
 
# displaying Score function
def show_score(choice, color, font, size):
   
    # creating font object score_font
    score_font = pygame.font.SysFont(font, size)
     
    # create the display surface object
    # score_surface
    score_surface = score_font.render('Score : ' + str(score), True, color)
     
    # create a rectangular object for the
    # text surface object
    score_rect = score_surface.get_rect()
     
    # displaying text
    game_window.blit(score_surface, score_rect)

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

В первой строке мы создаем объект шрифта для отображения результатов.
Затем мы создадим текстовые поверхности для рендеринга партитуры.
После этого мы устанавим положение текста в середине игровой области.
Отобразим результаты с помощью blit и обновите счет, обновив поверхность с помощью flip().
Мы используем sleep(2), чтобы подождать 2 секунды, прежде чем закрыть окно с помощью quit().

# game over function
def game_over():
   
    # creating font object my_font
    my_font = pygame.font.SysFont('times new roman', 50)
     
    # creating a text surface on which text
    # will be drawn
    game_over_surface = my_font.render('Your Score is : ' + str(score), True, red)
     
    # create a rectangular object for the text
    # surface object
    game_over_rect = game_over_surface.get_rect()
     
    # setting position of the text
    game_over_rect.midtop = (window_x/2, window_y/4)
     
    # blit will draw the text on screen
    game_window.blit(game_over_surface, game_over_rect)
    pygame.display.flip()
     
    # after 2 seconds we will quit the
    # program
    time.sleep(2)
     
    # deactivating pygame library
    pygame.quit()
     
    # quit the program
    quit()

Шаг 6: Теперь мы создадим нашу основную функцию, которая будет делать следующие вещи:

Мы будем проверять ключи, которые будут отвечать за движение змейки, а затем создадим специальное условие, при котором змея не должна двигаться в противоположном направлении мгновенно.
После этого, если змейка и фрукт столкнутся, мы увеличим счет на 10, и новый фрукт будет инициализоравн.
После этого проверяем, ударилась змейка о стену или нет. Если змейка ударится о стену, мы вызовем функцию Game Over.
Если змейка ударит себя так же будет вызвана функция окончания Game Over.
И, наконец, мы будем отображать результаты с помощью созданной ранее функции show_score.

# Main Function
while True:
   
    # handling key events
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                change_to = 'UP'
            if event.key == pygame.K_DOWN:
                change_to = 'DOWN'
            if event.key == pygame.K_LEFT:
                change_to = 'LEFT'
            if event.key == pygame.K_RIGHT:
                change_to = 'RIGHT'
 
    # If two keys pressed simultaneously
    # we don't want snake to move into two directions
    # simultaneously
    if change_to == 'UP' and direction != 'DOWN':
        direction = 'UP'
    if change_to == 'DOWN' and direction != 'UP':
        direction = 'DOWN'
    if change_to == 'LEFT' and direction != 'RIGHT':
        direction = 'LEFT'
    if change_to == 'RIGHT' and direction != 'LEFT':
        direction = 'RIGHT'
 
    # Moving the snake
    if direction == 'UP':
        snake_position[1] -= 10
    if direction == 'DOWN':
        snake_position[1] += 10
    if direction == 'LEFT':
        snake_position[0] -= 10
    if direction == 'RIGHT':
        snake_position[0] += 10
 
    # Snake body growing mechanism
    # if fruits and snakes collide then scores will be
    # incremented by 10
    snake_body.insert(0, list(snake_position))
    if snake_position[0] == fruit_position[0] and snake_position[1] == fruit_position[1]:
        score += 10
        fruit_spawn = False
    else:
        snake_body.pop()
         
    if not fruit_spawn:
        fruit_position = [random.randrange(1, (window_x//10)) * 10,
                          random.randrange(1, (window_y//10)) * 10]
         
    fruit_spawn = True
    game_window.fill(black)
     
    for pos in snake_body:
        pygame.draw.rect(game_window, green, pygame.Rect(
          pos[0], pos[1], 10, 10))
         
    pygame.draw.rect(game_window, white, pygame.Rect(
      fruit_position[0], fruit_position[1], 10, 10))
 
    # Game Over conditions
    if snake_position[0] < 0 or snake_position[0] > window_x-10:
        game_over()
    if snake_position[1] < 0 or snake_position[1] > window_y-10:
        game_over()
     
    # Touching the snake body
    for block in snake_body[1:]:
        if snake_position[0] == block[0] and snake_position[1] == block[1]:
            game_over()
     
    # displaying score countinuously
    show_score(1, white, 'times new roman', 20)
     
    # Refresh game screen
    pygame.display.update()
 
    # Frame Per Second /Refresh Rate
    fps.tick(snake_speed)

Просмотры: 3 234

import pygame

import time

import random

snake_speed = 15

window_x = 720

window_y = 480

black = pygame.Color(0, 0, 0)

white = pygame.Color(255, 255, 255)

red = pygame.Color(255, 0, 0)

green = pygame.Color(0, 255, 0)

blue = pygame.Color(0, 0, 255)

pygame.init()

pygame.display.set_caption('GeeksforGeeks Snakes')

game_window = pygame.display.set_mode((window_x, window_y))

fps = pygame.time.Clock()

snake_position = [100, 50]

snake_body = [[100, 50],

              [90, 50],

              [80, 50],

              [70, 50]

              ]

fruit_position = [random.randrange(1, (window_x//10)) * 10,

                  random.randrange(1, (window_y//10)) * 10]

fruit_spawn = True

direction = 'RIGHT'

change_to = direction

score = 0

def show_score(choice, color, font, size):

    score_font = pygame.font.SysFont(font, size)

    score_surface = score_font.render('Score : ' + str(score), True, color)

    score_rect = score_surface.get_rect()

    game_window.blit(score_surface, score_rect)

def game_over():

    my_font = pygame.font.SysFont('times new roman', 50)

    game_over_surface = my_font.render(

        'Your Score is : ' + str(score), True, red)

    game_over_rect = game_over_surface.get_rect()

    game_over_rect.midtop = (window_x/2, window_y/4)

    game_window.blit(game_over_surface, game_over_rect)

    pygame.display.flip()

    time.sleep(2)

    pygame.quit()

    quit()

while True:

    for event in pygame.event.get():

        if event.type == pygame.KEYDOWN:

            if event.key == pygame.K_UP:

                change_to = 'UP'

            if event.key == pygame.K_DOWN:

                change_to = 'DOWN'

            if event.key == pygame.K_LEFT:

                change_to = 'LEFT'

            if event.key == pygame.K_RIGHT:

                change_to = 'RIGHT'

    if change_to == 'UP' and direction != 'DOWN':

        direction = 'UP'

    if change_to == 'DOWN' and direction != 'UP':

        direction = 'DOWN'

    if change_to == 'LEFT' and direction != 'RIGHT':

        direction = 'LEFT'

    if change_to == 'RIGHT' and direction != 'LEFT':

        direction = 'RIGHT'

    if direction == 'UP':

        snake_position[1] -= 10

    if direction == 'DOWN':

        snake_position[1] += 10

    if direction == 'LEFT':

        snake_position[0] -= 10

    if direction == 'RIGHT':

        snake_position[0] += 10

    snake_body.insert(0, list(snake_position))

    if snake_position[0] == fruit_position[0] and snake_position[1] == fruit_position[1]:

        score += 10

        fruit_spawn = False

    else:

        snake_body.pop()

    if not fruit_spawn:

        fruit_position = [random.randrange(1, (window_x//10)) * 10,

                          random.randrange(1, (window_y//10)) * 10]

    fruit_spawn = True

    game_window.fill(black)

    for pos in snake_body:

        pygame.draw.rect(game_window, green,

                         pygame.Rect(pos[0], pos[1], 10, 10))

    pygame.draw.rect(game_window, white, pygame.Rect(

        fruit_position[0], fruit_position[1], 10, 10))

    if snake_position[0] < 0 or snake_position[0] > window_x-10:

        game_over()

    if snake_position[1] < 0 or snake_position[1] > window_y-10:

        game_over()

    for block in snake_body[1:]:

        if snake_position[0] == block[0] and snake_position[1] == block[1]:

            game_over()

    show_score(1, white, 'times new roman', 20)

    pygame.display.update()

    fps.tick(snake_speed)

В этой статье мы напишем игру змейка на 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: Разработка игры "Змейка"

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

В этой статье я расскажу вам, как придумать простую игру-змейку, которую будет легко разработать даже новичку в Python.

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

Другой способ – это использование библиотеки turtle.

Этот модуль поставляется с предустановленным Python и предоставляет пользователям виртуальный холст для создания фигур и изображений.

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

В дополнение к этому модулю мы также будем использовать два других модуля, а именно;

  • Модуль Time – Этот метод позволит нам отслеживать количество секунд, прошедших с предыдущего момента времени.
  • Модуль Random – он генерирует числа случайным образом в Python.
  • Другие основные инструменты, которые вам понадобятся, включают текстовый редактор по вашему выбору. В этой статье я буду использовать VSCode. Конечно, вам нужно будет установить Python 3 на вашу машину, если у вас его еще нет

Это должно быть весело!

Как работает игра “Змейка

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

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

Если змея врежется в блок или в саму себя, игрок проиграет игру.

Для реализации этой игры мы выполним следующие шаги.

  • Импортируем в нашу программу предустановленные модули (turtle, time, и random).
  • Создание экрана игры с помощью модуля turtle.
  • Установка клавиш для направления движения змейки по экрану.
  • Реализация игрового процесса.

Создайте файл snakegame.py, в который мы добавим код реализации.

Импортирование модулей

В этой части кода мы импортируем модули turtle, time и random, которые по умолчанию предустановлены в Python.

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

Для вычисления времени задержки здесь используется модуль time.

Добавьте следующий фрагмент кода в ваш файл snakegame.py.

import turtle
import random
import time

player_score = 0
highest_score = 0
delay_time = 0.1

Создание экрана игры

Модуль turtle, который мы импортируем здесь, позволит нам создать виртуальный холст, который будет экраном окна игры.

Отсюда мы можем создать тело змеи и еду, которую она будет собирать.

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

Добавьте этот код в файл Python.

Понравилась статья? Поделить с друзьями:
  • Как написать игру для телеграм
  • Как написать игру для иос
  • Как написать игру для андроид на java
  • Как написать игру для айфона
  • Как написать игру для zx spectrum скачать