hypatia-software-organization/hypatia-engine

View on GitHub
hypatia/render.py

Summary

Maintainability
A
1 hr
Test Coverage
# This module is part of Hypatia and is released under the
# MIT License: http://opensource.org/licenses/MIT

"""How stuff is drawn. Very specific rendering stuff. Includes
screen and viewport.

Mostly a lot of scaffolding.

See Also:
    :mod:`animations`

"""

import sys
import time
import itertools

import pygame
from pygame.locals import *

from hypatia import constants


class Screen(object):
    """Everything blits to screen!

    Notes:
      --

    CONSTANTS:
      FPS (int): frames per second limit

    Attributes:
      clock (pygame.time.Clock):
      time_elapsed_milliseconds (int): the time difference between
        the two most recent frames/updates in milliseconds.
      screen_size (tuple):
      screen (pygame.display surface): --

    """

    FPS = 60

    def __init__(self, filters=None):
        """Will init pygame.

        Args:
          filters (list): list of functions which takes and
            returns a surface.

        """

        pygame.init()
        pygame.mouse.set_visible(False)
        self.clock = pygame.time.Clock()
        self.time_elapsed_milliseconds = 0
        display_info = pygame.display.Info()
        self.screen_size = (display_info.current_w, display_info.current_h)
        self.screen = pygame.display.set_mode(self.screen_size,
                                              FULLSCREEN | DOUBLEBUF)
        self.filters = filters

    def update(self, surface):
        """Update the screen; apply surface to screen, automatically
        rescaling for fullscreen.

        """

        scaled_surface = pygame.transform.scale(surface, self.screen_size)

        if self.filters:

            for filter_function in self.filters:
                scaled_surface = filter_function(scaled_surface)

        self.screen.blit(scaled_surface, (0, 0))
        pygame.display.flip()
        self.time_elapsed_milliseconds = self.clock.tick(Screen.FPS)


# how much of this is redundant due to pygame Surface.scroll?
class Viewport(object):
    """Display only a fixed area of a surface.

    Attributes:
      surface (pygame.Surface): viewport surface
      rect (pygame.Rect): viewable coordinates

    """

    def __init__(self, size):
        """

        Args:
          size (tuple): (int x, int y) pixel dimensions of viewport.

        Example:
          >>> viewport = Viewport((320, 240))

        """

        self.surface = pygame.Surface(size)
        self.rect = pygame.Rect((0, 0), size)

    def center_on(self, entity, master_rect):
        """Center the viewport rectangle on an object.

        Note:
          entity must have entity.rect (pygame.Rect)

          Does not center if centering would render off-surface;
          finds nearest.

        Args:
          entity: something with an attribute "rect" which value is
            a pygame.Rect.

        Returns:
          bool: --

        """

        entity_position_x, entity_position_y = entity.rect.center
        difference_x = entity_position_x - self.rect.centerx
        difference_y = entity_position_y - self.rect.centery
        potential_rect = self.rect.move(*(difference_x, difference_y))

        if potential_rect.left < 0:
            difference_x = 0

        if potential_rect.top < 0:
            difference_y = 0

        if potential_rect.right > master_rect.right:
            difference_x = (difference_x -
                            (potential_rect.right - master_rect.right))

        if potential_rect.bottom > master_rect.bottom:
            difference_y = (difference_y -
                            (potential_rect.bottom - master_rect.bottom))

        self.rect.move_ip(*(difference_x, difference_y))

    def relative_position(self, position):
        x, y = position
        offset = self.rect.topleft
        x -= offset[0]
        y -= offset[1]
        position_on_screen = (x, y)

        return position_on_screen

    def blit(self, surface):
        """Draw the correct portion of supplied surface onto viewport.

        Args:
          surface (pygame.Surface): will only draw the area described
            by viewport coordinates.

        Example:
          >>> viewport = Viewport((100, 100))
          >>> surface = pygame.Surface((800, 600))
          >>> viewport.blit(surface)

        """

        self.surface.blit(surface,
                          (0, 0),
                          self.rect)


if __name__ == "__main__":
    import doctest
    doctest.testmod()