コード例 #1
0
    def __init__(self, world):
        self.world = world
        self.player = None  # the focused player, or None to show full world

        # the class instance on which to call on_key_pressed and on_mouse_moved
        self.input_subscriber = None
        # same for draw_background, draw_cells, draw_hud
        self.draw_subscriber = None

        self.win_size = Vec(1000, 1000 * 9 / 16)
        self.screen_center = self.win_size / 2
        self.screen_scale = 1
        self.world_center = Vec(0, 0)
        self.mouse_pos = Vec(0, 0)

        window = Gtk.Window()
        window.set_title('agar.io')
        window.set_default_size(self.win_size.x, self.win_size.y)
        window.connect('delete-event', Gtk.main_quit)

        self.drawing_area = Gtk.DrawingArea()
        window.add(self.drawing_area)

        window.set_events(Gdk.EventMask.POINTER_MOTION_MASK)
        window.connect('key-press-event', self.key_pressed)
        window.connect('motion-notify-event', self.mouse_moved)
        window.connect('button-press-event', self.mouse_pressed)

        self.drawing_area.connect('draw', self.draw)

        window.show_all()
コード例 #2
0
ファイル: draw_hud.py プロジェクト: astumpf/gagar
    def on_draw_hud(self, c, w):
        for i, t in enumerate(self.draw_times):
            c.draw_line(w.win_size - Vec(4 * i - 2, 0),
                        relative=(0, -t * 1000),
                        width=2,
                        color=to_rgba(RED, .3))

        for i, t in enumerate(self.world_times):
            c.draw_line(w.win_size - Vec(4 * i, 0),
                        relative=(0, -t * 1000),
                        width=2,
                        color=to_rgba(YELLOW, .3))

        # 25, 30, 60 FPS marks
        graph_width = 4 * len(self.draw_times)
        for fps, color in ((25, ORANGE), (30, GREEN), (60, BLUE)):
            c.draw_line(w.win_size - Vec(graph_width, 1000 / fps),
                        relative=(graph_width, 0),
                        width=.5,
                        color=to_rgba(color, .3))

        now = time()
        dt = now - self.draw_last
        self.draw_last = now
        self.draw_times.appendleft(dt)
コード例 #3
0
ファイル: window.py プロジェクト: henrylu518/gagar
    def __init__(self, world):
        self.world = world
        self.player = None  # the focused player, or None to show full world

        # the class instance on which to call on_key_pressed and on_mouse_moved
        self.input_subscriber = None
        # same for draw_background, draw_cells, draw_hud
        self.draw_subscriber = None

        self.win_size = Vec(1000, 1000 * 9 / 16)
        self.screen_center = self.win_size / 2
        self.screen_scale = 1
        self.world_center = Vec(0, 0)
        self.mouse_pos = Vec(0, 0)

        window = Gtk.Window()
        window.set_title("agar.io")
        window.set_default_size(self.win_size.x, self.win_size.y)
        window.connect("delete-event", Gtk.main_quit)

        self.drawing_area = Gtk.DrawingArea()
        window.add(self.drawing_area)

        window.set_events(Gdk.EventMask.POINTER_MOTION_MASK)
        window.connect("key-press-event", self.key_pressed)
        window.connect("motion-notify-event", self.mouse_moved)
        window.connect("button-press-event", self.mouse_pressed)

        self.drawing_area.connect("draw", self.draw)

        window.show_all()
コード例 #4
0
ファイル: window.py プロジェクト: astumpf/gagar
    def recalculate(self):
        alloc = self.drawing_area.get_allocation()
        self.win_size.set(alloc.width, alloc.height)
        self.screen_center = self.win_size / 2
        if self.player:  # any client is focused
            # if self.player.is_alive or (self.player.center.x == 0 and self.player.center.y == 0) or not self.player.scale == 1.0: # HACK due to bug: player scale is sometimes wrong (sent by server?) in spectate mode
            window_scale = max(self.win_size.x / 1920, self.win_size.y / 1080)
            new_screen_scale = self.player.scale * window_scale * self.screen_zoom_scale
            self.screen_scale = lerp_smoothing(self.screen_scale,
                                               new_screen_scale, 0.1, 0.0001)

            smoothing_factor = 0.1
            if self.player.is_alive:
                smoothing_factor = 0.3

            self.world_center.x = lerp_smoothing(self.world_center.x,
                                                 self.player.center.x,
                                                 smoothing_factor, 0.01)
            self.world_center.y = lerp_smoothing(self.world_center.y,
                                                 self.player.center.y,
                                                 smoothing_factor, 0.01)

            self.world = self.player.world
        elif self.world.size:
            new_screen_scale = min(
                self.win_size.x / self.world.size.x,
                self.win_size.y / self.world.size.y) * self.screen_zoom_scale
            self.screen_scale = lerp_smoothing(self.screen_scale,
                                               new_screen_scale, 0.1, 0.0001)
            self.world_center = self.world.center
        else:
            # happens when the window gets drawn before the world got updated
            self.screen_scale = self.screen_zoom_scale
            self.world_center = Vec(0, 0)
コード例 #5
0
 def mouse_moved(self, _, event):
     """Called by GTK. Set input_subscriber to handle this."""
     if not self.input_subscriber: return
     self.mouse_pos = Vec(event.x, event.y)
     pos_world = self.screen_to_world_pos(self.mouse_pos)
     self.input_subscriber.on_mouse_moved(pos=self.mouse_pos,
                                          pos_world=pos_world)
コード例 #6
0
ファイル: team_overlay.py プロジェクト: astumpf/gagar
    def on_draw_hud(self, c, w):
        c.draw_text((10, 30), 'Team', align='left', color=WHITE, outline=(BLACK, 2), size=27)

        # draw player position in main view
        for i, player in enumerate(list(self.tagar_client.player_list.values())):
            c.draw_text((10, 60 + TEAM_OVERLAY_PADDING * i), player.nick,
                        align='left', color=WHITE, outline=(BLACK, 2), size=18)

            if player.total_mass > 0:
                mass_color = GRAY
                mass_text = 'Mass: ' + str('%.2f' % player.total_mass)
            else:
                mass_text = 'Dead'
                mass_color = RED

            c.draw_text((10, 75 + TEAM_OVERLAY_PADDING * i), mass_text,
                        align='left', color=mass_color, outline=(BLACK, 2), size=12)

            c.draw_text((10, 88 + TEAM_OVERLAY_PADDING * i), '#' + player.party_token,
                        align='left', color=GRAY, outline=(BLACK, 2), size=12)

            button = Button(90, 75 - 12 + TEAM_OVERLAY_PADDING * i, 50, 25, "JOIN")
            button.id = player
            w.register_button(button)
            c.draw_button(button)

            if self.tagar_client.player.is_alive and player.is_alive:
                # draw lines to team members
                client_pos = w.world_to_screen_pos(w.player.center)
                pos = w.world_to_screen_pos(Vec(player.position_x, player.position_y))
                c.draw_line(client_pos, pos, width=2, color=GREEN)

                # TODO draw names
                text_size = 12
                border_x = border_y = text_size

                if not border_x < pos.x < w.win_size.x-border_x or not border_y < pos.y < w.win_size.x-border_x:
                    side_out = abs(pos.x/pos.y) > w.win_size.x/w.win_size.y
                    alignment = 'left' if pos.x < w.win_size.x/2 else 'right'

                    if side_out and abs(pos.x-client_pos.x) > 0.0:
                        x = min(max(pos.x, border_x), w.win_size.x-border_x)
                        pos.y -= client_pos.y
                        pos.y *= abs((x-client_pos.x)/(pos.x-client_pos.x))
                        pos.y += client_pos.y
                        pos.x = x
                    elif abs(pos.y-client_pos.y) > 0.0:
                        y = min(max(pos.y, border_y), w.win_size.y-border_y)
                        pos.x -= client_pos.x
                        pos.x *= abs((y-client_pos.y)/(pos.y-client_pos.y))
                        pos.x += client_pos.x
                        pos.y = y

                    dist = ((w.player.center.x-player.position_x)**2 + (w.player.center.y-player.position_y)**2)**0.5

                    c.draw_text(pos, "%s (%.1f / %.1f)" % (player.nick, player.total_mass, dist), align=alignment, color=WHITE, outline=(BLACK, 2), size=text_size)
コード例 #7
0
    def draw(c, w, cell, pos=None):
        if cell.is_food or cell.is_ejected_mass:
            return
        text_pos = Vec(pos) if pos else w.world_to_screen_pos(cell.pos)

        # draw cell's mass
        if cell.name:
            text_pos.iadd(Vec(0, (info_size + nick_size(cell, w)) / 2))
        c.draw_text(text_pos, '%i' % cell.mass, align='center', outline=(BLACK, 2), size=info_size)

        # draw needed mass to eat it splitted
        text_pos.iadd(Vec(0, info_size))
        c.draw_text(text_pos, '(%i)' % ((cell.mass*2*1.33)-w.player.total_mass), align='center', outline=(BLACK, 2), size=info_size/1.5)
コード例 #8
0
ファイル: window.py プロジェクト: astumpf/gagar
    def draw_minimap_backgound(self, c, w):
        if w.world.size:
            minimap_w = w.win_size.x / 5
            minimap_size = Vec(minimap_w, minimap_w)
            minimap_scale = minimap_size.x / w.world.size.x
            minimap_offset = w.win_size - minimap_size

            def world_to_map(world_pos):
                pos_from_top_left = world_pos - w.world.top_left
                return minimap_offset + pos_from_top_left * minimap_scale

            # minimap background
            c.fill_rect(minimap_offset,
                        size=minimap_size,
                        color=to_rgba(DARK_GRAY, .8))

            # outline the area visible in window
            c.stroke_rect(world_to_map(w.screen_to_world_pos(Vec(0, 0))),
                          world_to_map(w.screen_to_world_pos(w.win_size)),
                          width=1,
                          color=BLACK)
コード例 #9
0
    def test_visible_area(self):
        player = Player()

        # simple test

        win = WindowMock()

        player.scale = win.screen_scale
        player.world.top_left = win.tl
        player.world.bottom_right = win.br

        ptl, pbr = player.visible_area

        rtl = win.screen_to_world_pos(zero)
        rbr = win.screen_to_world_pos(screen)

        self.assertAlmostEqual(ptl.x, rtl.x)
        self.assertAlmostEqual(ptl.y, rtl.y)
        self.assertAlmostEqual(pbr.x, rbr.x)
        self.assertAlmostEqual(pbr.y, rbr.y)

        # complex test

        win = WindowMock(Vec(123, 234), Vec(-34.5, 45.6))

        player.scale = win.screen_scale = 2.3
        player.world.top_left = win.tl
        player.world.bottom_right = win.br

        ptl, pbr = player.visible_area

        rtl = win.screen_to_world_pos(zero)
        rbr = win.screen_to_world_pos(screen)

        self.assertAlmostEqual(ptl.x, rtl.x)
        self.assertAlmostEqual(ptl.y, rtl.y)
        self.assertAlmostEqual(pbr.x, rbr.x)
        self.assertAlmostEqual(pbr.y, rbr.y)
コード例 #10
0
ファイル: team_overlay.py プロジェクト: astumpf/gagar
    def on_draw_minimap(self, c, w):
        if w.world.size:
            minimap_w = w.win_size.x / 5
            minimap_size = Vec(minimap_w, minimap_w)
            minimap_scale = minimap_size.x / w.world.size.x
            minimap_offset = w.win_size - minimap_size

            def world_to_map(world_pos):
                pos_from_top_left = world_pos - w.world.top_left
                return minimap_offset + pos_from_top_left * minimap_scale

            # draw cells
            cells = self.tagar_client.team_world.cells.copy()
            for cell in cells.values():
                if cell.cid not in w.world.cells:
                    if cell.cid in self.tagar_client.team_cids:
                        c.fill_circle(world_to_map(cell.pos),
                                      cell.size * minimap_scale,
                                      color=to_rgba(cell.color, 0.7))
                    else:
                        alpha = .66 if cell.mass > (self.tagar_client.player.total_mass * 0.66) else 0.33
                        c.stroke_circle(world_to_map(cell.pos),
                                        cell.size * minimap_scale,
                                        color=to_rgba(cell.color, alpha))

            # draw lines to team members
            if self.tagar_client.player.is_alive:
                for i, player in enumerate(list(self.tagar_client.player_list.values())):
                    if player.is_alive:
                        c.draw_line(world_to_map(w.player.center),
                                    world_to_map(Vec(player.position_x, player.position_y)),
                                    width=1, color=GREEN)

            # draw names
            for i, player in enumerate(list(self.tagar_client.player_list.values())):
                if player.is_alive:
                    c.draw_text(world_to_map(Vec(player.position_x, player.position_y)), player.nick,
                                align='center', color=WHITE, outline=(BLACK, 2), size=8)
コード例 #11
0
ファイル: draw_hud.py プロジェクト: astumpf/gagar
    def on_draw_hud(c, w):
        if w.player.is_alive and w.screen_zoom_scale != 1.0:
            window_scale = max(w.win_size.x / 1920, w.win_size.y / 1080)
            screen_scale_no_zoom = w.player.scale * window_scale

            def screen_to_world_pos(screen_pos):
                return (screen_pos - w.screen_center) \
                    .idiv(screen_scale_no_zoom).iadd(w.world_center)

            # outline the area visible in window
            c.stroke_rect(
                w.world_to_screen_pos(screen_to_world_pos(Vec(0, 0))),
                w.world_to_screen_pos(screen_to_world_pos(w.win_size)),
                width=1,
                color=LIGHT_GRAY)
コード例 #12
0
    def on_draw_cells(self, c, w):
        if len(w.player.own_ids) <= 1:
            return  # dead or only one cell, no re-merge time to display

        now = time()
        for cell in w.player.own_cells:
            split_for = now - cell.spawn_time
            # formula by HungryBlob
            ttr = max(30, cell.size // 5) - split_for
            if ttr < 0:
                continue
            pos = w.world_to_screen_pos(cell.pos)
            pos.isub(Vec(0, (info_size + nick_size(cell, w)) / 2))
            c.draw_text(pos, 'TTR %.1fs after %.1fs' % (ttr, split_for),
                        align='center', outline=(BLACK, 2), size=info_size)
コード例 #13
0
ファイル: draw_hud.py プロジェクト: astumpf/gagar
    def on_draw_minimap(c, w):
        if w.world.size:
            minimap_w = w.win_size.x / 5
            minimap_size = Vec(minimap_w, minimap_w)
            minimap_scale = minimap_size.x / w.world.size.x
            minimap_offset = w.win_size - minimap_size

            def world_to_map(world_pos):
                pos_from_top_left = world_pos - w.world.top_left
                return minimap_offset + pos_from_top_left * minimap_scale

            for cell in w.world.cells.values():
                c.stroke_circle(world_to_map(cell.pos),
                                cell.size * minimap_scale,
                                color=to_rgba(cell.color, .8))
コード例 #14
0
 def recalculate(self):
     alloc = self.drawing_area.get_allocation()
     self.win_size.set(alloc.width, alloc.height)
     self.screen_center = self.win_size / 2
     if self.player:  # any client is focused
         window_scale = max(self.win_size.x / 1920, self.win_size.y / 1080)
         self.screen_scale = self.player.scale * window_scale
         self.world_center = self.player.center
         self.world = self.player.world
     elif self.world.size:
         self.screen_scale = min(self.win_size.x / self.world.size.x,
                                 self.win_size.y / self.world.size.y)
         self.world_center = self.world.center
     else:
         # happens when the window gets drawn before the world got updated
         self.screen_scale = 1
         self.world_center = Vec(0, 0)
コード例 #15
0
class WorldViewer(object):
    """
    Draws one world and handles keys/mouse.
    Does not poll for events itself.
    Calls input_subscriber.on_{key_pressed|mouse_moved}() methods on key/mouse input.
    Calls draw_subscriber.on_draw_{background|cells|hud}() methods when drawing.
    """

    INFO_SIZE = 300

    def __init__(self, world):
        self.world = world
        self.player = None  # the focused player, or None to show full world

        # the class instance on which to call on_key_pressed and on_mouse_moved
        self.input_subscriber = None
        # same for draw_background, draw_cells, draw_hud
        self.draw_subscriber = None

        self.win_size = Vec(1000, 1000 * 9 / 16)
        self.screen_center = self.win_size / 2
        self.screen_scale = 1
        self.world_center = Vec(0, 0)
        self.mouse_pos = Vec(0, 0)

        window = Gtk.Window()
        window.set_title('agar.io')
        window.set_default_size(self.win_size.x, self.win_size.y)
        window.connect('delete-event', Gtk.main_quit)

        self.drawing_area = Gtk.DrawingArea()
        window.add(self.drawing_area)

        window.set_events(Gdk.EventMask.POINTER_MOTION_MASK)
        window.connect('key-press-event', self.key_pressed)
        window.connect('motion-notify-event', self.mouse_moved)
        window.connect('button-press-event', self.mouse_pressed)

        self.drawing_area.connect('draw', self.draw)

        window.show_all()

    def focus_player(self, player):
        """Follow this client regarding center and zoom."""
        self.player = player
        self.world = player.world

    def show_full_world(self, world=None):
        """
        Show the full world view instead of one client.
        :param world: optionally update the drawn world
        """
        self.player = None
        if world:
            self.world = world

    def key_pressed(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if not self.input_subscriber: return
        val = event.keyval
        try:
            char = chr(val)
        except ValueError:
            char = ''
        self.input_subscriber.on_key_pressed(val=val, char=char)

    def mouse_moved(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if not self.input_subscriber: return
        self.mouse_pos = Vec(event.x, event.y)
        pos_world = self.screen_to_world_pos(self.mouse_pos)
        self.input_subscriber.on_mouse_moved(pos=self.mouse_pos,
                                             pos_world=pos_world)

    def mouse_pressed(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if not self.input_subscriber: return
        self.input_subscriber.on_mouse_pressed(button=event.button)

    def world_to_screen_pos(self, world_pos):
        return (world_pos - self.world_center) \
            .imul(self.screen_scale).iadd(self.screen_center)

    def screen_to_world_pos(self, screen_pos):
        return (screen_pos - self.screen_center) \
            .idiv(self.screen_scale).iadd(self.world_center)

    def world_to_screen_size(self, world_size):
        return world_size * self.screen_scale

    def recalculate(self):
        alloc = self.drawing_area.get_allocation()
        self.win_size.set(alloc.width, alloc.height)
        self.screen_center = self.win_size / 2
        if self.player:  # any client is focused
            window_scale = max(self.win_size.x / 1920, self.win_size.y / 1080)
            self.screen_scale = self.player.scale * window_scale
            self.world_center = self.player.center
            self.world = self.player.world
        elif self.world.size:
            self.screen_scale = min(self.win_size.x / self.world.size.x,
                                    self.win_size.y / self.world.size.y)
            self.world_center = self.world.center
        else:
            # happens when the window gets drawn before the world got updated
            self.screen_scale = 1
            self.world_center = Vec(0, 0)

    def draw(self, widget, cairo_context):
        c = Canvas(cairo_context)
        if self.draw_subscriber:
            self.recalculate()
            self.draw_subscriber.on_draw_background(c, self)
            self.draw_subscriber.on_draw_cells(c, self)
            self.draw_subscriber.on_draw_hud(c, self)
コード例 #16
0
ファイル: window.py プロジェクト: henrylu518/gagar
class WorldViewer(object):
    """
    Draws one world and handles keys/mouse.
    Does not poll for events itself.
    Calls input_subscriber.on_{key_pressed|mouse_moved}() methods on key/mouse input.
    Calls draw_subscriber.on_draw_{background|cells|hud}() methods when drawing.
    """

    INFO_SIZE = 300

    def __init__(self, world):
        self.world = world
        self.player = None  # the focused player, or None to show full world

        # the class instance on which to call on_key_pressed and on_mouse_moved
        self.input_subscriber = None
        # same for draw_background, draw_cells, draw_hud
        self.draw_subscriber = None

        self.win_size = Vec(1000, 1000 * 9 / 16)
        self.screen_center = self.win_size / 2
        self.screen_scale = 1
        self.world_center = Vec(0, 0)
        self.mouse_pos = Vec(0, 0)

        window = Gtk.Window()
        window.set_title("agar.io")
        window.set_default_size(self.win_size.x, self.win_size.y)
        window.connect("delete-event", Gtk.main_quit)

        self.drawing_area = Gtk.DrawingArea()
        window.add(self.drawing_area)

        window.set_events(Gdk.EventMask.POINTER_MOTION_MASK)
        window.connect("key-press-event", self.key_pressed)
        window.connect("motion-notify-event", self.mouse_moved)
        window.connect("button-press-event", self.mouse_pressed)

        self.drawing_area.connect("draw", self.draw)

        window.show_all()

    def focus_player(self, player):
        """Follow this client regarding center and zoom."""
        self.player = player
        self.world = player.world

    def show_full_world(self, world=None):
        """
        Show the full world view instead of one client.
        :param world: optionally update the drawn world
        """
        self.player = None
        if world:
            self.world = world

    def key_pressed(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if not self.input_subscriber:
            return
        val = event.keyval
        try:
            char = chr(val)
        except ValueError:
            char = ""
        self.input_subscriber.on_key_pressed(val=val, char=char)

    def mouse_moved(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if not self.input_subscriber:
            return
        self.mouse_pos = Vec(event.x, event.y)
        pos_world = self.screen_to_world_pos(self.mouse_pos)
        self.input_subscriber.on_mouse_moved(pos=self.mouse_pos, pos_world=pos_world)

    def mouse_pressed(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if not self.input_subscriber:
            return
        self.input_subscriber.on_mouse_pressed(button=event.button)

    def world_to_screen_pos(self, world_pos):
        return (world_pos - self.world_center).imul(self.screen_scale).iadd(self.screen_center)

    def screen_to_world_pos(self, screen_pos):
        return (screen_pos - self.screen_center).idiv(self.screen_scale).iadd(self.world_center)

    def world_to_screen_size(self, world_size):
        return world_size * self.screen_scale

    def recalculate(self):
        alloc = self.drawing_area.get_allocation()
        self.win_size.set(alloc.width, alloc.height)
        self.screen_center = self.win_size / 2
        if self.player:  # any client is focused
            window_scale = max(self.win_size.x / 1920, self.win_size.y / 1080)
            self.screen_scale = self.player.scale * window_scale
            self.world_center = self.player.center
            self.world = self.player.world
        elif self.world.size:
            self.screen_scale = min(self.win_size.x / self.world.size.x, self.win_size.y / self.world.size.y)
            self.world_center = self.world.center
        else:
            # happens when the window gets drawn before the world got updated
            self.screen_scale = 1
            self.world_center = Vec(0, 0)

    def draw(self, _, c):
        if self.draw_subscriber:
            self.recalculate()
            self.draw_subscriber.on_draw_background(c, self)
            self.draw_subscriber.on_draw_cells(c, self)
            self.draw_subscriber.on_draw_hud(c, self)
コード例 #17
0
ファイル: window.py プロジェクト: astumpf/gagar
class WorldViewer(object):
    """
    Draws one world and handles keys/mouse.
    Does not poll for events itself.
    Calls input_subscriber.on_{key_pressed|mouse_moved}() methods on key/mouse input.
    Calls draw_subscriber.on_draw_{background|cells|hud}() methods when drawing.
    """

    INFO_SIZE = 300

    MIN_SCREEN_SCALE = 0.075
    MAX_SCREEN_SCALE = 1

    def __init__(self, world):
        self.world = world
        self.player = None  # the focused player, or None to show full world

        # the class instance on which to call on_key_pressed and on_mouse_moved
        self.input_subscriber = None
        # same for draw_background, draw_cells, draw_hud
        self.draw_subscriber = None
        self.button_subscriber = None

        self.buttons = []

        self.win_size = Vec(1000, 1000 * 9 / 16)
        self.screen_center = self.win_size / 2
        self.screen_scale = 1
        self.screen_zoom_scale = 1
        self.world_center = Vec(0, 0)
        self.mouse_pos = Vec(0, 0)

        window = Gtk.Window()
        window.set_title('agar.io')
        window.set_default_size(self.win_size.x, self.win_size.y)
        window.connect('delete-event', Gtk.main_quit)

        self.drawing_area = Gtk.DrawingArea()
        window.add(self.drawing_area)

        window.set_events(Gdk.EventMask.KEY_PRESS_MASK
                          | Gdk.EventMask.POINTER_MOTION_MASK
                          | Gdk.EventMask.BUTTON_PRESS_MASK
                          | Gdk.EventMask.SCROLL_MASK)
        window.connect('key-press-event', self.key_pressed)
        window.connect('motion-notify-event', self.mouse_moved)
        window.connect('button-press-event', self.mouse_pressed)
        window.connect('scroll-event', self.mouse_wheel_moved)

        self.drawing_area.connect('draw', self.draw)

        window.show_all()
        #draw_thread = threading.Thread(target=self.draw_loop)
        #draw_thread.daemon = True
        #draw_thread.start()

    def draw_loop(self):
        while True:
            self.drawing_area.queue_draw()
            time.sleep(0.003)

    def focus_player(self, player):
        """Follow this client regarding center and zoom."""
        self.player = player
        self.world = player.world

    def show_full_world(self, world=None):
        """
        Show the full world view instead of one client.
        :param world: optionally update the drawn world
        """
        self.player = None
        if world:
            self.world = world

    def key_pressed(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if not self.input_subscriber:
            return
        val = event.keyval
        try:
            char = chr(val)
        except ValueError:
            char = ''
        self.input_subscriber.on_key_pressed(val=val, char=char)

    def mouse_moved(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if not self.input_subscriber:
            return
        self.mouse_pos = Vec(event.x, event.y)
        pos_world = self.screen_to_world_pos(self.mouse_pos)
        self.input_subscriber.on_mouse_moved(pos=self.mouse_pos,
                                             pos_world=pos_world)

    def mouse_pressed(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if not self.input_subscriber:
            return
        self.input_subscriber.on_mouse_pressed(button=event.button)
        if event.button == 1:
            for button in self.buttons:
                if button.contains_point(self.mouse_pos):
                    self.button_subscriber.on_button_pressed(
                        button, self.mouse_pos)

    def mouse_wheel_moved(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if event.direction == Gdk.ScrollDirection.UP and self.screen_zoom_scale < self.MAX_SCREEN_SCALE:
            self.screen_zoom_scale = min(self.screen_zoom_scale * 1.5,
                                         self.MAX_SCREEN_SCALE)
        if event.direction == Gdk.ScrollDirection.DOWN and self.screen_zoom_scale > self.MIN_SCREEN_SCALE:
            self.screen_zoom_scale = max(self.screen_zoom_scale * 0.75,
                                         self.MIN_SCREEN_SCALE)

    def register_button(self, button):
        self.buttons.append(button)
        if button.contains_point(self.mouse_pos):
            self.button_subscriber.on_button_hover(button, self.mouse_pos)

    def world_to_screen_pos(self, world_pos):
        return (world_pos - self.world_center) \
            .imul(self.screen_scale).iadd(self.screen_center)

    def screen_to_world_pos(self, screen_pos):
        return (screen_pos - self.screen_center) \
            .idiv(self.screen_scale).iadd(self.world_center)

    def world_to_screen_size(self, world_size):
        return world_size * self.screen_scale

    def recalculate(self):
        alloc = self.drawing_area.get_allocation()
        self.win_size.set(alloc.width, alloc.height)
        self.screen_center = self.win_size / 2
        if self.player:  # any client is focused
            # if self.player.is_alive or (self.player.center.x == 0 and self.player.center.y == 0) or not self.player.scale == 1.0: # HACK due to bug: player scale is sometimes wrong (sent by server?) in spectate mode
            window_scale = max(self.win_size.x / 1920, self.win_size.y / 1080)
            new_screen_scale = self.player.scale * window_scale * self.screen_zoom_scale
            self.screen_scale = lerp_smoothing(self.screen_scale,
                                               new_screen_scale, 0.1, 0.0001)

            smoothing_factor = 0.1
            if self.player.is_alive:
                smoothing_factor = 0.3

            self.world_center.x = lerp_smoothing(self.world_center.x,
                                                 self.player.center.x,
                                                 smoothing_factor, 0.01)
            self.world_center.y = lerp_smoothing(self.world_center.y,
                                                 self.player.center.y,
                                                 smoothing_factor, 0.01)

            self.world = self.player.world
        elif self.world.size:
            new_screen_scale = min(
                self.win_size.x / self.world.size.x,
                self.win_size.y / self.world.size.y) * self.screen_zoom_scale
            self.screen_scale = lerp_smoothing(self.screen_scale,
                                               new_screen_scale, 0.1, 0.0001)
            self.world_center = self.world.center
        else:
            # happens when the window gets drawn before the world got updated
            self.screen_scale = self.screen_zoom_scale
            self.world_center = Vec(0, 0)

    def draw(self, widget, cairo_context):
        self.buttons = []
        c = Canvas(cairo_context)
        if self.draw_subscriber:
            self.recalculate()
            self.draw_subscriber.on_draw_background(c, self)
            self.draw_subscriber.on_draw_cells(c, self)
            self.draw_minimap_backgound(c, self)
            self.draw_subscriber.on_draw_minimap(c, self)
            self.draw_subscriber.on_draw_hud(c, self)

    def draw_minimap_backgound(self, c, w):
        if w.world.size:
            minimap_w = w.win_size.x / 5
            minimap_size = Vec(minimap_w, minimap_w)
            minimap_scale = minimap_size.x / w.world.size.x
            minimap_offset = w.win_size - minimap_size

            def world_to_map(world_pos):
                pos_from_top_left = world_pos - w.world.top_left
                return minimap_offset + pos_from_top_left * minimap_scale

            # minimap background
            c.fill_rect(minimap_offset,
                        size=minimap_size,
                        color=to_rgba(DARK_GRAY, .8))

            # outline the area visible in window
            c.stroke_rect(world_to_map(w.screen_to_world_pos(Vec(0, 0))),
                          world_to_map(w.screen_to_world_pos(w.win_size)),
                          width=1,
                          color=BLACK)
コード例 #18
0
from unittest import TestCase

from agarnet.vec import Vec
from agarnet.world import Cell, Player, World

screen = Vec(1920, 1080)
zero = Vec(0, 0)


class WindowMock:
    def __init__(self, tl=Vec(-10, 10), br=Vec(-10, 10)):
        self.tl = tl
        self.br = br
        self.world_center = (br + tl) / 2
        self.screen_center = screen / 2
        self.screen_scale = 1

    # taken from gagar, same as in official client
    def screen_to_world_pos(self, screen_pos):
        return (screen_pos - self.screen_center) \
            .idiv(self.screen_scale).iadd(self.world_center)


class CellTest(TestCase):
    def test_lt(self):
        self.assertLess(Cell(1), Cell(2))
        self.assertLess(Cell(2, size=10), Cell(1, size=11))


class WorldTest(TestCase):
    def test_world(self):
コード例 #19
0
 def __init__(self, tl=Vec(-10, 10), br=Vec(-10, 10)):
     self.tl = tl
     self.br = br
     self.world_center = (br + tl) / 2
     self.screen_center = screen / 2
     self.screen_scale = 1
コード例 #20
0
ファイル: window.py プロジェクト: astumpf/gagar
class WorldViewer(object):
    """
    Draws one world and handles keys/mouse.
    Does not poll for events itself.
    Calls input_subscriber.on_{key_pressed|mouse_moved}() methods on key/mouse input.
    Calls draw_subscriber.on_draw_{background|cells|hud}() methods when drawing.
    """

    INFO_SIZE = 300

    MIN_SCREEN_SCALE = 0.075
    MAX_SCREEN_SCALE = 1

    def __init__(self, world):
        self.world = world
        self.player = None  # the focused player, or None to show full world

        # the class instance on which to call on_key_pressed and on_mouse_moved
        self.input_subscriber = None
        # same for draw_background, draw_cells, draw_hud
        self.draw_subscriber = None
        self.button_subscriber = None

        self.buttons = []

        self.win_size = Vec(1000, 1000 * 9 / 16)
        self.screen_center = self.win_size / 2
        self.screen_scale = 1
        self.screen_zoom_scale = 1
        self.world_center = Vec(0, 0)
        self.mouse_pos = Vec(0, 0)

        window = Gtk.Window()
        window.set_title('agar.io')
        window.set_default_size(self.win_size.x, self.win_size.y)
        window.connect('delete-event', Gtk.main_quit)

        self.drawing_area = Gtk.DrawingArea()
        window.add(self.drawing_area)

        window.set_events(Gdk.EventMask.KEY_PRESS_MASK |
                          Gdk.EventMask.POINTER_MOTION_MASK |
                          Gdk.EventMask.BUTTON_PRESS_MASK |
                          Gdk.EventMask.SCROLL_MASK)
        window.connect('key-press-event', self.key_pressed)
        window.connect('motion-notify-event', self.mouse_moved)
        window.connect('button-press-event', self.mouse_pressed)
        window.connect('scroll-event', self.mouse_wheel_moved)

        self.drawing_area.connect('draw', self.draw)

        window.show_all()
        #draw_thread = threading.Thread(target=self.draw_loop)
        #draw_thread.daemon = True
        #draw_thread.start()

    def draw_loop(self):
        while True:
            self.drawing_area.queue_draw()
            time.sleep(0.003)

    def focus_player(self, player):
        """Follow this client regarding center and zoom."""
        self.player = player
        self.world = player.world

    def show_full_world(self, world=None):
        """
        Show the full world view instead of one client.
        :param world: optionally update the drawn world
        """
        self.player = None
        if world:
            self.world = world

    def key_pressed(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if not self.input_subscriber:
            return
        val = event.keyval
        try:
            char = chr(val)
        except ValueError:
            char = ''
        self.input_subscriber.on_key_pressed(val=val, char=char)

    def mouse_moved(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if not self.input_subscriber:
            return
        self.mouse_pos = Vec(event.x, event.y)
        pos_world = self.screen_to_world_pos(self.mouse_pos)
        self.input_subscriber.on_mouse_moved(pos=self.mouse_pos, pos_world=pos_world)

    def mouse_pressed(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if not self.input_subscriber:
            return
        self.input_subscriber.on_mouse_pressed(button=event.button)
        if event.button == 1:
            for button in self.buttons:
                if button.contains_point(self.mouse_pos):
                    self.button_subscriber.on_button_pressed(button, self.mouse_pos)

    def mouse_wheel_moved(self, _, event):
        """Called by GTK. Set input_subscriber to handle this."""
        if event.direction == Gdk.ScrollDirection.UP and self.screen_zoom_scale < self.MAX_SCREEN_SCALE:
            self.screen_zoom_scale = min(self.screen_zoom_scale * 1.5, self.MAX_SCREEN_SCALE)
        if event.direction == Gdk.ScrollDirection.DOWN and self.screen_zoom_scale > self.MIN_SCREEN_SCALE:
            self.screen_zoom_scale = max(self.screen_zoom_scale * 0.75, self.MIN_SCREEN_SCALE)

    def register_button(self, button):
        self.buttons.append(button)
        if button.contains_point(self.mouse_pos):
            self.button_subscriber.on_button_hover(button, self.mouse_pos)

    def world_to_screen_pos(self, world_pos):
        return (world_pos - self.world_center) \
            .imul(self.screen_scale).iadd(self.screen_center)

    def screen_to_world_pos(self, screen_pos):
        return (screen_pos - self.screen_center) \
            .idiv(self.screen_scale).iadd(self.world_center)

    def world_to_screen_size(self, world_size):
        return world_size * self.screen_scale

    def recalculate(self):
        alloc = self.drawing_area.get_allocation()
        self.win_size.set(alloc.width, alloc.height)
        self.screen_center = self.win_size / 2
        if self.player:  # any client is focused
            # if self.player.is_alive or (self.player.center.x == 0 and self.player.center.y == 0) or not self.player.scale == 1.0: # HACK due to bug: player scale is sometimes wrong (sent by server?) in spectate mode
            window_scale = max(self.win_size.x / 1920, self.win_size.y / 1080)
            new_screen_scale = self.player.scale * window_scale * self.screen_zoom_scale
            self.screen_scale = lerp_smoothing(self.screen_scale, new_screen_scale, 0.1, 0.0001)

            smoothing_factor = 0.1
            if self.player.is_alive:
                smoothing_factor = 0.3

            self.world_center.x = lerp_smoothing(self.world_center.x, self.player.center.x, smoothing_factor, 0.01)
            self.world_center.y = lerp_smoothing(self.world_center.y, self.player.center.y, smoothing_factor, 0.01)

            self.world = self.player.world
        elif self.world.size:
            new_screen_scale = min(self.win_size.x / self.world.size.x, self.win_size.y / self.world.size.y) * self.screen_zoom_scale
            self.screen_scale = lerp_smoothing(self.screen_scale, new_screen_scale, 0.1, 0.0001)
            self.world_center = self.world.center
        else:
            # happens when the window gets drawn before the world got updated
            self.screen_scale = self.screen_zoom_scale
            self.world_center = Vec(0, 0)

    def draw(self, widget, cairo_context):
        self.buttons = []
        c = Canvas(cairo_context)
        if self.draw_subscriber:
            self.recalculate()
            self.draw_subscriber.on_draw_background(c, self)
            self.draw_subscriber.on_draw_cells(c, self)
            self.draw_minimap_backgound(c, self)
            self.draw_subscriber.on_draw_minimap(c, self)
            self.draw_subscriber.on_draw_hud(c, self)

    def draw_minimap_backgound(self, c, w):
        if w.world.size:
            minimap_w = w.win_size.x / 5
            minimap_size = Vec(minimap_w, minimap_w)
            minimap_scale = minimap_size.x / w.world.size.x
            minimap_offset = w.win_size - minimap_size

            def world_to_map(world_pos):
                pos_from_top_left = world_pos - w.world.top_left
                return minimap_offset + pos_from_top_left * minimap_scale

            # minimap background
            c.fill_rect(minimap_offset, size=minimap_size,
                        color=to_rgba(DARK_GRAY, .8))

            # outline the area visible in window
            c.stroke_rect(world_to_map(w.screen_to_world_pos(Vec(0, 0))),
                          world_to_map(w.screen_to_world_pos(w.win_size)),
                          width=1, color=BLACK)