view 003/002.py @ 12:9dc97f88e274 default tip

Added CC0 license
author Radomir Dopieralski <sheep-devel@sheep.art.pl>
date Sun, 08 Jul 2012 19:56:38 +0200
parents 2a0f43c87b80
children
line wrap: on
line source

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pygame
import pygame.locals as pg
from pytmx import tmxloader


FACING = {
    (0, -1): 0,
    (-1, 0): 1,
    (0, 1): 2,
    (1, 0): 3,
}


def load_sheet(filename, width=32, height=None):
    if height is None:
        height = width
    image = pygame.image.load(filename)
    image = image.convert()
    image.set_colorkey((0xff, 0, 0xff))
    w, h = image.get_size()
    images = []
    for x in xrange(w // width):
        for y in xrange(h // height):
            rect = pygame.rect.Rect(x * width, y * height, width, height)
            images.append(image.subsurface(rect))
    return images


class HeroSprite(pygame.sprite.Sprite):
    def __init__(self, (x, y)):
        super(HeroSprite, self).__init__()
        self.spritesheet = load_sheet('spritesheet.png', 64)
        self.image = self.spritesheet[2]
        self.rect = self.image.get_rect()
        self.rect.midbottom = (x * 32 + 16, y * 32 + 32)
        self.animations = []

    def move(self, (dx, dy)):
        self.animations.append(self.animation_slide((dx, dy)))

    def animation_slide(self, (dx, dy)):
        facing = FACING[dx, dy]
        self.image = self.spritesheet[facing]
        for step in xrange(8):
            self.rect.move_ip(dx * 4, dy * 4)
            yield

    def update(self):
        if self.animations:
            try:
                self.animations[0].next()
            except StopIteration:
                self.animations.pop(0)

class Level(object):
    def __init__(self, filename):
        self.tiled_map = tmxloader.load_pygame(filename)
        self.hero_position = 1, 1

    def render(self, screen):
        w = self.tiled_map.tilewidth
        h = self.tiled_map.tileheight
        get_image = self.tiled_map.getTileImage
        for l, layer in enumerate(self.tiled_map.tilelayers):
            for y in xrange(self.tiled_map.height):
                for x in xrange(self.tiled_map.width):
                    image = get_image(x, y, l)
                    if image:
                        screen.blit(image, (x * w, y * h))
        x, y = self.hero_position

    def get_properties(self, (x, y)):
        properties = {}
        for l, layer in enumerate(self.tiled_map.tilelayers):
            properties.update(self.tiled_map.getTileProperties((x, y, l)) or {})
        return properties

    def is_blocked(self, (x, y)):
        return self.get_properties((x, y)).get('block')

    def move_hero(self, (dx, dy)):
        x, y = self.hero_position
        if not self.is_blocked((x + dx, y + dy)):
            self.hero_position = x + dx, y + dy
            return True
        return False


class Game(object):
    def __init__(self):
        pygame.display.init()
        pygame.font.init()
        self.screen = pygame.display.set_mode((800, 600))
        self.screen.fill((0x66, 0x66, 0x66))
        self.keys = {
            pg.K_UP: (self.move_hero, (0, -1)),
            pg.K_DOWN: (self.move_hero, (0, 1)),
            pg.K_LEFT: (self.move_hero, (-1, 0)),
            pg.K_RIGHT: (self.move_hero, (1, 0)),
            pg.K_ESCAPE: (self.quit,),
        }
        self.sprites = pygame.sprite.RenderUpdates()

    def load_level(self, filename):
        self.level = Level(filename)
        self.hero_sprite = HeroSprite(self.level.hero_position)
        self.sprites.add(self.hero_sprite)
        self.background = self.screen.copy()
        self.level.render(self.background)
        self.screen.blit(self.background, (0, 0))
        self.sprites.draw(self.screen)
        pygame.display.update()

    def quit(self):
        self.game_over = True

    def move_hero(self, direction):
        if self.level.move_hero(direction):
            self.hero_sprite.move(direction)

    def control(self):
        for event in pygame.event.get():
            if event.type == pg.QUIT:
                self.quit()
            elif event.type == pg.KEYDOWN:
                try:
                    action = self.keys[event.key]
                except KeyError:
                    pass
                else:
                    action[0](*action[1:])

    def display(self):
        self.sprites.clear(self.screen, self.background)
        self.sprites.update()
        dirty = self.sprites.draw(self.screen)
        pygame.display.update(dirty)

    def run(self):
        self.clock = pygame.time.Clock()
        self.game_over = False
        while not self.game_over:
            self.display()
            self.control()
            self.clock.tick(30)


if __name__ == '__main__':
    game = Game()
    game.load_level('level.tmx')
    game.run()