Снегопад из снежинок на Python с помощью Черепашки
В прошлом году мы, используя команду .shape(), меняли внешний вид Черепашки на снежинку. Сегодня мы из таких Черепашек сделаем снегопад.
Для начала импортируем модули turtle и random. Теперь создадим экземпляр класса Screen(), чтобы можно было управлять настройками окна и внешним видом черепашки. Через метод setup() зададим размер окна в 800px в ширину и 600px в высоту.
import turtle import random screen = turtle.Screen() screen.setup(800, 600) screen.tracer(2) points = ((0.0, 0.0), (100.0, 0.0), (100.0, 0.0), (125.0, 43.3012701892), (125.0, 43.3012701892), (150.980762114, 28.3012701892), (150.980762114, 28.3012701892), (134.480762114, -0.277568135665), (134.480762114, -0.277568135665), (184.480762114, -0.277568135665), (184.480762114, -0.277568135665), (184.480762114, -30.2775681357), (184.480762114, -30.2775681357), (134.480762114, -30.2775681357), (134.480762114, -30.2775681357), (150.980762114, -58.8564064606), (150.980762114, -58.8564064606), (125.0, -73.8564064606), (125.0, -73.8564064606), (100.0, -30.5551362713), (100.0, -30.5551362713), (0.0, -30.5551362713), (0.0, -30.5551362713), (50.0, -117.15767665), (50.0, -117.15767665), (100.0, -117.15767665), (100.0, -117.15767665), (100.0, -147.15767665), (100.0, -147.15767665), (67.0, -147.15767665), (67.0, -147.15767665), (92.0, -190.458946839), (92.0, -190.458946839), (66.0192378865, -205.458946839), (66.0192378865, -205.458946839), (41.0192378865, -162.15767665), (41.0192378865, -162.15767665), (24.5192378865, -190.736514975), (24.5192378865, -190.736514975), (-1.46152422707, -175.736514975), (-1.46152422707, -175.736514975), (23.5384757729, -132.435244785), (23.5384757729, -132.435244785), (-26.4615242271, -45.832704407), (-26.4615242271, -45.832704407), (-76.4615242271, -132.435244785), (-76.4615242271, -132.435244785), (-51.4615242271, -175.736514975), (-51.4615242271, -175.736514975), (-77.4422863406, -190.736514975), (-77.4422863406, -190.736514975), (-93.9422863406, -162.15767665), (-93.9422863406, -162.15767665), (-118.942286341, -205.458946839), (-118.942286341, -205.458946839), (-144.923048454, -190.458946839), (-144.923048454, -190.458946839), (-119.923048454, -147.15767665), (-119.923048454, -147.15767665), (-152.923048454, -147.15767665), (-152.923048454, -147.15767665), (-152.923048454, -117.15767665), (-152.923048454, -117.15767665), (-102.923048454, -117.15767665), (-102.923048454, -117.15767665), (-52.9230484541, -30.5551362713), (-52.9230484541, -30.5551362713), (-152.923048454, -30.5551362713), (-152.923048454, -30.5551362713), (-177.923048454, -73.8564064606), (-177.923048454, -73.8564064606), (-203.903810568, -58.8564064606), (-203.903810568, -58.8564064606), (-187.403810568, -30.2775681357), (-187.403810568, -30.2775681357), (-237.403810568, -30.2775681357), (-237.403810568, -30.2775681357), (-237.403810568, -0.277568135664), (-237.403810568, -0.277568135664), (-187.403810568, -0.277568135664), (-187.403810568, -0.277568135664), (-203.903810568, 28.3012701892), (-203.903810568, 28.3012701892), (-177.923048454, 43.3012701892), (-177.923048454, 43.3012701892), (-152.923048454, 1.06581410364e-13), (-152.923048454, 1.06581410364e-13), (-52.9230484541, 1.06581410364e-13), (-52.9230484541, 1.06581410364e-13), (-102.923048454, 86.6025403784), (-102.923048454, 86.6025403784), (-152.923048454, 86.6025403784), (-152.923048454, 86.6025403784), (-152.923048454, 116.602540378), (-152.923048454, 116.602540378), (-119.923048454, 116.602540378), (-119.923048454, 116.602540378), (-144.923048454, 159.903810568), (-144.923048454, 159.903810568), (-118.942286341, 174.903810568), (-118.942286341, 174.903810568), (-93.9422863406, 131.602540378), (-93.9422863406, 131.602540378), (-77.4422863406, 160.181378703), (-77.4422863406, 160.181378703), (-51.4615242271, 145.181378703), (-51.4615242271, 145.181378703), (-76.4615242271, 101.880108514), (-76.4615242271, 101.880108514), (-26.4615242271, 15.2775681357), (-26.4615242271, 15.2775681357), (23.5384757729, 101.880108514), (23.5384757729, 101.880108514), (-1.46152422707, 145.181378703), (-1.46152422707, 145.181378703), (24.5192378865, 160.181378703), (24.5192378865, 160.181378703), (41.0192378865, 131.602540378), (41.0192378865, 131.602540378), (66.0192378865, 174.903810568), (66.0192378865, 174.903810568), (92.0, 159.903810568), (92.0, 159.903810568), (67.0, 116.602540378), (67.0, 116.602540378), (100.0, 116.602540378), (100.0, 116.602540378), (100.0, 86.6025403784), (100.0, 86.6025403784), (50.0, 86.6025403784), (50.0, 86.6025403784), (0.0, 0.0)) screen.register_shape('snowflake', points)
Я заранее посчитал точки для рисования новой фигуры со снежинкой и поместил их в кортеж points. Затем, используя команду register_shape(), зарегистрировал ее под именем snowflake. У нас появилась вот такая красивая снежинка.
Теперь напишем функцию create_snowflake, которая будет нам создавать новую снежинку по нашим параметрам.
def create_snowflake(first=False): snowflake = turtle.Turtle() snowflake.hideturtle() snowflake.speed(0) snowflake.shape('snowflake') snowflake.turtlesize(.08) snowflake.color('#1f75fe') snowflake.penup() end_y = 900 if first else 320 snowflake.goto(random.randint(-380, 380), random.randint(300, end_y)) snowflake.setheading(270) snowflake.showturtle() return snowflake
Создадим новую снежинку на основе экземпляра класса Turtle. Скроем снежинку командой hideturtle(), чтобы нам не видно было перемещения и расстановки снежинок. Зададим скорость движения равной 0. Укажем форму снежинки и уменьшим размер командой turtlesize() в 0.08 раз. Также зададим синий цвет. После этого поднимем перо командой penup(), чтобы при дальнейшем движении наша черепашка не оставляла за собой след.
Теперь осталось переместить черепашку вверх, за границу окна. Для этого используем команду goto(), а координаты получаем с помощью генератора случайных чисел, используя команду randint(), где передаем два числа. Так как ширина нашего окна в 800px, то видимые координаты по оси X у нас для Черепашки от -400 до 400. Уберем справа и слева по 20px, чтобы избежать эффекта, когда снежинка наполовину скрыта боковой границей окна. Высота нашего окна 600px. Верхняя граница находится в координате 300px по оси Y. Нам необходимо разбросать снежинки в высоту нашего окна, это от 300 до 900. Нужно это для того, чтобы, когда снежинки дойдут до нижней части окна, мы могли их убрать и создать новую в верхней части. Тогда получится эффект сплошного падения снежинок, без разрывов и пробелов.
На последок развернем нашу снежинку "головой" вниз, используя команду setheading() и указав параметр 270 градусов (по умолчанию Черепашка смотрит вправо). Затем покажем снежинку командой showturtle(). И вернем командой return нашу настроенную и установленную снежинку.
Перейдем к основной части программы. Установим количество снежинок через переменную n. Также создадим пустой список showflakes для хранения всех активных снежинок. И с помощью цикла for наполним его снежинками.
n = 25 snowflakes = [] for _ in range(n): snowflakes.append(create_snowflake(first=True)) while True: screen.update() for snowflake in snowflakes: snowflake.forward(random.randint(5, 15)) snowflake.tilt(random.randint(0, 180)) if snowflake.ycor() < -300: snowflake.hideturtle() snowflakes.remove(snowflake) snowflakes.append(create_snowflake())
Затем создадим бесконечный цикл while в котором будем реализовывать движение снежинок. Будем брать из списка snowflakes по снежинке и с помощью команды движения вперед forward передвигать ее на случайное число пикселей (можно использовать фиксированное значение). Для создания эффекта падения с помощью команды tilt будем изменять угол наклона нашей снежинки. Это значение также будем получать случайным образом, поворачивая shape() на 180 градусов.
Теперь необходимо проверить, достигла ли наша снежинка нижней границы окна. У каждой снежинки узнаем ее y координату командой ycor(). И если это значение оказалось меньше -300px, то скроем снежинку, удалим ее из нашего списка снежинок и добавим туда новую, используя ранее написанную функцию.
Но теперь для добавления снежинки достаточно ее поместить чуть выше верхней границы окна. Опять же это делается, чтобы между снежинками не создавалось видимого разрыва. Для этого в самой функции я предусмотрел параметр first, по умолчанию он имеет значение False. В этом случае диапазон генерации y координаты равен от 300 до 320 px. Т.е. следующая снежинка появится чуть выше верней границы окна и тут же начнет падать на нашем холсте.
В итоге получится вот такой результат:
Для создания плавной анимации используем команду screen.tracer(), куда передадим числовое значение. Чем больше значение, тем быстрее снежинки будут у нас падать. При этом не забудем в самом начале цикла while указать команду screen.update() для обновления холста.
import turtle import random screen = turtle.Screen() screen.setup(800, 600) screen.tracer(2) points = ((0.0, 0.0), (100.0, 0.0), (100.0, 0.0), (125.0, 43.3012701892), (125.0, 43.3012701892), (150.980762114, 28.3012701892), (150.980762114, 28.3012701892), (134.480762114, -0.277568135665), (134.480762114, -0.277568135665), (184.480762114, -0.277568135665), (184.480762114, -0.277568135665), (184.480762114, -30.2775681357), (184.480762114, -30.2775681357), (134.480762114, -30.2775681357), (134.480762114, -30.2775681357), (150.980762114, -58.8564064606), (150.980762114, -58.8564064606), (125.0, -73.8564064606), (125.0, -73.8564064606), (100.0, -30.5551362713), (100.0, -30.5551362713), (0.0, -30.5551362713), (0.0, -30.5551362713), (50.0, -117.15767665), (50.0, -117.15767665), (100.0, -117.15767665), (100.0, -117.15767665), (100.0, -147.15767665), (100.0, -147.15767665), (67.0, -147.15767665), (67.0, -147.15767665), (92.0, -190.458946839), (92.0, -190.458946839), (66.0192378865, -205.458946839), (66.0192378865, -205.458946839), (41.0192378865, -162.15767665), (41.0192378865, -162.15767665), (24.5192378865, -190.736514975), (24.5192378865, -190.736514975), (-1.46152422707, -175.736514975), (-1.46152422707, -175.736514975), (23.5384757729, -132.435244785), (23.5384757729, -132.435244785), (-26.4615242271, -45.832704407), (-26.4615242271, -45.832704407), (-76.4615242271, -132.435244785), (-76.4615242271, -132.435244785), (-51.4615242271, -175.736514975), (-51.4615242271, -175.736514975), (-77.4422863406, -190.736514975), (-77.4422863406, -190.736514975), (-93.9422863406, -162.15767665), (-93.9422863406, -162.15767665), (-118.942286341, -205.458946839), (-118.942286341, -205.458946839), (-144.923048454, -190.458946839), (-144.923048454, -190.458946839), (-119.923048454, -147.15767665), (-119.923048454, -147.15767665), (-152.923048454, -147.15767665), (-152.923048454, -147.15767665), (-152.923048454, -117.15767665), (-152.923048454, -117.15767665), (-102.923048454, -117.15767665), (-102.923048454, -117.15767665), (-52.9230484541, -30.5551362713), (-52.9230484541, -30.5551362713), (-152.923048454, -30.5551362713), (-152.923048454, -30.5551362713), (-177.923048454, -73.8564064606), (-177.923048454, -73.8564064606), (-203.903810568, -58.8564064606), (-203.903810568, -58.8564064606), (-187.403810568, -30.2775681357), (-187.403810568, -30.2775681357), (-237.403810568, -30.2775681357), (-237.403810568, -30.2775681357), (-237.403810568, -0.277568135664), (-237.403810568, -0.277568135664), (-187.403810568, -0.277568135664), (-187.403810568, -0.277568135664), (-203.903810568, 28.3012701892), (-203.903810568, 28.3012701892), (-177.923048454, 43.3012701892), (-177.923048454, 43.3012701892), (-152.923048454, 1.06581410364e-13), (-152.923048454, 1.06581410364e-13), (-52.9230484541, 1.06581410364e-13), (-52.9230484541, 1.06581410364e-13), (-102.923048454, 86.6025403784), (-102.923048454, 86.6025403784), (-152.923048454, 86.6025403784), (-152.923048454, 86.6025403784), (-152.923048454, 116.602540378), (-152.923048454, 116.602540378), (-119.923048454, 116.602540378), (-119.923048454, 116.602540378), (-144.923048454, 159.903810568), (-144.923048454, 159.903810568), (-118.942286341, 174.903810568), (-118.942286341, 174.903810568), (-93.9422863406, 131.602540378), (-93.9422863406, 131.602540378), (-77.4422863406, 160.181378703), (-77.4422863406, 160.181378703), (-51.4615242271, 145.181378703), (-51.4615242271, 145.181378703), (-76.4615242271, 101.880108514), (-76.4615242271, 101.880108514), (-26.4615242271, 15.2775681357), (-26.4615242271, 15.2775681357), (23.5384757729, 101.880108514), (23.5384757729, 101.880108514), (-1.46152422707, 145.181378703), (-1.46152422707, 145.181378703), (24.5192378865, 160.181378703), (24.5192378865, 160.181378703), (41.0192378865, 131.602540378), (41.0192378865, 131.602540378), (66.0192378865, 174.903810568), (66.0192378865, 174.903810568), (92.0, 159.903810568), (92.0, 159.903810568), (67.0, 116.602540378), (67.0, 116.602540378), (100.0, 116.602540378), (100.0, 116.602540378), (100.0, 86.6025403784), (100.0, 86.6025403784), (50.0, 86.6025403784), (50.0, 86.6025403784), (0.0, 0.0)) screen.register_shape('snowflake', points) def create_snowflake(first=False): snowflake = turtle.Turtle() snowflake.hideturtle() snowflake.speed(0) snowflake.shape('snowflake') snowflake.turtlesize(.08) snowflake.color('#1f75fe') snowflake.penup() end_y = 900 if first else 320 snowflake.goto(random.randint(-380, 380), random.randint(300, end_y)) snowflake.setheading(270) snowflake.showturtle() return snowflake n = 25 snowflakes = [] for _ in range(n): snowflakes.append(create_snowflake(first=True)) while True: screen.update() for snowflake in snowflakes: snowflake.forward(random.randint(5, 15)) snowflake.tilt(random.randint(0, 180)) if snowflake.ycor() < -300: snowflake.hideturtle() snowflakes.remove(snowflake) snowflakes.append(create_snowflake())