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
 def _remove_walls(self, x1, y1, x2, y2):
     to_remove = []
     for wall in self.level.walls:
         if wall.intersects(Position(x1, y1), Position(x2, y2)):
             to_remove.append(wall)
     for wall in to_remove:
         self.level.walls.remove(wall)
Esempio n. 3
0
 def _segment(self):
     num_segments = round(Position(self.x1, self.y1).distance(Position(self.x2, self.y2)))
     self.segments = []
     for i in range(num_segments):
         self.segments.append(WallSegment((self.x1 + (self.x2 - self.x1) * (i / num_segments),
                                           self.y1 + (self.y2 - self.y1) * (i / num_segments)),
                                          (self.x1 + (self.x2 - self.x1) * ((i+1) / num_segments),
                                           self.y1 + (self.y2 - self.y1) * ((i+1) / num_segments)),
                                          self))
Esempio n. 4
0
 def mousedown(self, x, y):
     door = self._get_door(x, y)
     button = self._get_button(x, y)
     if door and button:
         if door.center().distance(Position(x, y)) < button.distance(
                 Position(x, y)):
             self.door = door
         else:
             self.button = button
     elif door:
         self.door = door
     elif button:
         self.button = button
Esempio n. 5
0
 def mousemove(self, x, y):
     if self.door:
         self.canvas.redraw()
         button = self._get_button(x, y)
         if button:
             self._draw_trigger(self.door.center(), button)
         else:
             self._draw_trigger(self.door.center(), Position(x, y))
     elif self.button:
         self.canvas.redraw()
         door = self._get_door(x, y)
         if door:
             self._draw_trigger(self.button, door.center())
         else:
             self._draw_trigger(self.button, Position(x, y))
Esempio n. 6
0
 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)
Esempio n. 7
0
    def add_neighbor(self, node, direction, pos, next_pos):
        next_node = self.nodes.get(next_pos)
        x1, y1 = pos
        x2, y2 = next_pos
        p1 = Position(x1 + 0.5, y1 + 0.5)
        p2 = Position(x2 + 0.5, y2 + 0.5)
        for wall in self.level.possible_intersections(p1, p2):
            intersection = wall.intersects(p1, p2)
            # If we've already explored this node, add the appropriate connections.
            # If not, then if there's no wall between the two nodes, add it to our frontier.
            # If there is a wall, leave it to be discovered (and potentially connected)
            # later.
            if intersection:
                # Need special handling so we can determine which segments to create portals on
                if isinstance(wall, PortalWall):
                    for segment in wall.segments:
                        if segment.intersects(p1, p2):
                            node.add_neighbor(direction, None, segment,
                                              intersection)
                elif isinstance(wall, Wall):
                    node.add_neighbor(direction, None, wall, intersection)
                elif next_node:
                    if isinstance(wall, Door) or isinstance(wall, Grill):
                        path_from = True
                        path_to = True
                    elif isinstance(wall, Ledge) and intersection > 0:
                        path_from = True
                        path_to = False
                    elif isinstance(wall, Ledge) and intersection < 0:
                        path_from = False
                        path_to = True

                    node.add_neighbor(direction,
                                      (next_node if path_from else None), wall,
                                      intersection)
                    next_node.add_neighbor((direction + 2) % 4,
                                           (node if path_to else None), wall,
                                           -intersection)
                return True

        # No wall intersection
        if next_node:
            node.add_neighbor(direction, next_node, None, 0)
            next_node.add_neighbor((direction + 2) % 4, node, None, 0)
            return True
        else:
            return False
Esempio n. 8
0
 def _remove_entities(self, x, y):
     to_remove = []
     for e in self.level.entities:
         if e.x is not None and e.y is not None and e.distance(
                 Position(x, y)) < 0.2:
             to_remove.append(e)
     for e in to_remove:
         self.level.remove_entity(e)
Esempio n. 9
0
    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)
Esempio n. 10
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. 11
0
 def center(self):
     min_x = self.nodes[0].x
     max_x = self.nodes[0].x
     min_y = self.nodes[0].y
     max_y = self.nodes[0].y
     for node in self.nodes:
         min_x = min(min_x, node.x)
         max_x = max(max_x, node.x)
         min_y = min(min_y, node.y)
         max_y = max(max_y, node.y)
     return Position((min_x + max_x) * 0.5, (min_y + max_y) * 0.5)
Esempio n. 12
0
 def __init__(self, x, y, name=None):
     objects.Button.__init__(self, name)
     Position.__init__(self, x, y)
     self.objects = set()
Esempio n. 13
0
 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)
Esempio n. 14
0
 def mousedown(self, x, y):
     self.pos1 = Position(round(x), round(y))
Esempio n. 15
0
 def mousedown(self, x, y):
     self.pos1 = Position(round(x * 2) * 0.5, round(y * 2) * 0.5)
Esempio n. 16
0
 def _get_door(self, x, y):
     for wall in self.level.walls:
         if isinstance(
                 wall,
                 Door) and wall.center().distance(Position(x, y)) < 0.5:
             return wall
Esempio n. 17
0
 def _get_button(self, x, y):
     for entity in self.level.entities:
         if isinstance(entity,
                       Button) and entity.distance(Position(x, y)) < 0.5:
             return entity
Esempio n. 18
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
Esempio n. 19
0
 def mousedown(self, x, y):
     p = Position(round(x * 2) * 0.5, round(y * 2) * 0.5)
     self.level.goal.move_to(p)
     self.canvas.redraw()
Esempio n. 20
0
 def _pan_start(self, event):
     self.pan_from = Position(event.x, event.y)
     self.pan_orig = Position(*self.pan_offset.pos())
Esempio n. 21
0
 def __init__(self, x, y, name=None):
     Position.__init__(self, x, y)
     Object.__init__(self, name)