py_stepik/mod_graph/anim1.py

129 lines
4.1 KiB
Python
Raw Permalink Normal View History

2024-03-14 13:54:52 +00:00
"""
Анимация квадратов
https://stepik.org/lesson/468998/step/4?unit=459819
3: "Квадрат двигается справа налево"
4: "Два квадрата двигаются в противоположных направлениях"
Библиотека graph: https://kpolyakov.spb.ru/download/pygraph.zip
"""
from graph import *
from typing import NamedTuple
class Point(NamedTuple):
"""
Вспомогательный класс для упрощения работы с координатами (сложение)
"""
2024-03-23 19:57:35 +00:00
2024-03-14 13:54:52 +00:00
x: int | float
y: int | float
def __add__(self, other):
if isinstance(other, self.__class__):
return self.__class__(self.x + other.x, self.y + other.y)
if isinstance(other, (int, float)):
return self.__class__(self.x + other, self.y + other)
return NotImplemented
def make_title(n, name, start, font=("Arial", 15), n_color="indigo"):
pos = Point(10, 20) + start
n_width = Point(35, 0)
l1 = label(f"«{n}»", *pos, font=font, foreground=n_color)
l2 = label(f": {name}", *(pos + n_width), font=font)
return l1, l2
def square_left_to_right(start_pos=None):
start_pos = start_pos or Point(0, 0)
make_title(3, "Квадрат двигается справа налево", start_pos)
title_height = Point(0, 60)
start_pos = start_pos + title_height
scene_sz = Point(300, 300)
box_sz = Point(40, 40)
box_offset = Point(220, 5)
brushColor("Blue")
rectangle(*start_pos, *(start_pos + scene_sz)) # Размер фона
brushColor("Yellow")
obj = rectangle(
*(start_pos + box_offset), *(start_pos + box_offset + box_sz)
) # Создаем объект, который у нас в виде прямоугольника
data = {"done": False} # состояние объекта для контроля таймера из вне функции
def update(): # Создаем процедуру, которая отвечает за анимацию
# Она будет перемещать объект obj по оси x на -5 по оси y на 0 пикселей
moveObjectBy(obj, -5, 0)
if xCoord(obj) <= 1: # Если x координата меньше 1
killTimer(timer)
data["done"] = True
timer = onTimer(update, 40) # Каждые 50 мс будет запускаться процедура update
return (data,)
def two_squares(start_pos=None):
start_pos = start_pos or Point(0, 0)
make_title(4, "Два квадрата двигаются в\nпротивоположных направлениях", start_pos)
title_height = Point(0, 90)
start_pos = start_pos + title_height
scene_sz = Point(300, 300)
box_sz = Point(40, 40)
box1_offset = Point(220, 5)
box2_offset = Point(0, 250)
brushColor("Blue")
rectangle(*start_pos, *(start_pos + scene_sz))
brushColor("Yellow")
box1 = rectangle(*(start_pos + box1_offset), *(start_pos + box1_offset + box_sz))
box2 = rectangle(*(start_pos + box2_offset), *(start_pos + box2_offset + box_sz))
timer1 = None
timer2 = None
data1 = {"done": False}
data2 = {"done": False}
def update_box1():
moveObjectBy(box1, -5, 0)
if xCoord(box1) <= 1:
killTimer(timer1)
data1["done"] = True
def update_box2():
moveObjectBy(box2, 5, 0)
if xCoord(box2) >= scene_sz.x - box_sz.x:
killTimer(timer2)
data2["done"] = True
timer1 = onTimer(update_box1, 40)
timer2 = onTimer(update_box2, 40)
return data1, data2
def main():
canvasSize(400, 800)
2024-03-23 19:57:35 +00:00
state = [*square_left_to_right(), *two_squares(Point(0, 350))]
2024-03-14 13:54:52 +00:00
watch_timer = None
# выход по завершении всех анимаций
def watch_done():
if all(x["done"] for x in state):
killTimer(watch_timer)
close()
watch_timer = onTimer(watch_done, 6000)
run()
main()