Как нарисовать змейку в paint

Обновлено: 05.07.2024

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

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


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


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


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


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


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

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


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


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


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

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


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


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


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


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

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

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

Читайте также: