[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
Re: [pygame] fast sqrt? and profiling
On Jan 21, 2009, at 7:28 PM, Jake b wrote:
First:
Thanks everyone for all the replies.
Lots of useful information.
On Wed, Jan 21, 2009 at 11:11 AM, Casey Duncan <casey@xxxxxxxxxxx>
wrote:
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.
1) How do you use complex(imaginary) numbers in place of euclid
vectors? I tried searching for a tut/article, but, not having luck.
Here's some example code with some commonly used functions. Addition
and subtraction are built into the complex type and work as expected
(I use the real part for x and the imaginary part for y). complex
multiply can be used to rotate vectors:
# 2D vectors using python complex numbers
from math import atan2
import cmath
vector2 = complex
length = abs
def to_tuple(vector):
return (vector.real, vector.imag)
def to_tuple3(vector, z=0):
return (vector.real, vector.imag, z)
def radians(vector):
return atan2(vector.imag, vector.real)
def unit(radians):
return cmath.exp(radians * 1j)
def normal(vector):
L = length(vector)
if L == 0:
return vector2()
else:
return vector / L
def clamp(vector, max_length):
L = length(vector)
if L > max_length:
return vector * (max_length / L)
else:
return vector
def distance(vector1, vector2):
return length(vector1 - vector2)
@casey:
I thought my function was bad -- but your solution will be easy to
use. I'm using a factory, ie "spawn('type', 'loc | rand', *args)" to
spawn units. So I can append to the subgroups here. ( I am not
subclassing Sprite, but I do have a .dead member, that auto-deletes
when iterated. )
Sounds good.
2) Iterating on copy-of-list speed? Is there a reason to not do this?
Right now, if I'm iterating on a list which might be modified
( deleted, not sure if additions break it too. ), I'm in the habit
of iterating on a copy of the list. ( because, at least in some
cases, it breaks if not a copy )
ie:
def update(self):
for a in self.actor_list[:]: # iterate on copy, incase I delete
any later
a.update()
if a.dead or offscreen( a.loc ):
self.actor_list.remove( a )
This is good if the list may change during iteration. If you do this
repeatedly in a given frame, it might be better to create a custom
class (perhaps subclass set) that contains a stable set of the actors.
When you add or remove, these are stored in ancillary sets rather than
changing the stable set immediately. An update method called at the
beginning of each frame adds and removes the items from the ancillary
sets to update the stable set. These ancillary sets are then cleared.
This mean less memory allocation/cleanup and work copying the lists:
class StableSet(set):
"""Stable set that does not reflect changes until update() is called,
thus can be safely mutated while iterated
"""
def __init__(self):
self.added = set()
self.removed = set()
def add(self, item):
if item not in self:
self.added.add(item)
def remove(self, item):
if item in self:
self.removed.add(item)
else:
self.added.remove(item)
def update(self):
self -= self.removed
self.removed.clear()
self |= self.added
self.added.clear()
-Casey