[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Fwd: [pygame] 2 surfaces on a Sprite class]
You can overlay sprites nicely and move them around in a bunch, using
the group updates, or even deriving their posn from a 'master' sprite
for each group.
Attached code is for a gameboard operated by drag and drop, includes a
snap-to-square cursor.
SpritePieces is a utility for chopping up images, got idea from samepyg.
SpritePanelMouse moves the cursor, the snap to grid and the carried
piece, if there is one (.carrying)
If interested I can put this incomplete stuff with a demo game up
somewhere.
P
-------- Original Message --------
From: "alex" <alex@quad.com.ar>
Subject: [pygame] 2 surfaces on a Sprite class
To: <pygame-users@seul.org>
Hey there, I'm getting started with Sprites, I was wondering how could I
manage 2 or more surfaces on a single sprite class. I first tried to
make a
single sprite class for each surface, but each class must share a lot of
internal variables, so having them as a single class makes things
easier..
but then I realized that when myGroup.draw() is called, it will blit
self.image to the given surface (usually screen) at the self.rect
position,
so...
should I manually blit all class' surfaces into self.image before
calling
myGroup.draw()? or is there a better/clean way to do this?
any kind of suggestions are very welcome.
Alex
____________________________________
pygame mailing list
pygame-users@seul.org
http://pygame.seul.org
#spritepanels.py
#13feb02 PG separated from spygame
#08feb02 PG for mygamebox. sprite panels are a utility for game writers
#See http://www.mrexcessive.net/games/
OPTIONS = {}
pause = 0
screen = None
background = None
level = None
#ZZZ set these parameters in init call to SpritePanelMouse
GRID_square = None
GRID_offset = None
GRID_light_offset = None
GRID_center = None
GRID_number = None
try:
import os,sys,getopt
import random
import pygame
import pygame.draw
import pygame.sprite
from pygame.locals import *
except ImportError, err:
print "couldn't load module. %s" % (err)
sys.exit(2)
def load_image(name, colorkey=None):
fullname = os.path.join('data',name)
try:
image = pygame.image.load(fullname)
except pygame.error, message:
print 'Cannot load image:', name
raise SystemExit, message
image = image.convert()
if colorkey is not None:
if colorkey is -1:
colorkey = image.get_at((0,0))
image.set_colorkey(colorkey, RLEACCEL)
return image, image.get_rect()
class SpritePanelMouse(pygame.sprite.Sprite):
def __init__(self,GRID_BITS = None):
if GRID_BITS:
self.GRID_square = GRID_BITS['square']
self.GRID_offset = GRID_BITS['offset']
self.GRID_light_offset = GRID_BITS['light_offset']
self.GRID_center = GRID_BITS['center']
self.GRID_number = GRID_BITS['number']
pygame.sprite.Sprite.__init__(self) #call Sprite initialiser
self.original_image, self.original_rect = load_image('cursor.png',None)
self.image_carrying,drop = load_image('cursor_carrying.png',None)
self.image_carryingmany,drop = load_image('cursor_carryingmany.png',None)
self.image_vanish,drop = load_image('cursor_vanish.png',None)
(self.image,self.rect) = (self.original_image,self.original_rect)
self.carrying = None
self.pickedup = 0
self.saveimage = None
self.update() # set original position based on mouse
def update(self):
"move the cursor based on the mouse position"
self.pos = pygame.mouse.get_pos()
self.rect.center = self.pos
if self.carrying: # YYY show carried sprite on top of mouse (XXX ZZZ hopefully!)
self.carrying.rect.center = self.pos
def mousein(self):
if self.saveimage:
self.image = self.saveimage
else:
self.image = self.original_image
def mouseout(self):
"we no longer have focus"
self.saveimage = self.image
self.image = self.image_vanish
def mousedown(self,panel,flag_allow_reposition = 0):
if panel.ishit(self.rect.center):
flag_donedrop = 0
oldcarrying = None
if panel.flag_target_drop and self.carrying: # if something to drop
if panel.gridsprite.visible: # only drop if can
#ZZZ replace or question on collision (something already there, not compatible)
#ZZZ snap to grid
if self.pickedup:
#YYY PG without .clone() just moves sprite from panel to board
#panel.sticksprite(self.lastcontrolhit.clone(),self.pos) # drop the newthing
if panel.sticksprite(self.carrying,self.pos): # try to drop piece here
flag_donedrop = 1
self.carrying.butup()
self.pickedup = 0
self.image = self.original_image
oldcarrying = self.carrying
self.carrying = None # forget which piece now it's dropped
if (panel.flag_target_pick or flag_allow_reposition): # allow pickup from board
hits = pygame.sprite.spritecollide(self,panel,0) # 0 => don't kill
for hitwhat in hits:
if not self.carrying: #YYY only process until something picked up, so don't .butdown() on two and pick up one.
hitwhat.doyourthing() # always do its thing (paintable ones just don't)
if hitwhat.strength >= 0: # -ve => unpickable/moveable
if flag_donedrop and hitwhat == oldcarrying: # if hit what I just dropped, ignore it.
pass
else:
hitwhat.butdown()
self.image = self.image_carrying
self.carrying = hitwhat
self.pickedup = 1
def mouseup(self,panel):
pass
class SpritePieces:
"holds and provides access to an array of graphics"
def __init__(self,gridsize,piecesfile='pieces'): # gridsize is e.g. (10,10) for 100 squares
pieces = None # no pieces
self.pieces,self.pieces_rect = load_image(piecesfile + '.png',None)
self.gridsize = gridsize
self.gdx = self.pieces_rect.width / self.gridsize[0]
self.gdy = self.pieces_rect.height / self.gridsize[1]
self.colourkey = self.pieces.get_colorkey()
def pieceofimage(self,gxy):
(gx,gy) = gxy
pieceimage = self.pieces.subsurface((gx*self.gdx), (gy*self.gdy), self.gdx, self.gdy).convert()
pieceimage.set_colorkey(self.colourkey,RLEACCEL)
return pieceimage,pieceimage.get_rect()
#
pieceimage = pygame.Surface((self.gdx,self.gdy)) # new surface
pieceimage.set_colorkey(self.colourkey,RLEACCEL)
xy = pygame.Rect(gx*self.gdx, gy*self.gdy,self.gdx,self.gdy)
pieceimage.blit(self.pieces,(0,0),xy)
print "CKin poin=" + repr(pieceimage.get_colorkey())
return pieceimage,pieceimage.get_rect()
class SpritePanelSprite(pygame.sprite.Sprite):
""" same as pygame.sprite.Sprite, but with spritepanel common behaviours, required
default implementations &c. """
def doyourthing(self):
pass
class ShowGrid(SpritePanelSprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image, self.rect = load_image('cursor_snap.png',None)
self.strength = -1 # cannot pick/move &c.
class SpritePaint(SpritePanelSprite):
def __init__(self,xy,imagefile = 'button_default',pieces=None,choosepiece=None):
pygame.sprite.Sprite.__init__(self) #call Sprite initialiser
self.flag_paintable = 1
if not pieces: # get images from file, as of old
self.imagefile = imagefile
self.image_original, self.rect = load_image(self.imagefile + '.png', None)
self.image_pushed, drop = load_image(self.imagefile + '_push.png', None)
self.pieces = pieces
self.choosepiece = choosepiece
else: # get images from pieces, which is of class SpritePieces
if choosepiece: # choosepiece is gxgy into pieces, xy is coords on screen for centre
self.pieces = pieces
self.choosepiece = choosepiece
self.image_original, self.rect =pieces.pieceofimage(choosepiece)
#ZZZ for now piece images don't do 'pushed' (just do next row though, if needed. Ie. y+1)
self.image_pushed = self.image_original.convert() # copy
#YYY and always remember to...
self.image = self.image_original
self.rect.center = xy
self.busy = 0
def update(self):
"move/popup automatically &c."
pass
def doaction(self,action):
if not self.busy:
self.busy = 1
self.busy_counter = 30
def butdown(self):
self.image = self.image_pushed
self.image.set_alpha(140)
def butup(self):
self.image = self.image_original
self.image.set_alpha(255)
def clone(self):
"return a new instance of myself, like myself"
if not self.pieces:
minime = SpritePaint(self.rect.center,self.imagefile)
else:
print "Should be cloned in subclass"
return minime
class SpriteAction(SpritePaint):
def __init__(self,xy,imagefile = 'button_default_action.png',action='go',targetpanel=None):
SpritePaint.__init__(self,xy,imagefile)
self.flag_paintable = 0
self.action = action
self.settarget(targetpanel)
self.strength = -2 # not pickable, but actionable
def settarget(self,targetpanel):
"setup the target panel"
self.targetpanel = targetpanel
def doyourthing(self):
if self.targetpanel:
self.targetpanel.doaction(self.action)
class SpritePanel(pygame.sprite.RenderUpdates):
# a special panel of sprites which interacts with the mouse
def __init__(self,rect=None,showgrid=0,flag_target_drop=0,flag_target_pick=0,GRID_BITS=None,**argv):
if GRID_BITS:
self.GRID_square = GRID_BITS['square']
self.GRID_offset = GRID_BITS['offset']
self.GRID_light_offset = GRID_BITS['light_offset']
self.GRID_center = GRID_BITS['center']
self.GRID_number = GRID_BITS['number']
self.rect = rect # active drop area for this panel, default None
sprites = []
self.showgrid_original = showgrid # there will be a grid
self.showgrid = self.showgrid_original
self.gridsprite = ShowGrid() # initially invisible (not in group)
pygame.sprite.RenderUpdates.__init__(self,sprites)
self.flag_target_drop = flag_target_drop
self.flag_target_pick = flag_target_pick
def ishit(self,coord):
" is the panel hit ?"
if self.rect:
if self.rect.collidepoint(coord):
return 1
return 0
def doaction(self,action):
#ZZZ debug
if action:
for sprite in self.sprites():
sprite.doaction(action)
def grid_on(self):
"show if was showing before"
self.showgrid = self.showgrid_original
def grid_off(self):
self.showgrid = 0
def snaptogrid(self,pos):
self.gridsprite.visible = 0
if self.showgrid:
if self.ishit(pos):
(gx,gy) = self.pos2grid(pos)
if gy > 4: # must be in bottom 3 rows of board XXX ZZZ This test should only apply to gamestate when placing, not playing
self.gridsprite.rect.center = self.gridpos(pos)
if self.rect.contains(self.gridsprite.rect): # only draw if whole gridsquare fits
if not self.has(self.gridsprite):
self.add(self.gridsprite)
self.gridsprite.visible = 1
if not self.gridsprite.visible:
if self.has(self.gridsprite):
self.remove(self.gridsprite)
def gridpos(self,pos):
"snap pos to grid and return pixel coords"
(x,y) = pos
(a,b) = self.GRID_light_offset
(c,d) = self.GRID_center
(q,r) = self.GRID_square
x = c+ ((int((x-a)/q)*q)+a)
y = d+ ((int((y-b)/r)*r)+b)
return (x,y)
def grid2pos(self,grid):
"convert grid coords to pixel coords"
(gx,gy) = grid
(a,b) = self.GRID_light_offset
(c,d) = self.GRID_center
(q,r) = self.GRID_square
x = c + (q*gx)+a
y = d + (r*gy)+b
return (x,y)
def pos2grid(self,pos):
"snap pos to grid and return grid coords"
(x,y) = pos
(a,b) = self.GRID_light_offset
(q,r) = self.GRID_square
gx = int((x-a)/q)
gy = int((y-b)/r)
return (gx,gy)
def sticksprite(self,sprite,xy):
"just stick it down, no checking"
sprite.rect.center = self.gridpos(xy)
sprite.visible = 1
self.add(sprite)
return 1 # always allow for now