[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[pygame] handy snippets: Status Bar and Simple Button



Hey all.

Here are a couple classes I am using for the StrikeOps project, but
they're pretty general, so I'd thought I'd submit them here as they may
be useful to others.

Also, I guess this should be considered a submission to the PCR too, but
don't know what the proper channel is. (is it even called the PCR
anymore?)

-- 
+-------------------------------------------------------------+
| Shandy Brown                               Digital Thinkery |
| shandy@geeky.net             http://www.digitalthinkery.com |
+-------------------------------------------------------------+
#!/usr/bin/env python
"""
Here's some text to describe the SimpleButton module
"""

#Import Modules
import os, pygame
from pygame.locals import *


#-----------------------------------------------------------------------------
def load_png( name ):
	basedirectory = 'data'
	if isinstance(name, list):
		fullname = basedirectory
		for component in name:
			fullname = os.path.join(fullname, component)
	else:
		fullname = os.path.join(basedirectory, name)
	try:
		image = pygame.image.load(fullname)

		if image.get_alpha is None:
			image = image.convert()
		else:
			image = image.convert_alpha()
	except pygame.error, message:
		print 'Cannot load image:', fullname
		raise SystemExit, message
	return image, image.get_rect()


#-----------------------------------------------------------------------------
class EventSensitive:
	""" This is an interface for sprites that should be sensitive 
	    to keypresses and mouse clicks
	    The object MUST have listenKeys and offKeys for keypresses
	    The object MUST have rect and callbackFn for mouse clicks

	    listenKeys and offKeys are dicts of functions, indexed by key name
	    callbackFn is a function"""

	#----------------------------------------------------------------------
	def Signal( self, event ):
		"""event is a pygame style event"""
		if hasattr(self, 'callbackFn') \
		 and event.type == MOUSEBUTTONDOWN \
		 and self.rect.collidepoint (event.pos):
			self.callbackFn()

		elif hasattr(self, 'listenKeys') \
		 and event.type in [KEYUP,KEYDOWN]:
			if self.listenKeys.has_key( event.key ) \
			  and event.type is KEYDOWN:
				self.listenKeys[event.key]( )
			elif self.offKeys.has_key( event.key ) \
			  and event.type is KEYUP:
				self.offKeys[event.key]( )


#-----------------------------------------------------------------------------
class SimpleButton(pygame.sprite.Sprite, EventSensitive):
	def __init__(self, callbackFn, imgName=None):
		pygame.sprite.Sprite.__init__(self) #call Sprite initializer
		if imgName:
			self.image, self.rect = load_png(imgName)
		else:
			#if there's no image name, make a red square
			self.image = pygame.Surface( (100,100) )
			self.image.fill( (200,0,0) )
			self.rect = self.image.get_rect()

		self.callbackFn = callbackFn

	#----------------------------------------------------------------------
	def SetCallback( self, newCallbackFn ):
		self.callbackFn = newCallbackFn


#this calls the 'main' function when this script is executed
if __name__ == '__main__': print "didn't expect that!"
#!/usr/bin/env python
"""
This is a status bar class for things like health, time, progress, etc.
"""

#Import Modules
import os, pygame
from pygame.locals import *

red = (220,0,0)
black = (0,0,0)

#-----------------------------------------------------------------------------
class StatusBar(pygame.sprite.Sprite):
	"""status bar to track health"""
	def __init__(self, object, rect, 
	             outlineImg=None, insideImg=None,
		     attrName='health', fullAmt=100,
		     outerColor=black, innerColor=red ):
		"""pass in a rectstyle to tell the statusbar where to appear
		   and pass in an object with a health attribute"""
		pygame.sprite.Sprite.__init__(self) #call Sprite initializer

		self.outerColor = outerColor
		self.innerColor = innerColor

		#The outer image is usually something like a black outline
		# but it could be more complex, maybe with text or something
		if outlineImg is not None:
			self.backImg, self.rect = load_png(outlineImg)
			self.rect.move_ip( rect.topleft )
		else:
			self.rect = pygame.Rect(rect)
			self.backImg = pygame.Surface( (self.rect.width,
			                              self.rect.height) )
			self.backImg.fill( self.outerColor )

		#The inside image defaults to a red rectangle if no image
		# is given.
		if insideImg is not None:
			self.innerImg, self.innerRect = load_png(insideImg)
		else:
			self.innerRect = self.rect.inflate( -10, -10 )
			self.innerImg = pygame.Surface( (self.innerRect.width,
			                                 self.innerRect.height))
			self.innerImg.fill( self.innerColor )

		self.object= object
		self.attrName = attrName
		self.fullAmt = fullAmt
		self.amt = getattr(self.object, self.attrName)

		#For efficiency, the object can update it's status bar ONLY
		# when it's health is changed, instead of every tick.
		self.onlyUpdateOnExplicitRequest = 0

		if( hasattr(object, "SetStatusBar") ):
			self.object.SetStatusBar( self )
			self.onlyUpdateOnExplicitRequest = 1

		self.UpdateImg()

	def update(self):
		if self.onlyUpdateOnExplicitRequest :
			return
		self.UpdateImg()

	def UpdateImg(self):

		#First figure out how big the inner bar should be
		amt = getattr(self.object,self.attrName) / float(self.fullAmt)
		height = self.innerRect.height
		fullWidth  = self.innerRect.width

		width = fullWidth * amt
		if width < 0:
			width = 0

		self.image = self.backImg.convert_alpha()
		self.image.blit( self.innerImg, (5,5),
		                   Rect( [0,0,width,height] ) )


#this calls the 'main' function when this script is executed
if __name__ == '__main__': print "Not supposed to run me!"