[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[pygame] Toats



I come from a procedural programming background (FORTRAN, BASIC, ADA) and missed the whole transition to OOP (I was spending all of my computer time working in the world of SQL scripting).  The time has come for me to work back into some programming, and I've chosen Python both as an extension to many of the SQL scripting tasks that get tossed at me, and as an opening into OOP.  The first program I want to work on is going to be called TOATS, and it is intended to be a tool for use in Social Network Analysis (used specifically to display and manipulate links between various nodes in a network).  I'm looking at Python gaming programming as an environment to write the code because games have always (well, at least for the last 25 years or so) pushed the envelop for the delivery of rich content, and that is what I am trying to accomplish.  I think that the way sprites (and their groups) have been implemented is a natural fit for the types of manipulations I need to accomplish.  Anyone willing to help a newbie out?  Attached is my the current code I'm struggling with (started with TomPong as an example of sprite manipulation, and am trying to work in buttons as implemented in PyGU).  It's primitive, and ugly, mainly because I don't know what I'm doing, at least not yet.  My eventual design goal is to have a large central area where the visualization takes place, a pane to the left with some buttons, another pane along the bottom (more buttons), and some sort of textual output posting into the right pane.  I have managed to get the buttons to display on the left pane, by writing them to the surface of the sprite that is the left panel, and resize appropriately when the overall window is resized, but I have not been able to get them to react to clicking yet.  Is PyMike on this list?  In the attached chunk of code, 25 nodes are displayed, with a variety of links, bouncing about in the display area.  They are bouncing only because I needed to learn how to make them move, and to have the link sprites redraw themselves appropriately.  The eventual goal is to have them space themselves out a little, then stop, only moving when grabbed by the user.  Of course, they also need labels, and there are a variety of other manipulations I will need to add... as soon as I learn how... 
 
Joey
 
 
#!/usr/bin/python
#
#  Joey's Social Network Analysis tool TOATS
#
# Released under the GNU General Public License

VERSION = "0.1"

try:
	import sys
	import random
	import math
	import os
	import getopt
	from socket import *
	
	try:
		import pygame
		from pygame.locals import *
	except ImportError:
		print 'This requires PyGame.'

	try:
		import pygu
		from pygu.locals import *
	except ImportError:
		print 'This requires PyGU.'
		
except ImportError, err:
        print "couldn't load module. %s" % (err)
        sys.exit(2)

def load_png(name):
        """ Load image and return image object"""
        fullname = os.path.join('data', 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()

def first():
	print 'first pressed'
	return

class Control_Box(pygame.sprite.Sprite):
	def __init__(self,color,location):
		pygame.sprite.Sprite.__init__(self)
		self.location = location
		self.color = color
#		self.buttons = []
		if location == 'left':
			self.image = pygame.Surface((screenx/10,screeny))
#			self.image.fill(self.color)
			self.rect = self.image.get_rect()
			self.rect.topleft = [0,0]
#			self.buttons.append(pygu.gui.Button(text='First',font=font,pos=(self.rect.width/6,(self.rect.height/2-95)),size=(2*self.rect.width/3,30),command=first,button_color=BLUE,text_color=WHITE))
#			self.buttons.append(pygu.gui.Button(text='Second',font=font,pos=(self.rect.width/6,(self.rect.height/2-55)),size=(2*self.rect.width/3,30),command=Oldmain,button_color=BLUE,text_color=WHITE))
#			self.buttons.append(pygu.gui.Button(text='Third',font=font,pos=(self.rect.width/6,(self.rect.height/2-15)),size=(2*self.rect.width/3,30),command=Oldmain,button_color=BLUE,text_color=WHITE))
#			self.buttons.append(pygu.gui.Button(text='Fourth',font=font,pos=(self.rect.width/6,(self.rect.height/2+25)),size=(2*self.rect.width/3,30),command=Oldmain,button_color=BLUE,text_color=WHITE))
#			self.buttons.append(pygu.gui.Button(text='Fifth',font=font,pos=(self.rect.width/6,(self.rect.height/2+65)),size=(2*self.rect.width/3,30),command=Oldmain,button_color=BLUE,text_color=WHITE))
#			for b in self.buttons:
#				b.render(self.image)

		if location == 'right':
			self.image = pygame.Surface((screenx/5,screeny))
			self.image.fill(color)
			self.rect = self.image.get_rect()
			self.rect.topleft = [4*screenx/5,0]

		if location == 'bottom':
			self.image = pygame.Surface((screenx,screeny/10))
			self.image.fill(color)
			self.rect = self.image.get_rect()
			self.rect.topleft = [0,9*screeny/10]

	def resize(self):
#		global screenx
#		global screeny
		if self.location == 'left':
			self.image = pygame.Surface((screenx/10,screeny))
#			self.image.fill(self.color)
			self.rect = self.image.get_rect()
			self.rect.topleft = [0,0]
			self.buttons = []
			self.buttons.append(pygu.gui.Button(text='First',font=font,pos=(self.rect.width/6,(self.rect.height/2-95)),size=(2*self.rect.width/3,30),command=first,button_color=BLUE,text_color=WHITE))
			self.buttons.append(pygu.gui.Button(text='Second',font=font,pos=(self.rect.width/6,(self.rect.height/2-55)),size=(2*self.rect.width/3,30),command=Oldmain,button_color=BLUE,text_color=WHITE))
			self.buttons.append(pygu.gui.Button(text='Third',font=font,pos=(self.rect.width/6,(self.rect.height/2-15)),size=(2*self.rect.width/3,30),command=Oldmain,button_color=BLUE,text_color=WHITE))
			self.buttons.append(pygu.gui.Button(text='Fourth',font=font,pos=(self.rect.width/6,(self.rect.height/2+25)),size=(2*self.rect.width/3,30),command=Oldmain,button_color=BLUE,text_color=WHITE))
			self.buttons.append(pygu.gui.Button(text='Fifth',font=font,pos=(self.rect.width/6,(self.rect.height/2+65)),size=(2*self.rect.width/3,30),command=Oldmain,button_color=BLUE,text_color=WHITE))
			for b in self.buttons:
				b.render(self.image)

		if self.location == 'right':
			self.image = pygame.Surface((screenx/5,screeny))
			self.image.fill(self.color)
			self.rect = self.image.get_rect()
			self.rect.topleft = [4*screenx/5,0]

		if self.location == 'bottom':
			self.image = pygame.Surface((screenx,screeny/10))
			self.image.fill(self.color)
			self.rect = self.image.get_rect()
			self.rect.topleft = [0,9*screeny/10]

class Node(pygame.sprite.Sprite):
        """A node that will move across the screen
        Returns: Node object
        Functions: update, calcnewpos
        Attributes: area, vector"""

	def __init__(self,id,location, vector):
		pygame.sprite.Sprite.__init__(self)
		self.image, self.rect = load_png('ball1.png')
		screen = pygame.display.get_surface()
		self.area = screen.get_rect()
		self.vector = vector
		self.rect.center = location
#		self.rect.topleft=location
		self.hit = 0
		self.ID = id
		self.nodeset = set([self.ID])
		self.next_update_time = 0


	def update(self,current_time):
		if self.next_update_time < current_time:
			newpos = self.calcnewpos(self.rect,self.vector)
			self.rect = newpos
			(angle,z) = self.vector

			if not self.area.contains(newpos):
				tl = not self.area.collidepoint(newpos.topleft)
				tr = not self.area.collidepoint(newpos.topright)
				bl = not self.area.collidepoint(newpos.bottomleft)
				br = not self.area.collidepoint(newpos.bottomright)
				if tr and tl or (br and bl):
					angle = -angle
				if tl and bl:
					#self.offcourt()
					angle = math.pi - angle
				if tr and br:
					angle = math.pi - angle
					#self.offcourt()
			else:
				# Do Node and Control Box collide? if so, bounce the node back into the chalkboard
				if self.rect.colliderect(left.rect) == 1:
					angle = math.pi - angle
				elif self.rect.colliderect(right.rect) == 1:
					angle = math.pi - angle
				elif self.rect.colliderect(bottom.rect) == 1:
					angle = -angle
			self.vector = (angle,z)
			self.next_update_time = 0

        def calcnewpos(self,rect,vector):
                (angle,z) = vector
                (dx,dy) = (z*math.cos(angle),z*math.sin(angle))
                return rect.move(dx,dy)

class Link(pygame.sprite.Sprite):
	def __init__(self,color,anode,bnode):
		pygame.sprite.Sprite.__init__(self)
		self.color = color
		self.anode = anode.sprite
		self.bnode = bnode.sprite
		self.width = abs(self.anode.rect.center[0]-self.bnode.rect.center[0])
		self.height = abs(self.anode.rect.center[1]-self.bnode.rect.center[1])
#		print self.width,self.height
		self.image = pygame.Surface([self.width,self.height]).convert()
		self.image.set_colorkey([0,0,0])
		self.image.fill([0,0,0])
		self.rect = self.image.get_rect()
		self.rect.topleft=([min(self.anode.rect.center[0],self.bnode.rect.center[0]),min(self.anode.rect.center[1],self.bnode.rect.center[1])])
		if (self.anode.rect.center[0]<=self.bnode.rect.center[0] and self.anode.rect.center[1]<=self.bnode.rect.center[1]) or (self.anode.rect.center[0]>=self.bnode.rect.center[0] and self.anode.rect.center[1]>=self.bnode.rect.center[1]):
			pygame.draw.line(self.image,self.color,[0,0],[self.width,self.height],2)
		else:
			pygame.draw.line(self.image,self.color,self.rect.bottomleft,self.rect.topright,2)

		self.going_down = True
		self.next_update_time = 0

	def update(self,current_time):
		if self.next_update_time < current_time:
			self.width = abs(self.anode.rect.center[0]-self.bnode.rect.center[0])
			self.height = abs(self.anode.rect.center[1]-self.bnode.rect.center[1])
			self.image = pygame.Surface([self.width,self.height])
#			self.image.fill([0,0,0])
			self.image.set_colorkey([0,0,0])
			self.rect = self.image.get_rect()
			self.rect.topleft=([min(self.anode.rect.center[0],self.bnode.rect.center[0]),min(self.anode.rect.center[1],self.bnode.rect.center[1])])
#			if (self.anode.rect.center[0]<=self.bnode.rect.center[0] and self.anode.rect.center[1]<=self.bnode.rect.center[1]) or (self.anode.rect.center[0]>=self.bnode.rect.center[0] and self.anode.rect.center[1]>=self.bnode.rect.center[1]):
#				pygame.draw.line(self.image,self.color,[0,0],[self.width,self.height],2)
#			else:
#				pygame.draw.line(self.image,self.color,self.rect.bottomleft,self.rect.topright,3)

			if (self.anode.rect.center[0]<self.bnode.rect.center[0] and self.anode.rect.center[1]<self.bnode.rect.center[1]):
				pygame.draw.aaline(self.image,self.color,[0,0],[self.width,self.height],3)
			elif (self.anode.rect.center[0]>self.bnode.rect.center[0] and self.anode.rect.center[1]>self.bnode.rect.center[1]):
				pygame.draw.aaline(self.image,self.color,[self.width,self.height],[0,0],3)
			elif (self.anode.rect.center[0]>self.bnode.rect.center[0] and self.anode.rect.center[1]<self.bnode.rect.center[1]):
				pygame.draw.aaline(self.image,self.color,[0,self.height],[self.width,0],3)
			elif (self.anode.rect.center[0]<self.bnode.rect.center[0] and self.anode.rect.center[1]>self.bnode.rect.center[1]):
				pygame.draw.aaline(self.image,self.color,[self.width,0],[0,self.height],3)
			elif (self.width==0 and self.height!=0):
				pygame.draw.aaline(self.image,self.color,[0,0],[0,self.height],3)
			elif (self.height==0 and self.width!=0):
				pygame.draw.aaline(self.image,self.color,[0,0],[self.width,0],3)

			self.going_down = True
			self.next_update_time = 0

def Menu():
#	print screen
	buttons = []
	buttons.append(pygu.gui.Button(text='First',font=font,pos=(272,220),size=(100,30),command=first,button_color=BLUE,text_color=WHITE))
	while 1:
		event = pygame.event.poll()
		if event.type == QUIT:
			sys.exit()
		if event.type == KEYDOWN:
			if event.key == K_ESCAPE:
				sys.exit()
				
		screen.blit(background,(0,0))
#		pygu.gui.RenderText(screen,'PyGU Menu',('centered',90),(255,255,255),bigfont,'shadow')
		
		for b in buttons:
			b.render(screen)
			
		pygame.time.wait(10)
		pygame.display.flip()

def Oldmain():
	global screen
	global background
	global screenx
	global screeny
	
#	print screen
	# Initialise Nodes
	speed = 5
	rand = ((0.1 * (random.randint(5,8))))
	NodeDict = {1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,10:10,11:11,12:12,13:13,14:14,15:15,16:16,17:17,18:18,19:19,20:20,21:21,22:22,23:23,24:24,25:25}
	screenx = pygame.display.list_modes()[0][0]
	screeny = pygame.display.list_modes()[0][1]
	
#	for each in nodedic.keys():
	for each in NodeDict.keys():
		rand = ((0.1*(random.randint(1,9))))
		NodeDict[each] = pygame.sprite.GroupSingle(Node(each,(screenx/2+15*each,screeny/2+15*each),(rand,speed)))
		NodeDict[each].sprite.add(NodeSpritesGroup)
#		NodeDict[each].sprite.add(AllSpritesGroup)
	
	# Initialize Links
	color = GREEN
	LinkDict = {(1,2):1,(1,3):1,(1,4):1,(1,5):1,(1,6):1,(1,7):1,(1,8):1,(1,9):1,(2,3):1,(2,10):1,(2,11):1,(2,12):1}

	for each in LinkDict.keys():
		LinkDict[each] = pygame.sprite.GroupSingle(Link(color,NodeDict[each[0]],NodeDict[each[1]]))
		LinkDict[each].sprite.add(LinkSpritesGroupGreen)
		LinkDict[each].sprite.add(AllSpritesGroup)

	color = RED
	LinkDict = {(13,14):1,(13,15):1,(16,17):1,(16,18):1,(17,18):1}
	for each in LinkDict.keys():
		LinkDict[each] = pygame.sprite.GroupSingle(Link(color,NodeDict[each[0]],NodeDict[each[1]]))
		LinkDict[each].sprite.add(LinkSpritesGroupRed)
		LinkDict[each].sprite.add(AllSpritesGroup)

	color = YELLOW
	LinkDict = {(1,20):1,(20,21):1,(21,22):1,(21,23):1,(24,25):1}
	for each in LinkDict.keys():
		LinkDict[each] = pygame.sprite.GroupSingle(Link(color,NodeDict[each[0]],NodeDict[each[1]]))
		LinkDict[each].sprite.add(LinkSpritesGroupYellow)
		LinkDict[each].sprite.add(AllSpritesGroup)

	for each in NodeDict.keys():
		NodeDict[each].sprite.add(AllSpritesGroup)

#	nodesprites = pygame.sprite.RenderPlain(tuple(nodespriteslist))
#	linksprites = pygame.sprite.RenderPlain(tuple(linkspritelist))
	controlsprites = pygame.sprite.RenderPlain((left,right,bottom))

	# Blit everything to the screen
	screen.blit(background, (0, 0))
	pygame.display.flip()

	# Initialise clock
	clock = pygame.time.Clock()

	# Event loop
	while 1:
		# Make sure game doesn't run at more than 60 frames per second
		clock.tick(30)

		for event in pygame.event.get():
			if event.type == QUIT:
				return
			elif event.type == VIDEORESIZE:
				SCREEN_SIZE = event.size
				screen = pygame.display.set_mode(SCREEN_SIZE,RESIZABLE,32)
				pygame.display.set_caption("Window resized to "+str(event.size[0])+' by '+str(event.size[1]))
				# ReFill background - should be quick, but could redo as dirty update
				background = pygame.Surface(screen.get_size())
				background = background.convert()
				background.fill((0, 0, 0))
				screenx, screeny = SCREEN_SIZE
#				for y in range(0,screenx,background.get_height()):
#					for x in range(0,screeny,background.get_width()):
#						screen.blit(background,(x,y))
				# ReDraw Control Boxes
				left.resize()
				right.resize()
				bottom.resize()
				for y in range(0,screenx,background.get_height()):
					for x in range(0,screeny,background.get_width()):
						screen.blit(background,(x,y))
#			elif 

		# clear screen
		AllSpritesGroup.clear(screen,background)
		AllSpritesGroup.update(pygame.time.get_ticks())
		AllSpritesGroup.draw(screen)
		controlsprites.draw(screen)
		pygame.display.flip()

# Initialise screen
pygame.init()
maxscreen = [pygame.display.list_modes()[0][0] , pygame.display.list_modes()[0][1]]
screen = pygame.display.set_mode(maxscreen,RESIZABLE,32)
screenx = pygame.display.list_modes()[0][0]
screeny = pygame.display.list_modes()[0][1]

#print screen
pygame.display.set_caption('TOATS')
#screen = pygu.display.screen((640, 480), 'TOATS')
#pygu.display.load_screen(screen)


# Set up some colors, so I don't have to keep typing the RGB values
BLACK = [0,0,0]
BLUE = [0,0,255]
CYAN = [0,255,255]
MAGENTA = [255,0,255]
RED = [255,0,0]
WHITE = [255,255,255]
YELLOW = [255,255,0]
GREY = [200,200,200]
GREEN = [0,255,0]

font = pygu.font.Font(None,15)
#bigfont = pygu.font.Font(None,60)

# Fill background
#global background
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill(BLACK)

# get the screen size, then set up a boxes on the left, right and bottom, full height, 1/10 accross (left and right)
# full available width, 1/10 height (bottom)
# 1/10 is initial guess, will need to get more precise once we toss buttons in and play with various screen sizes
#global screenx 
#screenx = pygame.display.list_modes()[0][0]
#global screeny 
#screeny = pygame.display.list_modes()[0][1]

# Initialise control boxes
left = Control_Box(GREY,'left')
right = Control_Box(GREY,'right')
bottom = Control_Box(GREY,'bottom')

buttons = []
buttons.append(pygu.gui.Button(text='First',font=font,pos=(left.rect.width/6,(left.rect.height/2-95)),size=(2*left.rect.width/3,30),command=first,button_color=BLUE,text_color=WHITE))
buttons.append(pygu.gui.Button(text='Second',font=font,pos=(left.rect.width/6,(left.rect.height/2-55)),size=(2*left.rect.width/3,30),command=Oldmain,button_color=BLUE,text_color=WHITE))
buttons.append(pygu.gui.Button(text='Third',font=font,pos=(left.rect.width/6,(left.rect.height/2-15)),size=(2*left.rect.width/3,30),command=Oldmain,button_color=BLUE,text_color=WHITE))
buttons.append(pygu.gui.Button(text='Fourth',font=font,pos=(left.rect.width/6,(left.rect.height/2+25)),size=(2*left.rect.width/3,30),command=Oldmain,button_color=BLUE,text_color=WHITE))
buttons.append(pygu.gui.Button(text='Fifth',font=font,pos=(left.rect.width/6,(left.rect.height/2+65)),size=(2*left.rect.width/3,30),command=Oldmain,button_color=BLUE,text_color=WHITE))
for b in buttons:
	b.render(left.image)

pygame.display.flip()


# Initialize Sprite Groups
AllSpritesGroup = pygame.sprite.OrderedUpdates()
NodeSpritesGroup = pygame.sprite.Group()
LinkSpritesGroupRed = pygame.sprite.Group()
LinkSpritesGroupGreen = pygame.sprite.Group()
LinkSpritesGroupYellow = pygame.sprite.Group()
	
# Initialize Dictionaries
NodeDict = {}
LinkDict = {}


if __name__ == '__main__': 
#	Menu()
	Oldmain()