Example #1
0
class Replay(App):
    """A widget that replays a game from a log file captured by Logger

    Replay monkeypatches kivy.clock.time to fire events read from the log
    file.

    Touching the replay will change the replay speed based on the y (up/down)
    -coordinate of the touch, from 50% to 200%. (NB. every clock tick is still
    processed, so speedups might not actually be that big).

    This is more of a dirty hack than other parts of the code.
    """
    def __init__(self, log_filename):
        super(Replay, self).__init__()
        self.log_filename = log_filename
        kivy.clock.time = self.time
        self.stream = gzip.GzipFile(fileobj=open(self.log_filename, 'rb'))
        self.first_tick = time()
        self.last_tick = time()
        self.time_elapsed = 0
        self.stream_time = 0
        self.next_id = 0
        self.clock_speed = 1
        self.running = True

    def build(self):
        self.top_widget = Widget()
        self.content_widget = Widget()
        self.top_widget.add_widget(self.content_widget)
        self.top_widget.add_widget(SpeedAdjuster(self))
        return self.top_widget

    def time(self):
        """Like time.time(), but handles events from the log file
        """
        current = time()
        self.time_elapsed += (current - self.last_tick) * self.clock_speed
        self.last_tick = current
        if not self.running:
            return self.last_tick
        while self.stream and self.time_elapsed > self.stream_time:
            try:
                rec = pickle.load(self.stream)
            except EOFError:
                self.handle__end()
                self.running = False
                break
            else:
                getattr(self, 'handle_' + rec[0])(*rec[1:])
                if rec[0] == 'dt':
                    # Ensure every tick gets handled
                    break
        return self.first_tick + self.stream_time

    def handle__end(self):
        parent = self.top_widget.get_parent_window()
        with self.top_widget.canvas:
            Color(0, 0, 0.2, 0.5)
            Rectangle(size=(parent.width, 40),
                    pos=(0, parent.height / 2 - 20))
        self.top_widget.add_widget(Label(text='Replay finished',
                width=self.top_widget.get_parent_window().width,
                pos=(0, parent.height / 2 - 5), height=10, color=(1, 1, 1, 1)))

    # Handlers for events from the log file:

    def handle_random(self, state):
        """Set the random state"""
        random.setstate(state)

    def handle_add_widget(self, cls):
        """Add a child widget"""
        self.content_widget.add_widget(cls())

    def handle_dt(self, dt):
        """Tick the clock"""
        self.stream_time += dt

    def handle_down(self, attrs):
        """Generate a touch-down event"""
        self.handle__touch_event(attrs, 'on_touch_down')

    def handle_move(self, attrs):
        """Generate a touch-move event"""
        self.handle__touch_event(attrs, 'on_touch_move')

    def handle_up(self, attrs):
        """Generate a touch-up event"""
        self.handle__touch_event(attrs, 'on_touch_up')

    def handle__touch_event(self, attrs, event):
        """Generate any touch-down event"""
        touch = ReplayMotionEvent(None, attrs['id'], attrs)
        for name, value in attrs.items():
            setattr(touch, name, value)
        self.content_widget.dispatch(event, touch)

    def handle_window_size(self, width, height):
        print width, height
        children_to_do = set([self.content_widget])
        children_done = set()
        while children_to_do:
            child = children_to_do.pop()
            child.window_width = width
            child.window_height = height
            children_done.add(child)
            children_to_do.update(child.children)
            children_to_do.difference_update(children_done)
        self.content_widget.canvas.before.clear()
        with self.content_widget.canvas.before:
            PushMatrix()
            win = self.content_widget.get_parent_window()
            window_width = win.width
            window_height = win.height
            the_min = min(window_width / width, window_height / height)
            Scale(the_min)
        self.content_widget.canvas.after.clear()
        with self.content_widget.canvas.after:
            PopMatrix()
Example #2
0
class Replay(App):
    """A widget that replays a game from a log file captured by Logger

    Replay monkeypatches kivy.clock.time to fire events read from the log
    file.

    Touching the replay will change the replay speed based on the y (up/down)
    -coordinate of the touch, from 50% to 200%. (NB. every clock tick is still
    processed, so speedups might not actually be that big).

    This is more of a dirty hack than other parts of the code.
    """
    def __init__(self, log_filename):
        super(Replay, self).__init__()
        self.log_filename = log_filename
        kivy.clock.time = self.time
        self.stream = gzip.GzipFile(fileobj=open(self.log_filename, 'rb'))
        self.first_tick = time()
        self.last_tick = time()
        self.time_elapsed = 0
        self.stream_time = 0
        self.next_id = 0
        self.clock_speed = 1
        self.running = True

    def build(self):
        self.top_widget = Widget()
        self.content_widget = Widget()
        self.top_widget.add_widget(self.content_widget)
        self.top_widget.add_widget(SpeedAdjuster(self))
        return self.top_widget

    def time(self):
        """Like time.time(), but handles events from the log file
        """
        current = time()
        self.time_elapsed += (current - self.last_tick) * self.clock_speed
        self.last_tick = current
        if not self.running:
            return self.last_tick
        while self.stream and self.time_elapsed > self.stream_time:
            try:
                rec = pickle.load(self.stream)
            except EOFError:
                self.handle__end()
                self.running = False
                break
            else:
                getattr(self, 'handle_' + rec[0])(*rec[1:])
                if rec[0] == 'dt':
                    # Ensure every tick gets handled
                    break
        return self.first_tick + self.stream_time

    def handle__end(self):
        parent = self.top_widget.get_parent_window()
        with self.top_widget.canvas:
            Color(0, 0, 0.2, 0.5)
            Rectangle(size=(parent.width, 40), pos=(0, parent.height / 2 - 20))
        self.top_widget.add_widget(
            Label(text='Replay finished',
                  width=self.top_widget.get_parent_window().width,
                  pos=(0, parent.height / 2 - 5),
                  height=10,
                  color=(1, 1, 1, 1)))

    # Handlers for events from the log file:

    def handle_random(self, state):
        """Set the random state"""
        random.setstate(state)

    def handle_add_widget(self, cls):
        """Add a child widget"""
        self.content_widget.add_widget(cls())

    def handle_dt(self, dt):
        """Tick the clock"""
        self.stream_time += dt

    def handle_down(self, attrs):
        """Generate a touch-down event"""
        self.handle__touch_event(attrs, 'on_touch_down')

    def handle_move(self, attrs):
        """Generate a touch-move event"""
        self.handle__touch_event(attrs, 'on_touch_move')

    def handle_up(self, attrs):
        """Generate a touch-up event"""
        self.handle__touch_event(attrs, 'on_touch_up')

    def handle__touch_event(self, attrs, event):
        """Generate any touch-down event"""
        touch = ReplayMotionEvent(None, attrs['id'], attrs)
        for name, value in attrs.items():
            setattr(touch, name, value)
        self.content_widget.dispatch(event, touch)

    def handle_window_size(self, width, height):
        print width, height
        children_to_do = set([self.content_widget])
        children_done = set()
        while children_to_do:
            child = children_to_do.pop()
            child.window_width = width
            child.window_height = height
            children_done.add(child)
            children_to_do.update(child.children)
            children_to_do.difference_update(children_done)
        self.content_widget.canvas.before.clear()
        with self.content_widget.canvas.before:
            PushMatrix()
            win = self.content_widget.get_parent_window()
            window_width = win.width
            window_height = win.height
            the_min = min(window_width / width, window_height / height)
            Scale(the_min)
        self.content_widget.canvas.after.clear()
        with self.content_widget.canvas.after:
            PopMatrix()