[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