129 lines
4.1 KiB
Python
129 lines
4.1 KiB
Python
"""
|
||
Анимация квадратов
|
||
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()
|