예제 #1
0
    async def animate_spaceship(self, start_x: int, start_y: int) -> NoReturn:
        """
        A coroutine for drawing and moving the spaceship.
        :param start_x: a start x (column) point for the spaceship
        :param start_y: a start y (row) point for the spaceship
        :return:
        """

        x_speed, y_speed = 0, 0
        max_y, max_x = get_canvas_size(self._canvas)

        spaceship_frames = self._all_frames['spaceship']
        spaceship = MapObject(frame=spaceship_frames['rocket_frame_1'],
                              start_x=start_x,
                              start_y=start_y)
        self._dynamic_objects['spaceship'] = spaceship

        for i in itertools.cycle([1, 2]):
            for _ in range(0, 2):
                x, y = spaceship.current_coordinates()
                frame = spaceship_frames[f'rocket_frame_{i}']

                draw_frame(self._canvas, x, y, frame)

                x_direction, y_direction, space_pressed = \
                    read_controls(self._canvas)
                x_speed, y_speed = update_speed(x_speed, y_speed, x_direction,
                                                y_direction)
                await sleep(1)

                draw_frame(self._canvas, x, y, frame, negative=True)

                if y + y_speed <= 1:
                    y = 1
                elif y + y_speed + frame.height > max_y:
                    y = max_y - frame.height
                else:
                    y += y_speed

                if x + x_speed <= 1:
                    x = 1
                elif x + x_speed + frame.width >= max_x:
                    x = max_x - frame.width
                else:
                    x += x_speed

                if (space_pressed
                        and self._current_year >= MapSettings.PLASMA_GUN_YEAR):
                    x_fire = round(x + spaceship.frame.width // 2)
                    self._coroutines.append(self.fire(x_fire, y))

                spaceship.change_frame(frame)
                spaceship.change_coordinates(x, y)

                await self.check_game_over(spaceship, max_x, max_y)
예제 #2
0
    async def fill_orbit_with_garbage(self) -> NoReturn:
        """
        This method produces rubbish on the map
        """

        # Wait for a year when the first rubbish will appear on the map
        delay_tick = get_garbage_delay_tics(self._current_year)
        while delay_tick is None:
            await sleep(5)
            delay_tick = get_garbage_delay_tics(self._current_year)

        rubbish_frames = [
            frame for name, frame in self._all_frames['rubbish'].items()
            if not name.startswith('rocket')
        ]

        max_y, max_x = get_canvas_size(self._canvas)
        rubbish_count = 0

        # This variable shows how much rubbish can be on the map simultaneously
        max_rubbish_count = max_x * max_y // min(frame.height * frame.width
                                                 for frame in rubbish_frames)
        while True:
            await sleep(MapSettings.RUBBISH_COEFF)

            produce_next = False
            frame = rubbish_frames[random.randint(0, len(rubbish_frames) - 1)]
            start_x = random.randint(-frame.width + 2, max_x - 2)
            start_y = -frame.height
            rubbish_object = MapObject(frame, start_x, start_y)

            # Check that a new rubbish sample does not overlap existing
            # If it does, try to produce another sample.
            for existing_object in self._dynamic_objects.values():
                if rubbish_object & existing_object:
                    produce_next = True
                    break

            if produce_next:
                continue

            if rubbish_count > max_rubbish_count:
                # Reset count because objects with old IDs disappeared
                rubbish_count = 0
            else:
                rubbish_count += 1

            rubbish_id = f'rubbish_{rubbish_count}'
            self._dynamic_objects[rubbish_id] = rubbish_object
            self._coroutines.append(
                self.fly_garbage(rubbish_object, rubbish_id))
            await sleep(get_garbage_delay_tics(self._current_year))
예제 #3
0
    async def fire(self,
                   start_x: int,
                   start_y: int,
                   x_speed: Optional[Union[float, int]] = 0,
                   y_speed: Optional[Union[float, int]] = -1) -> NoReturn:
        """
        Display animation of gun shot, direction and speed
        can be specified.
        """

        x, y = start_x, start_y
        self._canvas.addstr(round(y), round(x), '*')
        await sleep(0)

        self._canvas.addstr(round(y), round(x), 'O')
        await sleep(0)
        self._canvas.addstr(round(y), round(x), ' ')

        x += x_speed
        y += y_speed

        symbol = '-' if x_speed else '|'

        max_y, max_x = get_canvas_size(self._canvas)
        curses.beep()
        fire_shot_object = MapObject(Frame(symbol), x, y)
        while 1 < y < max_y and 1 < x < max_x:
            self._canvas.addstr(round(y), round(x), symbol)
            await sleep(0)
            self._canvas.addstr(round(y), round(x), ' ')
            fire_shot_object.change_coordinates(x + x_speed, y + y_speed)
            for obj_id, obj in self._dynamic_objects.items():
                if obj_id.startswith('rubbish') and obj & fire_shot_object:
                    draw_frame(self._canvas,
                               obj.x,
                               obj.y,
                               obj.frame,
                               negative=True)
                    self._dynamic_objects.pop(obj_id)
                    await self.explode(obj.x, obj.y)
                    return

            y += y_speed
            x += x_speed
예제 #4
0
    async def draw_timer(self) -> NoReturn:
        max_y, max_x = get_canvas_size(self._canvas)
        canvas = self._canvas.derwin(3, max_x // 2, max_y - 2, max_x // 2 + 2)

        n_prev_phrase_symbols = 0
        while True:
            msg = f'Year: {self._current_year}'
            phrase = MapSettings.PHRASES.get(self._current_year, "")
            if phrase:
                msg = f'{msg} - {phrase}'
                n_prev_phrase_symbols = len(phrase) + 3
            else:
                msg = f'{msg}{" " * n_prev_phrase_symbols}'
                n_prev_phrase_symbols = 0

            canvas.addstr(1, 1, msg)
            canvas.border()
            canvas.refresh()
            await sleep(0)
예제 #5
0
    def _run_event_loop(self, canvas) -> NoReturn:
        curses.curs_set(False)

        self._canvas = canvas
        self._canvas.border()
        self._canvas.nodelay(True)

        max_y, max_x = get_canvas_size(self._canvas)
        # If we try to change a cell with coordinates (max_y, max_x),
        # curses will raise an exception (don't know why). So, to prevent
        # putting an object (for example, a star) into this cell,
        # we subtract 1 from each of components.
        max_x -= 1
        max_y -= 1

        n_stars = int((max_y * max_x) * MapSettings.STAR_COEFF)
        coordinates = {(random.randint(1, max_x), random.randint(1, max_y))
                       for _ in range(0, n_stars)}
        self._coroutines = [
            self.blink(
                MapObject(frame=Frame(random.choice(MapSettings.STAR_SET)),
                          start_x=x,
                          start_y=y)) for x, y in coordinates
        ]
        self._coroutines.append(self.animate_spaceship(start_y=10, start_x=10))
        self._coroutines.append(self.fill_orbit_with_garbage())
        self._coroutines.append(self.draw_timer())
        self._coroutines.append(self.increase_year())

        while True:
            for coroutine in self._coroutines.copy():
                try:
                    coroutine.send(None)
                    self._canvas.refresh()
                except StopIteration:
                    self._coroutines.remove(coroutine)
            if not self._coroutines:
                break

            time.sleep(TIC_TIMEOUT)
예제 #6
0
    async def fly_garbage(self,
                          rubbish_object: MapObject,
                          rubbish_id: str,
                          speed: Optional[float] = 0.5) -> NoReturn:
        """
        Animate garbage, flying from top to bottom.
        A start_x position will stay same, as specified on start.
        """

        max_y, max_x = get_canvas_size(self._canvas)

        x, y = rubbish_object.current_coordinates()
        while y < max_y:
            if rubbish_id not in self._dynamic_objects:
                return

            rubbish_object.change_coordinates(x, y)
            draw_frame(self._canvas, x, y, rubbish_object.frame)
            await sleep(0)
            draw_frame(self._canvas, x, y, rubbish_object.frame, negative=True)
            y += speed

        self._dynamic_objects.pop(rubbish_id)