[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
Re: [pygame] Extending Surface Class
Hi
Sorry to not have read your example exactly.
I went curious and tried to extend pygame.Surface by my own. I made a
SurfaceObject that has all the draw, transform and gfxdraw functions as
its own methods (see attachment). This only works because the functions
take a surface as first argument! It was a little experiment and I had
to use some trickery to get it to work. Not sure if it is useful at all.
~DR0ID
ERName schrieb:
Is it possible to extend the surface class? Every time I do the
surface ends up dieing somehow right after it is created... I may just
be doing it in the wrong way, though. The main point is to override
the __str__() method, so if you know another way besides extending
pygame.Surface, I'd be happy to hear it.
class ExtendedSurface(pygame.Surface):
def __init__(self, surface, string):
pygame.Surface.__init__(surface, surface.get_size()) #The docs
say to include a size, etc. but that just gives me "too many values to
unpack" errors.
self.string = string
def __str__(self):
return self.string
Thanks!
#!/usr/bin/python
# -*- coding: utf-8 -*-
u"""
TODO: doc
"""
__version__ = '$Id$'
import pygame
try:
import pygame.gfxdraw
except:
pass
import new
# save a pointer to the original pygame.Surface
pygame_surface = pygame.Surface
class SurfaceObject(pygame_surface):
u"""
SurfaceObject is a Surface that has all all functions from pygame.draw, pygame.gfxdraw,
pygame.transform as a own method. So instead of calling
s = pygame.Surface((10,10))
pygame.draw.line(...)
with this SurfaceObject one can do:
s = SurfaceObject((10,10))
s.draw_line(...)
The SurfaceObject might be slower than using the native functions.
At the end, the SurfaceObject needs to be blitted to the screen.
"""
def __init__(self, size, flags=0, depth=32):
super(SurfaceObject, self).__init__(size, flags, depth)
# add methods from pygame.draw
for name in dir(pygame.draw):
if not name.startswith('__'):
#new.instancemethod(function, instance, class)
attr = getattr(pygame.draw, name)
setattr(self, 'draw_'+name, new.instancemethod(attr, self, self.__class__))
try:
# add methods from gfxdraw, new in pygame 1.9
for name in dir(pygame.gfxdraw):
if not name.startswith('__'):
setattr(self, "gfxdraw_"+name, new.instancemethod(getattr(pygame.gfxdraw, name), self, self.__class__))
except:
pass
# wrapper for functions that return a pygame.Surface
# wrapper returns a SurfaceObject instaed of a pygame.Surface
class Wrapper(object):
def __init__(self, func):
self._func = func
def __call__(self, *args, **kwargs):
s = self._func(*args, **kwargs)
# not sure if this creates a surface that is the same a converted surface
so = SurfaceObject(s.get_size(), 0, s)
# transfer the content
so.blit(s, (0,0), )
return so
for name in dir(pygame.transform):
if not name.startswith('__'):
if name in ['threshold', 'average_color']:
# this functions take an surf, return a non surf
setattr(self, name, getattr(pygame.transform, name))
elif name in ['set_smoothscale_backend', 'get_smoothscale_backend']:
# this functions take not a surface and return not a surface
# this wrapper is there to just filter out the self argument of the methods
class Wrapper1(object):
def __init__(self, func):
self._func = func
def __call__(self, *args, **kwargs):
return self._func(*args, **kwargs)
w = Wrapper1(getattr(pygame.transform, name))
inst = new.instancemethod(w, self, self.__class__)
setattr(self, name, inst)
else:
# return a surface
w = Wrapper(getattr(pygame.transform, name))
inst = new.instancemethod(w, self, self.__class__)
setattr(self, name, inst)
# some methods from pygame.Surface return a Surface, they need to
# be wrapped to return a SurfaceObject
for name in ['convert', 'convert_alpha', 'subsurface']:
orig_name = '_orig_'+name
orig_func = getattr(self, name)
setattr(self, name, Wrapper(orig_func))
setattr(self, orig_name, orig_func)
# only allow SurfaceObject to be instanciated, even using pygame.Surface
pygame.Surface = SurfaceObject
pygame.surface.Surface= SurfaceObject
if __name__ == '__main__':
# usage
pygame.init()
s = SurfaceObject((400,300))
s.fill((255,0,0))
s.draw_line((255,255,0), (100,100), (400,300), 1)
s.draw_circle((0,0,255), (200,200), 50)
s.draw_line((255,255,255), (100,100), (300,300), 5)
#s.set_colorkey((255,0,0))
#s = s.rotate(90)
s2 = pygame.Surface((50,50))
s2.fill((255,255,255))
s2.draw_line((100,100,100), (0,0), (25,25), 3)
# print all attributes from a SurfaceObject
for i in dir(s): print i, '\t\t\t', getattr(s, i)
screen = pygame.display.set_mode((800, 600))
s2 = s2.convert()
# update display
screen.blit(s, (0,0))
screen.blit(s2, (400,0))
pygame.display.flip()
# wait for an event
pygame.event.clear()
pygame.event.wait()