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

Re: [pygame] Toats



Hello. This reply is pretty long, hope it helps :)

On Jan 5, 2008 12:57 PM, Bernard Quinn <bjquinniii@xxxxxxxxx> wrote:
> 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

If in the future you need 3d, you can use pygame with OpenGL.

> 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

I have a few tips. For 2d and 3d geometry, and vectors, check out the
'euclid' module.
http://www.partiallydisassembled.net/euclid/contents.html

	# example usage: see link for more
	from euclid import *
	v = Vector2( 123, 456 )

If you need multidimensional arrays, look into NumPy ( usage tutorial:
http://www.scipy.org/Tentative_NumPy_Tutorial )

The first line after a function and/or class holds a doc string. It's
used to grab documentation from the code. You did this for your Node()
class, and you can even do it for the methods, ie: in
Node.calcnewpos()

When you import: "from pygame.locals import *" it imports a lot of
common colors. You can use them without having to define rgb values:

	# get the color red
	foo = pygame.color.Color( "red" )

if you need a 'pointer' to other nodes, like a vertex with a list of
pointers to connected vertexes, you can use sprite lists. Have each
Node() have its own sprite list containing each of the connected
Node()s. So you would probably have one list containing all nodes to
draw, then:

	# psuedo-code:
	# node
	node_spritelist.draw()
	# node connections: foreach node: foreach connected
	for cur_node in node_spritelist.sprites():
		for cur_connection in cur_node.connections.sprites():
			# draw line from cur_node to cur_connection

I've heard there isn't much overhead for using lots of spritegroups,
and having sprites in multiple groups, so you can use them like this.
( Sprite() and sprite groups ref:
http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Sprite )

> 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

I'm not sure if PyGU has any functions for this ( I haven't used PyGU
), but todo it:

First get a mousedown or mouseup event to catch a click's coordinates.
Then check if that point is inside the Rect() of the button.

# in your event loop:
	elif event.type == MOUSEBUTTONDOWN:
		x,y = event.pos
		# now check if x,y collides with your button rect
		# note: depending on what you want, you might prefer event:MOUSEBUTTONUP

Note: that code doesn't care which button is pressed. here is a
reference for the events: http://www.pygame.org/docs/ref/event.html

> 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

They way I'm moving objects is I have a Vector2() named .loc, and I
have a velocity defined as pixels per second. Then I multiply the
velocity by delta ( calculated in fps.py attached to email ) It looks
like this

# code, in your unit/node class
class Unit( pygame.sprite.Sprite ):
	"""base unit class, with .loc, and .vel"""

	def update(self):
		"""do physics"""
		pygame.sprite.Sprite.update(self)

		# time based movement
		self.loc += self.vel * fps.delta

		# note:
		# if using .rect member to render, use .rect here instead of .loc
		# or set .rect based on .loc.x, and .loc.y

You don't have to use a Vector2() for .vel, just multiple fps.delta to
dx and dy in your .calcnewpos() method
		
I made a simple class fps that just calcs delta for you. You call it
every game update instead of calling clock.tick() ( If you want, I can
send you the full class I'm using, it has toggle-able FPS limiting,
and only re-draws fps every 1second instead of every frame )

To use it you would do:

# usage:
from fps import FPS()
# instance
fps = FPS()
# and game update
	# your update(): called every frame
	fps.tick()

# now in objects movement you can do:
	# object update():
	self.loc += self.vel * fps.delta

> 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...

For labels, have a .label member on Node(). Then use
pygame.font.Font() to render text.

What kind of manipulators? If its adding/removing connections to
nodes, use the sprite_connected example above, and just add/remove to
those groups.

>
> Joey
>
>

[for sanity] you can split your code into multiple files, and import
them. ( like the fps.py example ) Just place your other files into the
same directory as the main py file.

Right now i'm using a Game() class which holds any global variables
that other classes might need to access. Here's an example: ( Note:
all classes were in external files )

By making Game() an argument to your classes, you can call any method
Game() has, and also access its members. ( to get fps.delta, to
spawn_node(): ( which could add to Game()'s sprite list), etc... )

Here's two files to show this:

# == file: player.py ==
class Player( pygame.sprite.Sprite ):
	"""basic player class"""
	
	def __init__( self, game ):
		"""get a reference to the game class"""
		pygame.sprite.Sprite.__init__(self)
		self.sprite_w, self.sprite_h = 16, 16
		
		# references
		self.game = game
		self.fps = self.game.fps # shorthand for fps
		
		self.loc = Vector2( 0, 0 )
		self.vel = Vector2( 0, 0 )
		
		self.MAX_SPEED = 200
		
	def update(self):
		"""pysics code here"""
		pass # use self.fps.delta like above code
		
	def handle_event(self, event):
		"""handle any events specific to player"""
		# mousedown:
		if event.type == MOUSEBUTTONDOWN:
			pass # mouse pressed


# ==
# == file: game.py ==
# ==
try:	
	import pygame
	from pygame.locals import *
	# etc ...
	
	from fps import FPS # local file, same syntax to import
	from player import Player
	# etc...	
except ImportError, err:
	print "Couldn't load module. %s" % (err)
	sys.exit(2)

VERSION = "0.1.0"
WINDOW_TITLE = "toats: " + VERSION + " [ author ]"

class Game():
	"""base game logic class"""
	
	def __init__(self, width=1024, height=768):
		"""initialize game stuff"""			
		pygame.init()
		self.width, self.height = width, height
		self.screen = pygame.display.set_mode(( self.width, self.height ))
		pygame.display.set_caption( WINDOW_TITLE )
		
		# instances
		self.fps = FPS( self ) # different fps.py than attached, this use
uses game as arg
		self.player = Player( self )
		# etc...
		
		self.unit_sprites = RenderPlain()
		
	def handle_events(self):
		"""event loop"""
		for event in pygame.event.get():
			# pass copy of events to player
			self.player.handle_event( event )
			
			if event.type == pygame.QUIT: sys.exit()
			elif event.type == KEYDOWN:
				# exit on 'escape'
				if (event.key == K_ESCAPE): self.bDone = True
					
	def draw( self ):
		"""render"""
		self.screen.fill( pygame.color.Color("gray") )
		
		self.unit_sprites.draw( self.screen )
		
		pygame.display.flip()
		
	def spawn_unit( self ):
		"""spawn a unit"""
		pass # spawn code here
		
	def update( self ):
		"""game update"""
		self.fps.tick()
		
		self.unit_sprites.update()
		
	def loop( self ):
		"""main game loop"""
		self.bDone = False
		
		while not self.bDone:
			self.handle_events()
			
			self.update()
			
			self.draw()			
			# limit CPU here if you want to

# == entry point ==
if __name__ == "__main__":
	print "press ESC to quit."
	g = Game(640, 480)
	g.loop()

-- 
Jake
#!/usr/bin/python
# About: just calcs fps + delta

import pygame
from pygame.locals import *

class FPS:
	"""calcs delta
	
	self.clock.get_fps() = FPS
	self.delta = delta ( to multiply for time-based movement )
	"""
	
	def __init__(self):
		"""initialize FPS()"""
		self.clock = pygame.time.Clock()
		
		# FPS() calc's delta ( AKA: fps_elapsed )
		self.ticks_cur = pygame.time.get_ticks()
		self.ticks_last = pygame.time.get_ticks()
		
	def tick(self):
		"""call each game-loop, does .clock.tick() or .clock.tick(max_fps)
		
		Returns same value as Clock.tick()."""
		
		# calculate delta
		self.ticks_cur = pygame.time.get_ticks()		
		self.delta = ( self.ticks_cur - self.ticks_last ) / 1000.0
		self.ticks_last = self.ticks_cur
		
		return self.clock.tick()