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

Re: [pygame] speed problem: max 6 fps



... and here are the attachements.

yours,
Gerrit.

-- 
Asperger Syndroom - een persoonlijke benadering:
	http://people.nl.linux.org/~gerrit/
Het zijn tijden om je zelf met politiek te bemoeien:
	http://www.sp.nl/
#!/usr/bin/env python -tt

import sys
import time
from random import randint

import pygame
from pygame.locals import *

import sprites
import errors
import world

size = (2500, 3000)
res = (1024, 768)

def main():
	pygame.init()
	wereld = world.World(size, res)
	clock = pygame.time.Clock()

	sprites.init(wereld)
	player = sprites.Player((100,100))

	wereld.border(50)
	[wereld.placerandomwall(50, 100, 50, 100) for _ in xrange(50)]
	background = pygame.Surface(wereld.world.get_size()).convert()
	background.fill((10, 20, 40))

	while True:
		clock.tick(30)
		print "fps", clock.get_fps()
		##for event in pygame.event.get():
			##if event.type == KEYDOWN and event.key == K_ESCAPE:
				##return

		keystate = pygame.key.get_pressed()

		x = keystate[K_RIGHT] - keystate[K_LEFT]
		y = keystate[K_DOWN] - keystate[K_UP]
		s = keystate[K_SPACE]
		if keystate[K_ESCAPE]: return
			
		player.move([x, y])
		if s and bool(x)^bool(y):
			try: player.shoot([x, y])
			except errors.CantShoot:
				c, i, t = sys.exc_info()

		sprites.all.update()

		wereld.center(player.rect)
		wereld.world.blit(background, (0,0))

		allsprites = sprites.all.sprites()
		allrects = [s.rect for s in allsprites]
		for sprite_index in wereld.src.collidelistall(allrects):
			s = allsprites[sprite_index]
			wereld.world.blit(s.image, s.rect)
			
		##sprites.all.draw(wereld.world) # NO, NO, NO!
		wereld.display.blit(wereld.world, (0,0), wereld.src)
		pygame.display.update()


PROFILE = True
if __name__ == '__main__':
	if PROFILE:
		import profile
		profile.run('main()', 'brian.pfl')
	else:
		main()
#!/usr/bin/python

import time

class MyError:
	pass

class UnDefined(NotImplementedError):
	def __init__(self, _class, attr):
		self._class = _class
		self.attr = attr
	
	def __str__(self):
		return '%s.%s missing' % (self._class, self.attr)

class WrongDefined(UnDefined):
	def __str__(self):
		return '%s.%s defined wrong' % (self._class, self.attr)

class CantShoot(MyError):
	def __init__(self, me, why):
		self.me = me
		self.why = why
	
	def __str__(self):
		return "%s unable to shoot: %s" % (self.me, self.why)

class UnableShooting(CantShoot):
	def __init__(self, me):
		self.me = me
	
	def __str__(self):
		return "%s has no shooting ability" % self.me

class ShootingReload(CantShoot):
	def __init__(self, me, st, rt):
		self.me = me
		self.st = st
		self.rt = rt

	def __str__(self):
		me = self.me
		st = self.st
		rt = self.rt
		ct = time.time()
		dt = ct - st
		wt = rt - dt
		
		return "%s: %.3f seconds since last shot, wait %.2f more seconds" % (me, dt, wt)

class Collision(MyError):
	def __init__(self, src, dest):
		self.src = src
		self.dest = dest
	
	def __str__(self):
		return "%s collides with %s" % (self.src, self.dest)
#/usr/bin/python -tt

from __future__ import division

import operator
import time

import pygame
from pygame.constants import *

import errors
import world
#from constants import *

def debug(*m):
	print time.time(),
	for i in m: print i,
	print

all = pygame.sprite.RenderUpdates()
creatures = pygame.sprite.Group()
bullets = pygame.sprite.Group()
walls = pygame.sprite.Group()

initialized = False
def init(w):
	Sprite.area = w.world.get_rect()
	Sprite.world = w

	global initialized
	initialized = True

def accelmove(goal, steps, back, kill):
	"""accelmove(goal, steps, back, kill) --> iterator

	Returns an iterator which, if looped and moved according to, will
	accelerate or decellerate. For example:
	
		>>> i=accelmove(3, 5, True, True)
		>>> i.next();i.next();i.next();i.next();i.next();i.next()
		  1.2
		  0.89999999999999991
		  0.59999999999999998
		  0.29999999999999999
		  0.0 # sum of these 5 is 3
		  Traceback (most recent call last):
			File "<stdin>", line 1, in ?
			StopIteration
		>>> i=accelmove(5, 3, False, False)
		>>> i.next();i.next();i.next();i.next();i.next();i.next();i.next()
		 0.0
		 1.6666666666666667
		 3.3333333333333335
		 3.3333333333333335
		 3.3333333333333335
	
	goal:	sum of all different results, so when moving 10 while accelerating,
			goal=10 does the job.

	steps:	number of steps to achieve the goal. This can be used to specify
			acceleration speed.
	
	back:	decelerate instead of accelerate (largest numbers will be first).

	kill:	kill the iterator when finished. Useful when jumping, not useful
			when falling.
	"""
	total = reduce(operator.add, range(steps))
	factor = float(total)/goal
	if back:
		d = -1
	else:
		d = 1
	for i in range(steps)[::d]:
		yield i/factor
	if not kill:
		while 1:
			yield i/factor


class Sprite(pygame.sprite.Sprite):

	def __init__(self, startpos):
		for attr in 'image', 'size', 'groups':
			if not hasattr(self, attr):
				raise errors.UnDefined(self.__class__, attr)
		if not initialized:
			raise errors.MyError("Not initialized")

		pygame.sprite.Sprite.__init__(self, self.groups + (all,))

		self.image.convert()

		rect = self.image.get_rect()
		rect.move_ip(startpos)

		self.rect = rect
	
	def __setattr__(self, attr, val):
		self.__dict__[attr] = val
		if attr == 'image':
			self.rect = self.image.get_rect()
	
	def __repr__(self):
		return "<%s sprite(in %d groups) id=%s>" % (self.__class__.__name__, len(self.__g), hex(id(self)))

class Creature(Sprite):
	groups = (creatures,)
	gravity = True
	__f = None

	def __init__(self, *args):
		for attr in 'speed', 'fallspeed', 'falltime':
			if not hasattr(self, attr) and self.attr:
				raise errors.UnDefined(self.__class__, attr)

		Sprite.__init__(self, *args)
		self.spritespeed = self.speed[:]
	
	def falling(self):
		"""falling() -> bool

		Returns True if sprite should fall now, which is true is
		gravity is True and no wall is directly below.
		"""

		if not self.gravity: return False
		for spr in walls.sprites():
			if self.rect.right < spr.rect.left or self.rect.left > spr.rect.right:
				continue
			if self.rect.bottom == spr.rect.top:
				return False
		return True
	
	def fallgen(self):
		return accelmove(self.falltime, self.fallspeed/self.spritespeed[1], False, False)

	def update(self):
		self.rect.move_ip(self.speed)

	def adjustmove(self, speed):
		"""
		adjustmove(speed) --> (speed, walls)
		Returns a tuple of the true offset moved and the walls
		which prevent it from moving the amount ordered. The true offset
		moved is also influenced by the speed, which is an instance
		attribute (spritespeed).

		FIXME: wellicht beter algoritme? Alle walls uitzoeken?
		"""

		x = y = 0
		s = max([abs(s) for s in speed])
		if s == 0:
			return (0, 0), ()
		xstep = speed[0]/s
		ystep = speed[1]/s
		wrs = [wall.rect for wall in self.world.localwalls()]
		w = []

		seq = range(0, s, -1)
		for i in range(0, s, int(max(speed)>=min(speed)) or -1):
			if speed[0] != 0:
				wx = self.rect.move((x+xstep, y)).collidelist(wrs)
				if wx == -1:
					x += xstep
				else:
					if not wrs[wx] in w:
						w.append(wrs[wx])
			if speed[1] != 0:
				wy = self.rect.move((x, y+ystep)).collidelist(wrs)
				if wy == -1:
					y += ystep
				else:
					if not wrs[wy] in w:
						w.append(wrs[wy])
		return (x, y), w
		

	def move(self, direction):
		"""move((x,y)) --> ((x,y), list)

		Moves the sprite by the given amount or less. Return value as
		adjustmove().

		TODO: vallen volgens zwaartekracht. Wellicht combi met springen?
		"""

		speed = []
		if self.falling():
			if self.__f:
				direction[1] = self.__f.next() / self.spritespeed[1]
			else:
				self.__f = self.fallgen()
		else:
			self.__f = None
		for i in range(len(direction)):
			speed.append(direction[i] * self.spritespeed[i])

		speed, wall = self.adjustmove(speed)
		self.speed = speed
		return speed, wall
	
class JumpingCreature(Creature):
	jumping = False
	__j = iter([])
	
	def __init__(self, *args):
		for attr in 'jumpheight',:
			if not hasattr(self, attr) or not isinstance(self.jumpheight, int):
				raise errors.UnDefined(self.__class__, attr)
		Creature.__init__(self, *args)

	def jumpgen(self, g, n):
		return accelmove(g, n, True, True)

	def canjump(self):
		"""canjump() -> bool

		Returns True if creature is CURRENTLY able to jump. This is False if
		it's already jumping, if it's falling or if either gravity or
		the ability to jump does not exist.
		"""
		if self.falling() or self.jumping or not self.gravity or not self.jumpheight: return False
		return True
	
	def startjump(self, h):
		"""startjump() -> None

		Starts to jump now.
		"""
		self.__j = self.jumpgen(h, h/self.spritespeed[1])
		self.jumping = True
	
	def endjump(self):
		"""endjump() -> None

		End to jump now (will probably start falling).
		"""
		self.__j = iter([])
		self.jumping = False
	
	def falling(self):
		"""falling() --> bool

		Checks whether the sprite is falling
		"""
		if self.jumping:
			return False
		else:
			return Creature.falling(self)

	def move(self, direction):
		if direction[1] <= -1 and self.canjump():
			self.startjump(self.jumpheight)
		if self.jumping:
			if direction[1] >= 0:
				self.endjump()
			else:
				try:
					n = self.__j.next()
					direction[1] = -n/self.spritespeed[1]
				except StopIteration:
					self.endjump()
					direction[1] = 0
			expspeed = self.speed
			truespeed, wall = Creature.move(self, direction)
			if wall and self.jumping: self.endjump()
		else:
			Creature.move(self, direction)
	
class ShootingCreature(Creature):
	canshoot = True
	shoottime = 0

	def __init__(self):
		if not issubclass(self.getbullet(), Bullet):
			raise errors.WrongDefined(self.__class__, 'getbullet')
		Creature.__init__(self)

	def getbullet(self):
		"""getbullet() --> class

		Returns a class which is a subclass of Bullet.
		Should be overloaded.
		"""
		raise UnDefined(self.__class__, 'getbullet')

	def shoot(self, direction):
		"""shoot(direction) --> None

		Shoots Bullet in direction.
		"""
		if not self.canshoot:
			raise errors.UnableShooting(self)
		if self.getbullet().reloadtime > time.time()-self.shoottime:
			raise errors.ShootingReload(self, st=self.shoottime, rt=self.getbullet().reloadtime)
		bullet = self.getbullet()(self, direction)
		self.shoottime = time.time()

class Player(JumpingCreature, ShootingCreature):
	speed = [9, 9]
	size = (50, 50)
	jumpheight = 150	# FIXME: should be mass...
	falltime = 300		# FIXME: should be mass...
	fallspeed = 150		# FIXME: should be mass...
	canshoot = True
	def getbullet(self): return PlayerBullet

	image = pygame.Surface(size)
	pygame.draw.rect(image, (0, 255, 0), image.get_rect(), 5)


class Wall(Sprite):
	groups = (walls,)

class SimpleWall(Wall):

	def __init__(self, size, *args):
		self.size = size
		self.image = pygame.Surface(size)
		pygame.draw.rect(self.image, (255, 0, 0), self.image.get_rect(), 25)
		Wall.__init__(self, *args)
		c = [s for s in pygame.sprite.spritecollide(self, walls, False) if s is not self]
		if c:
			self.kill()
			raise errors.Collision(self, c[0])

class Bullet(Sprite):
	groups = (bullets,)

	def __init__(self, origin, direction):
		for attr in 'speed', 'lifetime', 'reloadtime',:
			if not hasattr(self, attr):
				raise errors.UnDefined(self.__class__, attr)
		Sprite.__init__(self, origin.rect.center)
		self.origin = origin
		self.direction = direction
		self.starttime = time.time()
	
	def update(self):
		d = self.direction
		s = self.speed
		self.rect.move_ip([d[0]*s[0], d[1]*s[1]])
		if not self.area.contains(self.rect) or \
			time.time() - self.starttime > self.lifetime or \
			self.collides():
			self.kill()
	
	def collides(self):
		wallrects = [w.rect for w in walls.sprites()]
		found = self.rect.collidelist(wallrects)
		return found != -1
		

class PlayerBullet(Bullet):
	speed = [30, 30]
	size = (15, 15)
	image = pygame.Surface(size)
	lifetime = 1
	reloadtime = .3
	pygame.draw.circle(image, (255, 255, 0), image.get_rect().center, 7.5)


#!/usr/bin/python

from random import randint

import pygame
from pygame.constants import *

import errors
import sprites

class World:
	__cached_local_walls = []
	def __init__(self, size, res, fullscreen=True):
		self.size = size
		self.res = res
		self.src = pygame.Rect(0, 0, res[0], res[1])
		self.__cached_src = self.src.move((0,0))
		self.world = pygame.Surface(size)
		try:
			if fullscreen:
				self.display = pygame.display.set_mode(res, FULLSCREEN)
			else:
				self.display = pygame.display.set_mode(res)
		except pygame.error, m:
			if str(m) == 'No available video device':
				print 'ach...'
	
	def center(self, r):
		"""center(rect) --> None

		Centreert op gegeven Rect object.
		"""

		x, y = r.center
		res = self.res
		self.src = src = pygame.Rect(x-.5*res[0], y-.5*res[1], res[0], res[1])
		if src.left < 0:
			self.scroll((-src.left, 0))
		if src.right > self.size[0]:
			self.scroll((self.size[0]-src.right, 0))
		if src.top < 0:
			self.scroll((0, -src.top))
		if src.bottom > self.size[1]:
			self.scroll((0, self.size[1]-src.bottom))
		#self.src = src
	
	def border(self, w):
		"""border(width) --> list

		Creates a border around the world with width as width.
		Returns list of created walls.
		"""
		l = []
		x, y = self.size
		l.append(sprites.SimpleWall((x, w), (0, 0)))
		l.append(sprites.SimpleWall((x, w), (0, y-w)))
		l.append(sprites.SimpleWall((w, y-2*w), (0, w)))
		l.append(sprites.SimpleWall((w, y-2*w), (x-w, w)))
		return l
	
	def localwalls(self):
		"""localwalls() --> list

		Returns a list of walls which are in the current display src.
		"""

		if self.src == self.__cached_src:
			return self.__cached_local_walls

		rv = []

		for wall in sprites.walls.sprites():
			if self.src.colliderect(wall.rect):
				rv.append(wall)

		self.__cached_local_walls = rv
		self.__cached_src = self.src.move((0, 0))
		return rv

	def placerandomwall(self, minw, maxw, minh, maxh, wall=None):
		"""placerandomwall(minw, maxw, minh, maxh, wall) --> Wall object

		Places a random wall, at least minw wide and minh high, and
		at max maxw wide and maxh high. The optional wall argument
		is the class to use te create the wall. This should be compatible
		with the SimpleWall class in the sprites module.
		"""
		succes = False
		wall = wall or sprites.SimpleWall

		while not succes:
			w = randint(minw, maxw)
			h = randint(minh, maxh)
			x = randint(w, self.size[0] - w)
			y = randint(h, self.size[1] - h)
			try:
				sprites.SimpleWall((w, h), (x, y))
				succes = True
			except errors.Collision:
				succes = False


	def scroll(self, (x,y)):
		"""scroll((x, y)) --> None

		Scrollt scherm over (x, y) positie.
		"""

		self.src.left += x
		self.src.top += y