+++ /dev/null
-"""Optimized collision detection functions."""
-
-def overlaps(a, b):
- """Return true if two circles are overlapping.
-
- Usually, you'll want to use the 'collides' method instead, but
- this one can be useful for just checking to see if the player has
- entered an area or hit a stationary oject.
-
- (This function is optimized.)
-
- """
-
- cdef float ax
- cdef float bx
- cdef float ay
- cdef float by
- cdef float dx
- cdef float dy
- cdef float radius_a
- cdef float radius_b
- cdef float radius
-
- ax = a.x
- bx = b.x
- ay = a.y
- by = b.y
-
- dx = ax - bx
- dy = ay - by
-
- radius_a = getattr3(a, 'radius', 0.5)
- radius_b = getattr3(b, 'radius', 0.5)
- radius = radius_a + radius_b
-
- return dx * dx + dy * dy <= radius * radius
-
-
-cdef int _collides(float xa, float xb, float ya, float yb,
- float pxa, float pxb, float pya, float pyb,
- float radius_a, float radius_b):
-
- """Check collision for two moving circles."""
-
- cdef float dir_x
- cdef float dir_y
-
- cdef float diff_x
- cdef float diff_y
- cdef float dist_x
- cdef float dist_y
-
- cdef float dx
- cdef float dy
- cdef float t
-
- cdef float radius
-
- radius = radius_a + radius_b
-
- # Translate b's final position to be relative to a's start.
- # And now, circle/line collision.
- dir_x = pxa + (xb - xa) - pxb
- dir_y = pya + (yb - ya) - pyb
-
- if (dir_x < 0.0001 and dir_x > -0.0001
- and dir_y < 0.0001 and dir_y > -0.0001):
- # b did not move relative to a, so do point/circle.
- dx = pxb - pxa
- dy = pyb - pya
- return dx * dx + dy * dy < radius * radius
-
- diff_x = pxa - pxb
- diff_y = pya - pyb
-
- # dot(diff, dir) / dot(dir, dir)
- t = (diff_x * dir_x + diff_y * dir_y) / (dir_x * dir_x + dir_y * dir_y)
- if t < 0:
- t = 0
- elif t > 1:
- t = 1
-
- dist_x = pxa - (pxb + dir_x * t)
- dist_y = pya - (pyb + dir_y * t)
-
- # dist_sq < radius_sq
- return dist_x * dist_x + dist_y * dist_y <= radius * radius
-
-def collides(a, b):
- """Return true if the two moving circles collide.
-
- a and b should have the following attributes:
-
- x, y - required, current position
- px, py - not required, defaults to x, y, previous frame position
- radius - not required, defaults to 0.5
-
- (This function is optimized.)
-
- """
- cdef float xa
- cdef float xb
- cdef float ya
- cdef float yb
-
- cdef float pxa
- cdef float pya
- cdef float pxb
- cdef float pyb
-
- cdef float radius_a
- cdef float radius_b
-
- xa = a.x
- xb = b.x
- ya = a.y
- yb = b.y
-
- radius_a = getattr3(a, 'radius', 0.5)
- radius_b = getattr3(b, 'radius', 0.5)
-
- pxa = getattr3(a, 'px', xa)
- pya = getattr3(a, 'py', ya)
- pxb = getattr3(b, 'px', xb)
- pyb = getattr3(b, 'py', yb)
-
- return _collides(xa, xb, ya, yb, pxa, pxb, pya, pyb, radius_a, radius_b)
-
-def collides_all(a, others):
- """Filter the second argument to those that collide with the first.
-
- This is equivalent to filter(lambda o: collides(a, o), others),
- but is much faster when the compiled extension is available (which
- it is currently).
-
- """
- cdef float xa
- cdef float xb
- cdef float ya
- cdef float yb
-
- cdef float pxa
- cdef float pya
- cdef float pxb
- cdef float pyb
-
- cdef float radius_a
- cdef float radius_b
-
- cdef list bs
- cdef int length
-
- cdef list colliding
-
- cdef int coll
-
- colliding = []
-
- xa = a.x
- ya = a.y
- radius_a = getattr3(a, 'radius', 0.5)
- pxa = getattr3(a, 'px', xa)
- pya = getattr3(a, 'py', ya)
-
- bs = list(others)
- length = len(bs)
-
- for 0 <= i < length:
- b = others[i]
- xb = b.x
- yb = b.y
- radius_b = getattr3(b, 'radius', 0.5)
- pxb = getattr3(b, 'px', xb)
- pyb = getattr3(b, 'py', yb)
-
- if _collides(xa, xb, ya, yb, pxa, pxb, pya, pyb, radius_a, radius_b):
- colliding.append(b)
- return colliding