Esempio n. 1
0
class SegmentTool(Tool):
    def setup(self):
        self.pos1 = None

    def mousedown(self, x, y):
        self.pos1 = Position(round(x), round(y))

    def mousemove(self, x, y):
        if self.pos1:
            pos2 = self._closest_position(round(x), round(y))
            self.canvas.redraw()
            if self.pos1.pos() != pos2.pos():
                segment = self._make_segment(self.pos1, pos2)
                segment.draw(self.canvas)

    def mouseup(self, x, y):
        if self.pos1:
            pos2 = self._closest_position(round(x), round(y))
            if self.pos1.pos() != pos2.pos():
                segment = self._make_segment(self.pos1, pos2)
                self.level.walls.append(segment)
            self.canvas.redraw()
        self.pos1 = None

    def _closest_position(self, x, y):
        if abs(x - self.pos1.x) > abs(y - self.pos1.y):
            return Position(x, self.pos1.y)
        else:
            return Position(self.pos1.x, y)

    def _make_segment(self, pos1, pos2):
        raise NotImplementedError
Esempio n. 2
0
class PortalTool(Tool):
    def setup(self):
        self.pos1 = None

    def mousedown(self, x, y):
        self.pos1 = Position(round(x * 2) * 0.5, round(y * 2) * 0.5)

    def mousemove(self, x, y):
        if self.pos1:
            pos2 = self._closest_position(x, y)
            self.canvas.redraw()
            if self.pos1.pos() != pos2.pos():
                portal = self._make_portal(self.pos1, pos2)
                portal.draw(self.canvas)

    def mouseup(self, x, y):
        if self.pos1:
            pos2 = self._closest_position(x, y)
            if self.pos1.pos() != pos2.pos():
                portal = self._make_portal(self.pos1, pos2)
                self.level.add_entity(portal)
            self.canvas.redraw()
        self.pos1 = None

    def _closest_position(self, x, y):
        x = round(x * 2) * 0.5
        y = round(y * 2) * 0.5
        if x == self.pos1.x and y == self.pos1.y:
            return Position(x, y)
        if abs(x - self.pos1.x) > abs(y - self.pos1.y):
            if x > self.pos1.x:
                return Position(self.pos1.x + 1, self.pos1.y)
            else:
                return Position(self.pos1.x - 1, self.pos1.y)
        else:
            if y > self.pos1.y:
                return Position(self.pos1.x, self.pos1.y + 1)
            else:
                return Position(self.pos1.x, self.pos1.y - 1)

    def _make_portal(self, pos1, pos2):
        raise NotImplementedError
Esempio n. 3
0
class LevelCanvas(tk.Canvas):
    def __init__(self, app, level, width, height):
        self.level = level
        self.width = width
        self.height = height
        self.scale = None
        super().__init__(app, width=width, height=height)

        self.pan_from = None
        self.pan_orig = None
        self.pan_offset = Position(0, 0)

        self.calculate_transform()
        self.path_lines = []
        self.bind('<Configure>', self._resize)
        self.bind('<Button-2>', self._pan_start)
        self.bind('<B2-Motion>', self._pan_move)
        self.bind('<ButtonRelease-2>', self._pan_end)

    def set_scale(self, scale):
        self.scale = float(scale)
        self.calculate_transform()
        self.redraw()

    def calculate_transform(self):
        (x_min, y_min, x_max, y_max) = self.level.bounds
        center_x = (x_min + x_max) * 0.5
        center_y = (y_min + y_max) * 0.5

        level_width = x_max - x_min or 20
        level_height = y_max - y_min or 20
        scale = self.scale or min((self.width - 50) / level_width, (self.height - 50) / level_height)

        # A stack of Transforms
        self.transform = [
            Translate(-center_x, -center_y),
            Dilate(scale),
            Translate(self.width * 0.5, self.height * 0.5),
            Translate(self.pan_offset.x, self.pan_offset.y),
        ]
        self.inverse_transform = [t.inverse() for t in reversed(self.transform)]

    def transform_point(self, pos):
        return functools.reduce((lambda p, t: t.apply(p)), self.transform, pos)

    def preimage_point(self, pos):
        return functools.reduce((lambda p, t: t.apply(p)), self.inverse_transform, pos)

    def create_line(self, x1, y1, x2, y2, **options):
        x1_new, y1_new = self.transform_point((x1, y1))
        x2_new, y2_new = self.transform_point((x2, y2))
        return super().create_line(x1_new, y1_new, x2_new, y2_new, **options)

    def create_rectangle(self, x1, y1, x2, y2, **options):
        x1_new, y1_new = self.transform_point((x1, y1))
        x2_new, y2_new = self.transform_point((x2, y2))
        return super().create_rectangle(x1_new, y1_new, x2_new, y2_new, **options)

    def create_oval(self, x1, y1, x2, y2, **options):
        x1_new, y1_new = self.transform_point((x1, y1))
        x2_new, y2_new = self.transform_point((x2, y2))
        return super().create_oval(x1_new, y1_new, x2_new, y2_new, **options)

    def redraw(self):
        self.delete('all')
        self.level.draw(self)

    def _resize(self, event):
        self.width = event.width
        self.height = event.height
        self.calculate_transform()
        self.redraw()

    def _pan_start(self, event):
        self.pan_from = Position(event.x, event.y)
        self.pan_orig = Position(*self.pan_offset.pos())

    def _pan_move(self, event):
        self.pan_offset.x = self.pan_orig.x + event.x - self.pan_from.x
        self.pan_offset.y = self.pan_orig.y + event.y - self.pan_from.y
        self.calculate_transform()
        self.redraw()

    def _pan_end(self, event):
        self._pan_move(event)
        self.pan_from = None
        self.pan_orig = None