X-Git-Url: https://git.yukkurigames.com/?p=python-bulletml.git;a=blobdiff_plain;f=bulletml%2Fcollision.py;h=2e88b3c0a492008a8c62cb0a23c0c92fbd9f3f4f;hp=f185745ab77f410bcd541846a2b00d28badfd663;hb=HEAD;hpb=0f067785de711c772c2c44c7f1e1cf8b44b2704f diff --git a/bulletml/collision.py b/bulletml/collision.py index f185745..2e88b3c 100644 --- a/bulletml/collision.py +++ b/bulletml/collision.py @@ -1,9 +1,13 @@ """Simple collision check. This module provides simple collision checking appropriate for -shmups. It provides a routine to check whether two moving circles +shmups. It provides routines to check whether two moving circles collided during the past frame. +An equivalent C-based version will be used automatically if it was +compiled and installed with the module. If available, it will be noted +in the docstrings for the functions. + Basic Usage: from bulletml.collision import collides @@ -20,11 +24,16 @@ def overlaps(a, b): 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 unoptimized.) """ dx = a.x - b.x dy = a.y - b.y - radius = getattr(a, 'radius', 0.5) + getattr(b, 'radius', 0.5) + try: + radius = a.radius + b.radius + except AttributeError: + radius = getattr(a, 'radius', 0.5) + getattr(b, 'radius', 0.5) return dx * dx + dy * dy <= radius * radius @@ -37,6 +46,8 @@ def collides(a, b): px, py - not required, defaults to x, y, previous frame position radius - not required, defaults to 0.5 + (This function is unoptimized.) + """ # Current locations. xa = a.x @@ -45,27 +56,32 @@ def collides(a, b): yb = b.y # Treat b as a point, we only need one radius. - radius = getattr(a, 'radius', 0.5) + getattr(b, 'radius', 0.5) + try: + radius = a.radius + b.radius + except AttributeError: + radius = getattr(a, 'radius', 0.5) + getattr(b, 'radius', 0.5) # Previous frame locations. - pxa = getattr(a, 'px', xa) - pya = getattr(a, 'py', ya) - pxb = getattr(b, 'px', xb) - pyb = getattr(b, 'py', yb) + try: pxa = a.px + except KeyError: pxa = xa + try: pya = a.py + except KeyError: pya = ya + try: pxb = b.px + except KeyError: pxb = xb + try: pyb = b.py + except KeyError: pyb = yb # 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 abs(dir_x) < 0.0001 and abs(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 + 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. + return diff_x * diff_x + diff_y * diff_y < radius * radius # dot(diff, dir) / dot(dir, dir) t = (diff_x * dir_x + diff_y * dir_y) / (dir_x * dir_x + dir_y * dir_y) @@ -79,3 +95,18 @@ def collides(a, b): # dist_sq < radius_sq return dist_x * dist_x + dist_y * dist_y <= radius * radius + +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 not currently). + + """ + return filter(lambda o: collides(a, o), others) + +try: + from bulletml._collision import collides, overlaps, collides_all +except ImportError: + pass