Source

gallox / gallox / utils.py

Full commit
import os
import sys
import math

import pygame
from gallox.settings import *

# taken from pygame cookbook
def memoizer(new_dict=dict):
    """
    Creates a memoizer with the given dictionary policy.
 
    The memoizer thus obtained can be used as a decorator to remember the
    results of calls to long-running functions, such as loading images
    from disk. It also means that there will only be one copy of the image,
    which can be quite handy when dealing with restricted resources.
 
    Example:
 
    weak_memoize = memoize(new_dict=weakref.WeakValueDictionary)
 
    @weak_memoize
    def load_image(filename):
        # Your long running image-loading code goes here.
        return result
        
    """
    def memoize(func):
        cache = new_dict()
 
        def memo(*args, **kwargs):
            try:
                # Create a key, resorting to repr if the key isn't hashable.
                try:
                    k = (args, tuple(kwargs.items()))
                    hash(k)
                except TypeError:
                    k = repr(k)
                    
                # Try to return the result from the cache.
                return cache[k]
            except KeyError:
                # The key wasn't found, so invoke the function and save the
                # result in the cache.
                result = func(*args, **kwargs)
                cache[k] = result
                return result
            
        return memo
    
    return memoize

import weakref
memoize = memoizer(new_dict=weakref.WeakValueDictionary)

#@memoize
def load_image(name, colorkey=None, alpha=False):
    if not "." in name:
        fullname = os.path.join(DATA_PATH, 'sprites', "%s.png" % name )
    else:
        fullname = name
    try:
        image = pygame.image.load(fullname)
    except pygame.error, message:
        print 'Cannot load image:', fullname
        raise SystemExit, message
    if alpha:
        image = image.convert_alpha()
    else:
        image = image.convert()
        if colorkey is not None:
            if colorkey is -1:
                colorkey = image.get_at((0,0))
            image.set_colorkey(colorkey, pygame.RLEACCEL)
    return image, image.get_rect()

@memoize
def load_sound(name):
    class NoneSound:
        def play(self): pass
    if not pygame.mixer:
        return NoneSound()
    fullname = os.path.join(PROJECT_DIR, 'data', 'sounds', name)
    try:
        sound = pygame.mixer.Sound(fullname)
    except pygame.error, message:
        print 'Cannot load sound:', wav
        raise SystemExit, message
    return sound

def nearest_point(rect, point):
    """
    return the nearest point of rect to point
    """
    px, py = point
    if px < rect.left:
        x = rect.left
    elif px > rect.right:
        x = rect.right
    else:
        x = px
    if py < rect.top:
        y = rect.top
    elif py > rect.bottom:
        y = rect.bottom
    else:
        y = py
    return x,y

def dist_pr(point, rect):
    x,y = point
    rx,ry = nearest_point(rect, point)
    return math.hypot(rx-x, ry-y)

class Fader(object):
    def __init__(self, time=1, color=(0,0,0), direction="out", 
                 callback=sys.exit, *args, **kw):
        """
        fade to or from `color` in `time` seconds and call `callback`
        `dicection` should be "in" to fade from a solid color to screen or
        "out" to fade from screen to solid color.
        """
        self.color = color
        self.alpha = 0.0 if direction == "out" else 255.0
        self.i = 1 if direction == "out" else -1
        self.time = time * 1000.
        self.alpha_per_ms = 255 / self.time
        self.orig_image = None
        self.image = None
        self.rect = None
        self.clock = pygame.time.Clock()
        self.callback = lambda args=args, kw=kw: callback(*args, **kw)
    
    def update(self, events):
        ticks = self.clock.tick()
        if self.time <= 0:
            self.callback()
        self.alpha += self.alpha_per_ms * ticks * self.i
        self.time -= ticks
        if self.image:
            self.image.fill(self.color + (max(min(int(self.alpha), 255), 0),))
        return events, [self.rect]
    
    def blit(self, screen):
        if not self.image:
            self.orig_image = screen.copy()
            self.rect = self.orig_image.get_rect()
            self.image = pygame.Surface(self.rect.size, pygame.SRCALPHA)
        screen.blit(self.orig_image, self.rect)
        screen.blit(self.image, self.rect)