In addition to the standard BulletML XML format, this module supports
an equivalent YAML format. See bulletml.bulletyaml for more details.
+Finally, two simple collision routines are provided, bulletml.overlaps
+for stationary circles and bulletml.collides for moving circles.
+
More information is available at the BulletML homepage,
http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/index_e.html, or the
python-bullet homepage, http://code.google.com/p/python-bulletml/.
from bulletml.parser import BulletML
from bulletml.impl import Bullet
+from bulletml.collision import overlaps, collides
VERSION = (0, 1)
VERSION_STRING = ".".join(map(str, VERSION))
-__all__ = ["VERSION", "VERSION_STRING", "Bullet", "BulletML"]
+__all__ = ["VERSION", "VERSION_STRING", "Bullet", "BulletML",
+ "overlaps", "collides"]
--- /dev/null
+"""Simple collision check.
+
+This module provides simple collision checking appropriate for
+shmups. It provides a routine to check whether two moving circles
+collided during the past frame.
+
+Basic Usage:
+
+ from bulletml.collision import collides
+
+ for bullet in bullets:
+ if collides(player, bullet): ... # Kill the player.
+"""
+
+from __future__ import division
+
+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.
+ """
+
+ dx = a.x - b.x
+ dy = a.y - b.y
+ radius = getattr(a, 'radius', 0.5) + getattr(b, 'radius', 0.5)
+
+ return dx * dx + dy * dy <= 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
+
+ """
+ # Current locations.
+ xa = a.x
+ xb = b.x
+ ya = a.y
+ yb = b.y
+
+ # Treat b as a point, we only need one radius.
+ 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)
+
+ # 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
+
+ # 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