commit:8c878961bdf11ca833405143241d3756abfa1a95
author:Chip Black
committer:Chip Black
date:Mon Jul 28 03:52:10 2008 -0500
parents:6a20a91fa833722820ab35501b9ae0066eab5dce
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
diff --git a/Richter/Actor.py b/Richter/Actor.py
line changes: +45/-12
index 07a4ee6..bcfa6fb
--- a/Richter/Actor.py
+++ b/Richter/Actor.py
@@ -3,34 +3,40 @@ from Sprite import *
 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
@@ -38,8 +44,7 @@ class Actor:
 
 	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))
@@ -102,11 +107,39 @@ class Actor:
 		(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
@@ -128,4 +161,4 @@ class Actor:
 
 
 	def draw(self):
-		self.states[self.currentstate].drawAt(self.position)
+		self.currentstate.draw()

diff --git a/Richter/Level.py b/Richter/Level.py
line changes: +6/-2
index 1e6d984..84b13ec
--- a/Richter/Level.py
+++ b/Richter/Level.py
@@ -1,6 +1,7 @@
 import sys
 import os
 import re
+import new
 import yaml
 from Collage import Collage
 from Surface import SurfaceSet
@@ -44,6 +45,7 @@ class Layer:
 	def update(self):
 		for t in self.things:
 			t.update()
+			t.collideCheck(self.things)
 
 
 	def drawSurfaces(self):
@@ -139,13 +141,15 @@ class Level:
 						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])