""" https://stepik.org/lesson/468998/step/7?unit=459819 3: "Квадрат в самом начале стоит в правом нижнем углу и двигается при нажатии стрелок только вверх или влево" 4: "Квадрат двигается при нажатии стрелок но не может выйти за пределы экрана" Библиотека graph: https://kpolyakov.spb.ru/download/pygraph.zip """ import graph from graph import * from typing import NamedTuple import types consts = types.SimpleNamespace() consts.VK_Q = 81 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 __sub__(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 data = {"delta": Point(0, 0), "callbacks": []} 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_up_left(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(260, 260) brushColor("Blue") rectangle(*start_pos, *(start_pos + scene_sz)) brushColor("Yellow") box_pos = start_pos + box_offset obj = rectangle(*box_pos, *(box_pos + box_sz)) def update(): delta = data["delta"] coord = Point(xCoord(obj), yCoord(obj)) - start_pos if ( coord.x + delta.x < 0 or coord.x + box_sz.x + delta.x > scene_sz.x or coord.y + delta.y < 0 or coord.y + box_sz.y + delta.y > scene_sz.y or delta.x > 0 or delta.y > 0 ): return moveObjectBy(obj, delta.x, delta.y) data.setdefault("callbacks", []).append(update) def square_free_move(start_pos=None): start_pos = start_pos or Point(0, 0) make_title(4, "Квадрат двигается свободно", 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(130, 130) brushColor("Blue") rectangle(*start_pos, *(start_pos + scene_sz)) brushColor("Yellow") box_pos = start_pos + box_offset obj = rectangle(*box_pos, *(box_pos + box_sz)) def update(): delta = data["delta"] coord = Point(xCoord(obj), yCoord(obj)) - start_pos if ( coord.x + delta.x < 0 or coord.x + box_sz.x + delta.x > scene_sz.x or coord.y + delta.y < 0 or coord.y + box_sz.y + delta.y > scene_sz.y ): return moveObjectBy(obj, delta.x, delta.y) data.setdefault("callbacks", []).append(update) def keyPressed(event): match event.keycode: case graph.VK_LEFT: data["delta"] = Point(-5, 0) case graph.VK_RIGHT: data["delta"] = Point(5, 0) case graph.VK_UP: data["delta"] = Point(0, -5) case graph.VK_DOWN: data["delta"] = Point(0, 5) case consts.VK_Q | graph.VK_ESCAPE: killTimer(data["update_timer"]) close() def update(): for callback in data["callbacks"]: callback() data["delta"] = Point(0, 0) def main(): canvasSize(460, 800) square_up_left() square_free_move(Point(0, 350)) data["update_timer"] = onTimer(update, 40) onKey(keyPressed) run() main()