Added Actor object, collision now works on rects as well as points
+from Sprite import *
+
+class Actor:
+ def __init__(self, surfaces=None):
+ self.states = {}
+ self.currentstate = None
+ self.surfaces = surfaces
+ self.position = [0,0]
+ self.vgravity = 0
+
+
+ def defineState(self, statename, sprite):
+ self.states[statename] = sprite
+
+
+ def setState(self, statename):
+ self.currentstate = statename
+ self.states[self.currentstate].reset()
+ self.states[self.currentstate].play()
+
+
+ def setPosition(self, x, y):
+ self.position = [x,y]
+
+
+ def collideDelta(self, delta):
+ if not self.surfaces:
+ return False
+ s = self.states[self.currentstate]
+ # Don't panic. We don't care about the sprite's position since
+ # we keep track of it ourself.
+ s.setPosition(self.position[0], self.position[1])
+ s.hitbox.move_ip(delta[0], delta[1])
+ if self.surfaces.collideRect(s.hitbox):
+ return True
+ else:
+ return False
+
+
+ def moveDelta(self, delta):
+ collided = False
+ s = self.states[self.currentstate]
+ s.setPosition(self.position[0], self.position[1])
+ d = [0,0]
+ if self.surfaces.collideRect(s.hitbox) or (delta[0] == 0 and delta[1] == 0):
+ return (True, (0,0))
+ if abs(delta[0]) > abs(delta[1]):
+ dx = delta[0] / abs(delta[0])
+ dy = float(delta[1]) / float(abs(delta[0]))
+ xrange = abs(int(delta[0]))
+ while xrange > 0:
+ d[0] += dx
+ d[1] += dy
+ nrect = s.hitbox.move(d[0],d[1])
+ if self.surfaces.collideRect(nrect):
+ # Slide along surfaces if possible
+ nrect = s.hitbox.move(d[0],d[1]-dy)
+ if not self.surfaces.collideRect(nrect):
+ d[1] -= dy
+ xrange -= 1
+ continue
+ nrect = s.hitbox.move(d[0]-dx,d[1])
+ if dy != 0 and not self.surfaces.collideRect(nrect):
+ d[0] -= dx
+ xrange -= 1
+ continue
+ d[0] -= dx
+ d[1] -= dy
+ collided = True
+ break
+ xrange -= 1
+ d[1] = int(d[1])
+ else:
+ dy = delta[1] / abs(delta[1])
+ dx = float(delta[0]) / float(abs(delta[1]))
+ yrange = abs(int(delta[1]))
+ while yrange > 0:
+ d[1] += dy
+ d[0] += dx
+ nrect = s.hitbox.move(d[0],d[1])
+ if self.surfaces.collideRect(nrect):
+ # Slide along surfaces if possible
+ nrect = s.hitbox.move(d[0]-dx,d[1])
+ if not self.surfaces.collideRect(nrect):
+ d[0] -= dx
+ yrange -= 1
+ continue
+ nrect = s.hitbox.move(d[0],d[1]-dy)
+ if dx != 0 and not self.surfaces.collideRect(nrect):
+ d[1] -= dy
+ yrange -= 1
+ continue
+ d[1] -= dy
+ d[0] -= dx
+ collided = True
+ break
+ yrange -= 1
+ d[0] = int(d[0])
+ return (collided, d)
+
+
+ def move(self, delta):
+ (collided, delta) = self.moveDelta(delta)
+ self.position[0] += delta[0]
+ self.position[1] += delta[1]
+ return collided
+
+
+ def update(self):
+ "Override this function. Called once per frame."
+ pass
+
+
+ def draw(self):
+ self.states[self.currentstate].drawAt(self.position)
fpsman = pygame.time.Clock()
-
def init(resolution=(640,480)):
pygame.init()
try:
animating = False
anim_t = 0
size = (0,0)
- uparrow = False
displaylists = None
+ showup = False
+ showhitbox = False
+
def __init__(self, file, position=(0,0), scale=1.0, rotation=0,
mirror=False, flip=False, color=(1.0,1.0,1.0,1.0),
framerate=0.0, gravity=(LEFT,BOTTOM)):
- self.position = position
- self.scale = scale
- self.rotation = rotation
- self.mirror = mirror
- self.flip = flip
- self.color= color
- self.setFramerate(framerate)
- self.gravity = gravity
-
self.frames = []
d = None
if type(file) == type([]):
d = TexMan.load(file)
self.frames.append(d['texture'])
self.size = d['size']
- self.rect = pygame.Rect(self.position, self.size)
self.tsize = d['tsize']
+ self.rotation = rotation
+ self.mirror = mirror
+ self.flip = flip
+ self.color = color
+ self.setFramerate(framerate)
+ self.scale = scale
+ self.position = position
+ self.gravity = gravity
+
+ self.fixHitbox()
self.gen_displaylist()
def setPosition(self, x, y):
self.position = (x,y)
- self.rect.move_ip(x,y)
+ self.hitbox.topleft = (x + self.hitbox_offset[0], y + self.hitbox_offset[1])
def setColor(self, r, g, b, a = 1.0):
def setScale(self, scale):
self.scale = scale
-
+ self.fixHitbox()
+
- def setGravity(self, xg, yg):
+ def fixHitbox(self):
+ self.hitbox_offset = [0,0]
+ for i in range(0,2):
+ if self.gravity[i] == -1:
+ self.hitbox_offset[i] = 0
+ elif self.gravity[i] == 0:
+ self.hitbox_offset[i] = -(self.size[0] * self.scale) / 2
+ elif self.gravity[i] == 1:
+ self.hitbox_offset[i] = -(self.size[0] * self.scale)
+ self.hitbox = pygame.Rect((self.position[0] + self.hitbox_offset[0], self.position[1] + self.hitbox_offset[1]), (self.size[0] * self.scale, self.size[1] * self.scale))
+
+
+ def setGravity(self, xg, yg, genlist=True):
if self.gravity != (xg,yg):
self.gravity = (xg,yg)
- self.gen_displaylist()
+ if genlist:
+ self.gen_displaylist()
+ self.fixHitbox()
def setFramerate(self, rate):
def play(self):
- self.animating = True
+ if len(self.frames) > 1:
+ self.animating = True
def stop(self):
if self.scale != 1.0:
glScalef(self.scale, self.scale, 1.0)
glCallList(self.displaylists[self.frameno])
- if self.uparrow:
+ if self.showup:
glDisable(GL_TEXTURE_2D)
glColor3f(0.0,0.0,1.0)
glBegin(GL_TRIANGLES)
glVertex(5, 0, 0)
glEnd()
glPopMatrix()
+ if self.showhitbox:
+ glDisable(GL_TEXTURE_2D)
+ glColor3f(1.0,1.0,1.0)
+ glBegin(GL_LINE_LOOP)
+ glVertex(self.hitbox.left, self.hitbox.bottom, 0)
+ glVertex(self.hitbox.left, self.hitbox.top, 0)
+ glVertex(self.hitbox.right, self.hitbox.top, 0)
+ glVertex(self.hitbox.right, self.hitbox.bottom, 0)
+ glEnd()
# detailed check
self.rect = pygame.Rect(p1,(self.dx,self.dy))
self.rect.normalize()
- self.rect.width += 1
- self.rect.height += 1
- # Expand the collision rect for nearly horizontal or vertical
- # surfaces
- if abs(self.m_x) < 0.2: # 5:1 ratio or more
- self.rect.height += 2*self.fuzz
- self.rect.top -= self.fuzz
- elif abs(self.m_y) < 0.2: # 1:5 ratio or less
- self.rect.width += 2*self.fuzz
- self.rect.left -= self.fuzz
-
-
- def collide(self, point):
- if self.rect.collidepoint(point[0],point[1]):
- if self.m_x > -1.0 and self.m_x < 1.0:
- if self.dx > 0:
- if point[1] < self.m_x * point[0] + self.b_x:
- return True
- else:
- if point[1] > self.m_x * point[0] + self.b_x:
- return True
+ #self.rect.width += 1
+ #self.rect.height += 1
+
+
+ def lineSideTest(self, point):
+ if self.m_x > -1.0 and self.m_x < 1.0:
+ if self.dx > 0:
+ if point[1] < self.m_x * point[0] + self.b_x:
+ return True
+ else:
+ if point[1] > self.m_x * point[0] + self.b_x:
+ return True
+ else:
+ if self.dy > 0:
+ if point[0] > self.m_y * point[1] + self.b_y:
+ return True
else:
- if self.dy > 0:
- if point[0] > self.m_y * point[1] + self.b_y:
- return True
- else:
- if point[0] < self.m_y * point[1] + self.b_y:
- return True
+ if point[0] < self.m_y * point[1] + self.b_y:
+ return True
return False
+ def collidePoint(self, point):
+ if self.rect.collidepoint(point[0],point[1]):
+ return self.lineSideTest(point)
+
+
+ def collideRect(self, rect):
+ if not self.rect.colliderect(rect):
+ return False
+ #print self.collidePoint(rect.bottomleft), self.collidePoint(rect.bottomright), self.collidePoint(rect.topright), self.collidePoint(rect.topright)
+ return self.lineSideTest(rect.bottomleft) or \
+ self.lineSideTest(rect.bottomright) or \
+ self.lineSideTest(rect.topright) or \
+ self.lineSideTest(rect.topright)
+
+
def draw(self):
angle = math.atan(self.m_x)
if self.dx < 0 or self.dy < 0:
else:
arrow = (angle+math.pi/2) % (2*math.pi)
anglepoint = (math.cos(arrow) * 10, math.sin(arrow) * 10)
+
glPushMatrix()
glDisable(GL_TEXTURE_2D)
+
+ if self.dx > 0:
+ py = self.rect.top # rects are upside-down in our space
+ else:
+ py = self.rect.bottom - 1
+ if self.dy > 0:
+ px = self.rect.right - 1
+ else:
+ px = self.rect.left
+ glColor4f(1.0,0.0,0.0,0.25)
+ glBegin(GL_TRIANGLES)
+ glVertex3f(self.p2[0], self.p2[1], 0)
+ glVertex3f(self.p1[0], self.p1[1], 0)
+ glVertex3f(px, py, 0)
+ glEnd()
+
glColor3f(1.0,1.0,1.0)
glBegin(GL_LINES)
glVertex3f(self.p1[0],self.p1[1],0)
glVertex3f(self.rect.centerx, self.rect.centery, 0)
glVertex3f(self.rect.centerx + anglepoint[0], self.rect.centery + anglepoint[1], 0)
glEnd()
+
glPopMatrix()
class Solid:
def __init__(self, p1, p2):
self.rect = pygame.Rect(p1,(p2[0]-p1[0],p2[1]-p1[1]))
+ self.rect.normalize()
- def collide(self, point):
+ def collidePoint(self, point):
return self.rect.collidepoint(point[0],point[1])
+ def collideRect(self, rect):
+ return bool(self.rect.colliderect(rect))
+
+
+ def draw(self):
+ glPushMatrix()
+ glDisable(GL_TEXTURE_2D)
+ glColor4f(1.0,0.0,0.0,0.25)
+ glBegin(GL_QUADS)
+ glVertex(self.rect.left, self.rect.bottom, 0)
+ glVertex(self.rect.left, self.rect.top, 0)
+ glVertex(self.rect.right, self.rect.top, 0)
+ glVertex(self.rect.right, self.rect.bottom, 0)
+ glEnd()
+ glColor3f(1.0,1.0,1.0)
+ glBegin(GL_LINE_LOOP)
+ glVertex(self.rect.left, self.rect.bottom, 0)
+ glVertex(self.rect.left, self.rect.top, 0)
+ glVertex(self.rect.right, self.rect.top, 0)
+ glVertex(self.rect.right, self.rect.bottom, 0)
+ glEnd()
+ glPopMatrix()
+
+
class SurfaceSet:
surfaces = None
f.close()
- def collide(self,point):
+ def collidePoint(self,point):
colliders = filter(lambda x: x.rect.collidepoint(point), self.surfaces)
if not colliders:
return False
- if filter(lambda x: not x, [c.collide(point) for c in colliders]):
+ if filter(lambda x: not x, [c.collidePoint(point) for c in colliders]):
+ return False
+ return True
+
+
+ def collideRect(self, rect):
+ colliders = filter(lambda x: x.rect.colliderect(rect), self.surfaces)
+ if not colliders:
+ return False
+ #print [(c,c.rect,c.collideRect(rect)) for c in colliders]
+ if filter(lambda x: not x, [c.collideRect(rect) for c in colliders]):
return False
return True
tile 6 1
tile 6 2
-solid 0 2 1 3
-surface 0 1 2 1
+solid 0 0 10 1
surface 2 1 4 2
-solid 2 0 4 1
-surface 4 2 4 5
-surface 4 5 5 5
-surface 5 5 5 1
-surface 5 1 6 1
-surface 6 1 6 3
-surface 6 3 7 3
-surface 7 3 7 1
-surface 7 1 10 1
+solid 4 1 5 5
+solid 6 1 7 3
tilesize 1 1
texture img/ByteIco.png
from Sprite import *
from Collage import *
from Surface import *
+from Actor import *
import Engine
#resolution = (1280,1024)
pygame.display.set_caption("platformtest")
ground = Collage('data/example1')
-ground.position = [0,0]
surfaces = SurfaceSet('data/example1')
stars = Collage('data/stars')
-stars.position = [0,0]
candelabra = Sprite(['Sprites/candelabra_short/cand_s_1.png','Sprites/candelabra_short/cand_s_2.png','Sprites/candelabra_short/cand_s_3.png','Sprites/candelabra_short/cand_s_4.png'])
-candelabra.position = [64, 64]
+candelabra.setPosition(64, 64)
candelabra.setScale(2.0)
candelabra.setGravity(CENTER, BOTTOM)
candelabra.setFramerate(10.0)
candelabra.play()
-player_l = Sprite(['img/richter%d.png' % n for n in range(0,8)],
- framerate=10.0, scale=2.0, gravity=(CENTER,BOTTOM))
-player_r = Sprite(['img/richter%d.png' % n for n in range(0,8)], mirror=True,
- framerate=10.0, scale=2.0, gravity=(CENTER,BOTTOM))
+class Richter(Actor):
+ def __init__(self, surfaces=None):
+ Actor.__init__(self, surfaces)
+ self.defineState('walk_l',
+ Sprite(['img/richter%d.png' % n for n in range(0,8)],
+ framerate=10.0, scale=2.0, gravity=(CENTER,BOTTOM)))
+ self.defineState('walk_r',
+ Sprite(['img/richter%d.png' % n for n in range(0,8)], mirror=True,
+ framerate=10.0, scale=2.0, gravity=(CENTER,BOTTOM)))
+ self.defineState('idle_l',
+ Sprite("img/richter0.png", scale=2.0, gravity=(CENTER,BOTTOM)))
+ self.defineState('idle_r',
+ Sprite("img/richter0.png", mirror=True, scale=2.0, gravity=(CENTER,BOTTOM)))
+ self.setState('idle_r')
-def moveObject(pos, delta):
- npos = list(pos)
- npos[0] += delta[0]
- npos[1] += delta[1]
- if surfaces.collide(npos):
- npos[1] += 1
- if surfaces.collide(npos):
- return pos
+ self.delta = [0,0]
+ self.jumping = False
+ self.grounded = self.collideDelta((0,-1))
+
+
+ def jump(self):
+ if not self.jumping and self.grounded:
+ self.delta[1] = 15.0
+ self.jumping = True
+ self.grounded = False
+
+
+ def jumpCancel(self):
+ self.jumping = False
+ if self.delta[1] > 0.0:
+ self.delta[1] = 0.0
+
+
+ def walkRight(self):
+ self.delta[0] = 2
+ self.setState('walk_r')
+
+
+ def walkLeft(self):
+ self.delta[0] = -2
+ self.setState('walk_l')
+
+
+ def idle(self):
+ if self.currentstate == 'walk_l':
+ self.setState('idle_l')
else:
- return npos
- else:
- return npos
+ self.setState('idle_r')
+ self.delta[0] = 0
+
+
+ def update(self):
+ if self.grounded:
+ self.delta[1] = 0
+ else:
+ self.delta[1] -= 0.5
+ # Climb up inclines (visually poetic, is it not?)
+ if self.grounded and self.delta[0] != 0:
+ delta = list(self.delta)
+ if self.collideDelta(delta):
+ for i in range(0,abs(delta[0])):
+ delta[1] += 1
+ if not self.collideDelta(delta):
+ self.delta = delta
+ break
+ self.move(self.delta)
+ self.grounded = self.collideDelta((0,-1))
+
+
+richter = Richter(surfaces)
+richter.setPosition(32, 64)
class gamestate:
- face = 1
- direction = [0,0]
- vgravity = 0
- position = [32,64]
+ drawsurface = False
def input(e):
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_LEFT:
- gamestate.direction[0] = -1
- gamestate.face = 0
- player_l.play()
+ richter.walkLeft()
elif e.key == pygame.K_RIGHT:
- gamestate.direction[0] = 1
- gamestate.face = 1
- player_r.play()
- elif e.key == pygame.K_DOWN:
- gamestate.direction[1] = -1
+ richter.walkRight()
elif e.key == pygame.K_UP:
- gamestate.direction[1] = 1
+ richter.jump()
+ elif e.key == pygame.K_1:
+ gamestate.drawsurface = not gamestate.drawsurface
elif e.type == pygame.KEYUP:
if e.key == pygame.K_LEFT or e.key == pygame.K_RIGHT:
- gamestate.direction[0] = 0
- player_l.stop()
- player_l.reset()
- player_r.stop()
- player_r.reset()
+ richter.idle()
elif e.key == pygame.K_UP:
- gamestate.direction[1] = 0
- if gamestate.vgravity != 0.0:
- gamestate.vgravity = 0.0
- elif e.key == pygame.K_DOWN:
- gamestate.direction[1] = 0
+ richter.jumpCancel()
def update():
- if gamestate.direction[1] == 1 and gamestate.vgravity == 0:
- gamestate.vgravity = 20.0
- gamestate.vgravity -= 0.5
- npos = [gamestate.position[0], gamestate.position[1] + gamestate.vgravity]
- if surfaces.collide(npos):
- npos[1] -= 1
- if surfaces.collide(npos):
- gamestate.vgravity = 0
- else:
- gamestate.position = npos
- # Move two pixels in whatever direction we're going, only horizontal
- gamestate.position = moveObject(gamestate.position,(gamestate.direction[0]*2,0))
- #ground.position[0] = gamestate.position[0] - resolution[0]/2
- #stars.position[0] = int(ground.position[0] / 5.0)
- #candelabra.position[0] -= ground.position[0] + 64
- if gamestate.position[1] < 0:
- gamestate.position = [gamestate.position[0],480]
+ richter.update()
+ if richter.position[1] < 0:
+ richter.position = [richter.position[0],480]
def draw():
stars.draw()
ground.draw()
candelabra.draw()
- if gamestate.face == 1:
- player_r.drawAt(gamestate.position)
- else:
- player_l.drawAt(gamestate.position)
+ richter.draw()
+ if gamestate.drawsurface:
+ surfaces.draw()
n = 0
def fpsthing():
n += 1
if n == 100:
fps = "%0.1f FPS" % Engine.fpsman.get_fps()
- pygame.display.set_caption("bouncetest [%s]" % fps)
+ pygame.display.set_caption("platformtest [%s]" % fps)
print fps
n = 0