[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] fast sqrt? and profiling



Others have made good suggestions about reducing the amount of work you do detecting collision (i.e., partitioning) and using complex numbers instead of euclid for 2d vectors. The latter made a big performance difference for me in a vector-heavy game I was working on.

If you don't want to implement efficient collision detection yourself, libraries like ODE, PyMunk and Rabbyt have fast implementations you can use (at the cost of the extra dependancy).

Not doing work at all is the best optimization -- and one a partitioning strategy does well at avoiding work in situations where collisions are relatively rare. I've made some notes below in your code suggesting ways it could be made faster, though this is not intended to be a substitute for a better algorithm, I hope it's helpful.

On Jan 20, 2009, at 10:27 PM, Jake b wrote:

5) Should I be staggering the dist() calls among multiple game updates()? [ sort of am indirectly, but no enforcement. ] Or decouple physics from graphics ?

Heres the functions I mentioned above:

def calc_local(self):
        """re-calc 'who are my neighbors' to cache for later."""

        l = [] #first, get list of neighbors

        for u in self.game.units.list_type(Unit):
            if u == self: continue # don't collide self.

For object identity, use the "is" operator instead of ==, it only needs to compare the object ids (basically a pointer compare) rather than invoke the rich comparison machinery.


if collide_circle( self.loc, u.loc, self.rad+self.local, u.rad):
                l.append(u)

You might find this faster as a list comprehension, since it avoids the explicit call to append(). Something like this:

         l = [u for u in self.game.units.list_type(Unit)
if u is not self and collide_circle( self.loc, u.loc, self.rad+self.local, u.rad)]

        self.local_cache = l

def list_type(self, t):
"""get list of units by class type. example: .list_type(Unit)"""
        l = []
        for u in self.units:
            if isinstance(u, t): l.append(u)

It seems inefficient to recalculate this each time. It might be better to have a dictionary of sprite groups for each unit type. Something like this:

units = {
	UnitType1: Group(),
	UnitType2: Group(),
	UnitType3: Group(),
	}

The actual unit types keys could be classes, strings, instances, whatever.

assuming the unit type is a class you could do this whenever a unit was created:

units[new_unit.__class__].add(new_unit)

If units are sprites, then when they are killed they are automatically removed. Iterating units of a particular type then becomes:

for u in units[some_unit.__class__]:

This should be a good deal faster than creating and populating a list every time you want to iterate all of the units of a particular type.

Note that you don't have to use a group to hold the units, a built-in list or set will also do, though groups have nice features like automatic removal on kill -- but only if you are using sprites.

-Casey