""" This is tested on pygame 1.9 and python 3.3 & 2.7. bitcraft (leif dot theden at gmail.com) Rendering demo for the pyscroll. Use the arrow keys to smoothly scroll the map. Window is resizable. See the "Quest" tutorial for a more simple use with pygame sprites and groups. """ from pytmx.util_pygame import load_pygame import pygame import pyscroll import pyscroll.data import collections import logging from pygame.locals import * import pyscroll.orthographic logger = logging.getLogger(__name__) ch = logging.StreamHandler() ch.setLevel(logging.INFO) logger.addHandler(ch) logger.setLevel(logging.INFO) SCROLL_SPEED = 5000 # simple wrapper to keep the screen resizeable def init_screen(width, height): return pygame.display.set_mode((width, height), pygame.RESIZABLE) class ScrollTest: """ Test and demo of pyscroll For normal use, please see the quest demo, not this. """ def __init__(self, filename): # load data from pytmx tmx_data = load_pygame(filename) # create new data source map_data = pyscroll.data.TiledMapData(tmx_data) # create new renderer self.map_layer = pyscroll.orthographic.BufferedRenderer(map_data, screen.get_size()) # create a font and pre-render some text to be displayed over the map f = pygame.font.Font(pygame.font.get_default_font(), 20) t = ["scroll demo. press escape to quit", "arrow keys move"] # save the rendered text self.text_overlay = [f.render(i, 1, (180, 180, 0)) for i in t] # set our initial viewpoint in the center of the map self.center = [self.map_layer.map_rect.width / 2, self.map_layer.map_rect.height / 2] # the camera vector is used to handle camera movement self.camera_acc = [0, 0, 0] self.camera_vel = [0, 0, 0] self.last_update_time = 0 # true when running self.running = False def draw(self, surface): # tell the map_layer (BufferedRenderer) to draw to the surface # the draw function requires a rect to draw to. self.map_layer.draw(surface, surface.get_rect()) # blit our text over the map self.draw_text(surface) def draw_text(self, surface): y = 0 for text in self.text_overlay: surface.blit(text, (0, y)) y += text.get_height() def handle_input(self): """ Simply handle pygame input events """ for event in pygame.event.get(): if event.type == QUIT: self.running = False break elif event.type == KEYDOWN: if event.key == K_ESCAPE: self.running = False break # this will be handled if the window is resized elif event.type == VIDEORESIZE: init_screen(event.w, event.h) self.map_layer.set_size((event.w, event.h)) # these keys will change the camera vector # the camera vector changes the center of the viewport, # which causes the map to scroll # using get_pressed is slightly less accurate than testing for events # but is much easier to use. pressed = pygame.key.get_pressed() if pressed[K_UP]: self.camera_acc[1] = -SCROLL_SPEED * self.last_update_time elif pressed[K_DOWN]: self.camera_acc[1] = SCROLL_SPEED * self.last_update_time else: self.camera_acc[1] = 0 if pressed[K_LEFT]: self.camera_acc[0] = -SCROLL_SPEED * self.last_update_time elif pressed[K_RIGHT]: self.camera_acc[0] = SCROLL_SPEED * self.last_update_time else: self.camera_acc[0] = 0 def update(self, td): self.last_update_time = td friction = pow(.0001, self.last_update_time) # update the camera vector self.camera_vel[0] += self.camera_acc[0] * td self.camera_vel[1] += self.camera_acc[1] * td self.camera_vel[0] *= friction self.camera_vel[1] *= friction # make sure the movement vector stops when scrolling off the screen if self.center[0] < 0: self.center[0] -= self.camera_vel[0] self.camera_acc[0] = 0 self.camera_vel[0] = 0 if self.center[0] >= self.map_layer.map_rect.width: self.center[0] -= self.camera_vel[0] self.camera_acc[0] = 0 self.camera_vel[0] = 0 if self.center[1] < 0: self.center[1] -= self.camera_vel[1] self.camera_acc[1] = 0 self.camera_vel[1] = 0 if self.center[1] >= self.map_layer.map_rect.height: self.center[1] -= self.camera_vel[1] self.camera_acc[1] = 0 self.camera_vel[1] = 0 self.center[0] += self.camera_vel[0] self.center[1] += self.camera_vel[1] # set the center somewhere else # in a game, you would set center to a playable character self.map_layer.center(self.center) def run(self): clock = pygame.time.Clock() self.running = True fps = 60. fps_log = collections.deque(maxlen=20) try: while self.running: # somewhat smoother way to get fps and limit the framerate clock.tick(fps*2) try: fps_log.append(clock.get_fps()) fps = sum(fps_log)/len(fps_log) dt = 1/fps except ZeroDivisionError: continue self.handle_input() self.update(dt) self.draw(screen) pygame.display.flip() except KeyboardInterrupt: self.running = False if __name__ == "__main__": import sys pygame.init() pygame.font.init() screen = init_screen(800, 600) pygame.display.set_caption('pyscroll Test') try: filename = sys.argv[1] except IndexError: logger.info("no TMX map specified, using default") filename = "desert.tmx" try: test = ScrollTest(filename) test.run() except: pygame.quit() raise