py_stepik/mod_graph/anim1.py
2024-03-23 22:57:35 +03:00

129 lines
4.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Анимация квадратов
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):
"""
Вспомогательный класс для упрощения работы с координатами (сложение)
"""
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)
state = [*square_left_to_right(), *two_squares(Point(0, 350))]
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()