view lib/display.py @ 59:6b9f9dcfabf1 default tip

Monster cleanup
author Radomir Dopieralski <moindev@sheep.art.pl>
date Wed, 02 Jan 2008 03:54:40 +0100
parents 17b5a0cc33d9
children
line wrap: on
line source

#!/usr/bin/python
# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
import os
from util import *

pygame.init()
screen = pygame.display.set_mode((320, 320))

def z_compare(a, b):
    return a.z-b.z

class SortedUpdates(pygame.sprite.RenderUpdates):
    """Sprite group with a depth for controlling drawing order."""
    
    def sprites(self):
        l = self.spritedict.keys()
        l.sort(z_compare)
        return l

class Gauge(pygame.sprite.Sprite):
    def __init__(self, display):
        pygame.sprite.Sprite.__init__(self)
        self.base_image = pygame.image.load("data/image/gauge.png").convert()
        self.image = self.base_image.copy()
        self.image.set_alpha(200)
        self.rect = self.image.get_rect()
        self.rect.bottom = display.screen.get_rect().bottom
        self.image.fill((128, 200, 0), Rect(11, 3, 18, 2))

class Shadow(pygame.sprite.Sprite):
    """Transparent shadows"""
    
    image = read_frames(os.path.join("data", "image", "shadow.png"))[0][0]

    def __init__(self, sprite):
        pygame.sprite.Sprite.__init__(self)
        self.dh = 10
        self.image.set_alpha(92)
        self.rect = Rect(0,0, 24, 24)
        self.sprite = sprite
        self.update()

    def update(self):
        x, y = self.sprite.rect.center
        self.rect.center = (x, y+4+self.sprite.h)

class Display:
    """Display-related code"""

    def __init__(self):
        self.clock = pygame.time.Clock()
        self.screen = screen
        self.sprites = SortedUpdates()
        self.shadows = pygame.sprite.RenderUpdates()
        self.effects = pygame.sprite.RenderUpdates()
        self.hud = pygame.sprite.RenderUpdates()
        self.scrollpos = [0, 0]
        self.key_pressed = None
        self.hud.add(Gauge(self))
        
    def get_image(self, filename, cache={}):
        """Read an image from disk, with caching."""
        
        image_path = os.path.join('data', 'image')
        try:
            return cache[filename]
        except KeyError:
            file_path = os.path.join(image_path, filename)
            cache[filename] = pygame.image.load(file_path).convert()
            return cache[filename]
    
    def draw_map(self, m):
        """Draw the background based on the provided map."""
        
        cache = {}
        background = pygame.Surface((m.w*24, m.h*16))
        background.fill((0, 0, 0))
        x, y = 0, 0
        for line in m:
            for tile in line:
                urls = m.map_key[tile]
                if urls and urls[0]:
                    image = self.get_image(urls[0], cache)
                    background.blit(image , (x*24, y*16))
                x += 1
            x = 0
            y += 1
        self.background = background

    def add_sprite(self, sprite):
        """Place a sprite taking scrolling into account"""
        
        self.sprites.add(sprite)
        sprite.rect.move_ip(self.scrollpos[0], self.scrollpos[1])

    def place_monsters(self, monsters):
        for monster in monsters.values():
            sprite = monster.sprite
            self.add_sprite(sprite)
            self.shadows.add(Shadow(sprite))

    def scroll_after(self, rect):
        """Scrolls to keep the sepcified rectangle visible."""
        hscroll = 0
        vscroll = 0            
        if rect.left<48:
            hscroll = 3
        if rect.right>self.screen.get_width()-48:
            hscroll = -3
        if rect.top<48:
            vscroll = 2
        if rect.bottom>self.screen.get_height()-48:
            vscroll = -2
        if hscroll or vscroll:
            self.scroll(hscroll, vscroll)
            self.refresh()

    def scroll(self, dx, dy):
        """Scroll the map by specified amount"""
    
        self.scrollpos[0] += dx
        self.scrollpos[1] += dy
        for sprite in self.sprites:
            sprite.rect.move_ip(dx, dy)
        for sprite in self.effects:
            sprite.rect.move_ip(dx, dy)
        for sprite in self.shadows:
            sprite.rect.move_ip(dx, dy)

    def clear_func(self, screen, rect):
        """
        Clean up after sprites, taking scrolling into account and
        handling sprites that are out of map.
        """
        
        source = rect.move(-self.scrollpos[0], -self.scrollpos[1])
        if not self.background.get_rect().contains(source):
            screen.fill((0,0,0),rect)
        screen.blit(self.background, rect, source)


    def refresh(self):
        '''Redraw the whole level'''
        
        self.screen.fill((0,0,0))
        self.screen.blit(self.background, self.scrollpos)
        self.hud.clear(self.screen, self.clear_func)
        self.effects.clear(self.screen, self.clear_func)
        self.sprites.clear(self.screen, self.clear_func)
        self.shadows.clear(self.screen, self.clear_func)
        self.shadows.draw(self.screen)
        self.sprites.draw(self.screen)
        self.effects.draw(self.screen)
        self.hud.draw(self.screen)
        pygame.display.update()

    def update(self):
        '''Redraw and update all the animated parts'''

        self.hud.clear(self.screen, self.clear_func)        
        self.effects.clear(self.screen, self.clear_func)
        self.sprites.clear(self.screen, self.clear_func)
        self.shadows.clear(self.screen, self.clear_func)
        self.sprites.update()
        self.shadows.update()
        self.effects.update()
        self.hud.update()
        dirty = self.shadows.draw(self.screen)
        dirty += self.sprites.draw(self.screen)
        dirty += self.effects.draw(self.screen)
        dirty += self.hud.draw(self.screen)
        pygame.display.update(dirty)
    
    def show_frame(self):
        # Update the screen
        self.update()
        self.clock.tick(15)            
        # Process input
        for event in pygame.event.get():
            if event.type==QUIT:
                sys.exit(0)
            elif event.type==KEYDOWN:
                self.key_pressed = event.key