""" https://stepik.org/lesson/468998/step/8?unit=459819 Два квадрата, один управляется стрелками, другой клавишами WASD Для выхода нужно нажать Q или Esc Библиотека 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 consts.VK_W = 87 consts.VK_A = 65 consts.VK_S = 83 consts.VK_D = 68 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_a": Point(0, 0), "delta_b": Point(0, 0), "callbacks": []} def square_a_on_scene(start_pos=None): start_pos = start_pos or Point(0, 0) scene_sz = Point(300, 300) box_sz = Point(40, 40) box_offset = Point(80, 80) 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_a"] 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 square_b(start_pos=None): start_pos = start_pos or Point(0, 0) scene_sz = Point(300, 300) box_sz = Point(40, 40) box_offset = Point(200, 200) brushColor("Yellow") box_pos = start_pos + box_offset obj = rectangle(*box_pos, *(box_pos + box_sz)) def update(): delta = data["delta_b"] 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_a"] = Point(-5, 0) case graph.VK_RIGHT: data["delta_a"] = Point(5, 0) case graph.VK_UP: data["delta_a"] = Point(0, -5) case graph.VK_DOWN: data["delta_a"] = Point(0, 5) case consts.VK_A: data["delta_b"] = Point(-5, 0) case consts.VK_D: data["delta_b"] = Point(5, 0) case consts.VK_W: data["delta_b"] = Point(0, -5) case consts.VK_S: data["delta_b"] = 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_a"] = Point(0, 0) data["delta_b"] = Point(0, 0) def main(): canvasSize(300, 300) square_a_on_scene() square_b() data["update_timer"] = onTimer(update, 40) onKey(keyPressed) run() main()