Added inter-actor collision event support
Changed state handling in Actor so that sprite hitbox always tracks with
Actor movment (provided you use setPosition() or move()). Added
inter-actor collision checking to Actor, which gets called in the Layer
update() path. Also fixed event handler loading to generate an instance
method instead of a function (which didn't work).
FIXME: Change object collision tracking to use QuadTree instead of list
class Actor:
def __init__(self, surfaces = None, position = [0,0]):
self.states = {}
+ self.currentstatename = None
self.currentstate = None
self.surfaces = surfaces
self.position = position
+ self.hitbox = None
+ self.colliding = set()
def defineState(self, statename, sprite):
+ if self.states.has_key(statename):
+ print "WARNING: Redefining state", statename
self.states[statename] = sprite
def setState(self, statename):
- self.currentstate = statename
- self.states[self.currentstate].reset()
- self.states[self.currentstate].play()
+ self.currentstatename = statename
+ self.currentstate = self.states[statename]
+ self.currentstate.reset()
+ self.currentstate.play()
+ self.currentstate.setPosition(self.position[0], self.position[1])
+ self.hitbox = self.currentstate.hitbox
def setPosition(self, x, y):
self.position = [x,y]
+ self.currentstate.setPosition(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):
+ s = self.currentstate
+ new_hitbox = s.hitbox.move(delta[0], delta[1])
+ if self.surfaces.collideRect(new_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])
+ s = self.currentstate
d = [0,0]
if self.surfaces.collideRect(s.hitbox) or (delta[0] == 0 and delta[1] == 0):
return (True, (0,0))
(collided, delta) = self.moveDelta(delta)
self.position[0] += delta[0]
self.position[1] += delta[1]
+ self.currentstate.setPosition(self.position[0], self.position[1])
if collided:
self.hitWall()
return collided
+ def collideCheck(self, objs):
+ """Test whether another object in objs is colliding with us,
+ and if so, trigger a collision event"""
+
+ if not self.surfaces: return
+
+ remove = []
+ for o in self.colliding:
+ if not self.hitbox.colliderect(o.hitbox):
+ remove.append(o)
+ for o in remove:
+ self.colliding.remove(o)
+ o.colliding.remove(self)
+ self.collideEnd(o)
+ o.collideEnd(self)
+
+ #for o in objs.collideRectWalk(self.hitbox):
+ for i in self.hitbox.collidelistall(filter(None, [o.hitbox for o in objs])):
+ o = objs[i]
+ if o is self: continue
+ if o not in self.colliding:
+ self.colliding.add(o)
+ o.colliding.add(self)
+ self.collideStart(o)
+ o.collideStart(self)
+
+
def hitWall(self):
"Called when this object hits a wall after attempting to move"
pass
def draw(self):
- self.states[self.currentstate].drawAt(self.position)
+ self.currentstate.draw()
import sys
import os
import re
+import new
import yaml
from Collage import Collage
from Surface import SurfaceSet
def update(self):
for t in self.things:
t.update()
+ t.collideCheck(self.things)
def drawSurfaces(self):
print "Malformed function definition:", fdef
continue
+ funcname = m.group(1)
code = "def %s:\n" % m.group(0)
for s in str.split("\n"):
if not s: continue
code += "\t" + s + "\n"
- code += "%s.%s = %s\n" % (name, m.group(1), m.group(1))
- code += "del %s\n" % m.group(1)
exec code in self.env
+ f = new.function(self.env[funcname].func_code, self.env)
+ self.env[name].__dict__[funcname] = new.instancemethod(f, self.env[name], self.env[name].__class__)
+ del self.env[funcname]
layer.add(self.env[name])