"""BulletML parser.
-http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/index_e.html
+This module parses and runs BulletML scripts. BulletML is a markup
+language for describing complex bullet patterns in shooting games.
+More information is available at the BulletML homepage,
+http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/index_e.html.
+
+Basic Usage:
+
+ from bulletml import Bullet, BulletML
+ doc = Bulletml.BulletML.FromDocument(open("test.xml", "rU"))
+ rank = 0.5 # Player difficulty, 0 to 1
+ params = [] # Initial variable settings, usually empty
+ actions = [a(params, rank) for a in doc.top]
+ bullet = Bullet(x, y, target=player, actions=actions, rank=rank)
+ bullets = [bullet]
+ ...
+ for bullet in bullets:
+ bullets.extend(bullet.step())
+
+ ...
+
+For drawing, you're on your own, but Bullet has a number of
+attributes that can be used to influence it.
+
"""
from bulletml.parser import BulletML
-from bulletml.impl import Bullet, Action
+from bulletml.impl import Bullet
VERSION = (1, 0)
VERSION_STRING = ".".join(map(str, VERSION))
+
+__all__ = ["VERSION", "VERSION_STRING", "Bullet", "BulletML"]
+
PI_2 = math.pi * 2
+__all__ = ["Action", "Bullet"]
+
class Action(object):
"""Running action implementation."""
return created
class Bullet(object):
- """Simple bullet implementation."""
+ """Simple bullet implementation.
+
+ Attributes:
+ x, y - current X/Y position
+ px, py - X/Y position prior to the last step
+ mx, my - X/Y axis-oriented speed modifier ("acceleration")
+ direction - direction of movement, in radians
+ speed - speed of movement, in units per frame
+ target - object with .x and .y fields for "aim" directions
+ vanished - set to true by a <vanish> action
+
+ Contructor Arguments:
+ x, y, direction, speed, target - same as the attributes
+ actions - internal action list
+ parent - parent of actions, None for manually-created bullets
+ rank - game difficulty, 0 to 1
+
+ """
def __init__(self, x=0, y=0, direction=0, speed=0, target=None,
actions=(), parent=None, rank=None):
@property
def aim(self):
- """Angle to the target."""
+ """Angle to the target, in radians."""
if self.target is None:
return self.direction
else:
def finished(self):
"""Check if this bullet is finished running.
+ A bullet is finished when it has vanished, and all its
+ actions have finished.
+
If this is true, the bullet should be removed from the screen.
(You will probably want to cull it under other circumstances
as well).
self._actions = []
def replace(self, old, new):
- """Replace an active action with another."""
+ """Replace an active action with another.
+
+ This is mostly used by actions internally to queue children.
+ """
try:
idx = self._actions.index(old)
except ValueError:
def step(self):
"""Advance by one frame.
- This updates the direction, speed, x, y, px, and py members,
- and may set the vanished flag.
+ This updates the position and velocity, and may also set the
+ vanished flag.
+
+ It returns any new bullets this bullet spawned during this step.
"""
created = []
"""BulletML parser.
-http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/index_e.html
+This is based on the format described at
+http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/bulletml_ref_e.html.
+
+Unless you are adding support for new tags, the only class you should
+care about in here is BulletML.
"""
from __future__ import division
class ParamList(object):
"""List of parameter definitions."""
- def __init__(self, params=[]):
+ def __init__(self, params=()):
self.params = list(params)
@classmethod
type(self).__name__, self.params, self.bullet)
class ActionDef(object):
- """Action definition."""
+ """Action definition.
+
+ To support parsing new actions, add tags to
+ ActionDef.CONSTRUCTORS. It maps tag names to classes with a
+ FromElement classmethod, which take the BulletML instance and
+ ElementTree element as arguments.
+ """
# This is self-referential, so it's filled in later.
CONSTRUCTORS = dict()
A BulletML document is a collection of bullets, actions, and
firings, as well as a base game type.
+
+ You can add tags to the BulletML.CONSTRUCTORS dictionary to extend
+ its parsing. It maps tag names to classes with a FromElement
+ classmethod, which take the BulletML instance and ElementTree
+ element as arguments.
+
"""
CONSTRUCTORS = dict(
fire=FireDef,
)
- def __init__(self, type="none", bullets={}, fires={}, actions={}):
+ def __init__(self, type="none", bullets=None, fires=None, actions=None):
self.type = type
- self.bullets = {}
- self.actions = {}
- self.fires = {}
+ self.bullets = {} if bullets is None else bullets
+ self.actions = {} if actions is None else actions
+ self.fires = {} if fires is None else fires
@classmethod
def FromDocument(cls, source):
+ """Return a BulletML instance based on a string or file-like."""
if isinstance(source, (str, unicode)):
source = StringIO(source)