4785ef2c8c17094076b38e49ceef4486fb9910b7
1 """BulletML implementation."""
3 from __future__
import division
5 from math
import atan2
, sin
, cos
7 __all__
= ["Action", "Bullet"]
10 """Running action implementation.
12 To implement new actions, add a new element/class pair to
13 parser.ActionDef.CONSTRUCTORS. It should support FromXML,
14 __getstate__, and __setstate__, and 5-ary __call__:
16 def __call__(self, owner, action, params, rank, created)
18 Which will be called to execute it. This function should modify
19 owner, action, and created in-place, and return true if action
20 execution should stop for this bullet this frame.
24 def __init__(self
, parent
, actions
, params
, rank
, repeat
=1):
25 self
.actions
= actions
32 self
.direction_frames
= 0
37 self
.previous_fire_direction
= 0
38 self
.previous_fire_speed
= 0
43 self
.copy_state(parent
)
46 return "%s(pc=%r, actions=%r)" % (
47 type(self
).__name
__, self
.pc
, self
.actions
)
50 """End this action and its parents."""
56 def copy_state(self
, other
):
57 """Copy fire/movement state from other to self."""
58 self
.direction_frames
= other
.direction_frames
59 self
.direction
= other
.direction
60 self
.aiming
= other
.aiming
61 self
.speed_frames
= other
.speed_frames
62 self
.speed
= other
.speed
63 self
.accel_frames
= other
.accel_frames
66 self
.previous_fire_direction
= other
.previous_fire_direction
67 self
.previous_fire_speed
= other
.previous_fire_speed
69 def step(self
, owner
, created
):
70 """Advance by one frame."""
72 if self
.speed_frames
> 0:
73 self
.speed_frames
-= 1
74 owner
.speed
+= self
.speed
76 if self
.direction_frames
> 0:
77 self
.direction_frames
-= 1
78 # I'm still not sure what the aim check is supposed to do.
79 if self
.aiming
and self
.direction_frames
<= 0:
80 owner
.direction
+= owner
.aim
82 owner
.direction
+= self
.direction
84 if self
.accel_frames
> 0:
85 self
.accel_frames
-= 1
92 if self
.wait_frames
> 0:
96 s_params
= self
.params
103 action
= self
.actions
[self
.pc
]
109 if self
.parent
is not None:
110 self
.parent
.copy_state(self
)
111 owner
.replace(self
, self
.parent
)
115 action
= self
.actions
[self
.pc
]
117 if action(owner
, self
, s_params
, rank
, created
):
120 class Bullet(object):
121 """Simple bullet implementation.
124 x, y - current X/Y position
125 px, py - X/Y position prior to the last step
126 mx, my - X/Y axis-oriented speed modifier ("acceleration")
127 direction - direction of movement, in radians
128 speed - speed of movement, in units per frame
129 target - object with .x and .y fields for "aim" directions
130 vanished - set to true by a <vanish> action
131 rank - game difficulty, 0 to 1, default 0.5
132 tags - string tags set by the running actions
133 appearance - string used to set bullet appearance
134 radius - radius for collision
136 Contructor Arguments:
137 x, y, direction, speed, target, rank, tags, appearance, radius
138 - same as the above attributes
139 actions - internal action list
140 Action - custom Action constructor
144 def __init__(self
, x
=0, y
=0, direction
=0, speed
=0, target
=None,
145 actions
=(), rank
=0.5, tags
=(), appearance
=None,
152 self
.direction
= direction
154 self
.vanished
= False
157 self
.tags
= set(tags
)
158 self
.appearance
= appearance
159 self
.actions
= list(actions
)
162 def FromDocument(cls
, doc
, x
=0, y
=0, direction
=0, speed
=0, target
=None,
163 params
=(), rank
=0.5, Action
=Action
):
164 """Construct a new Bullet from a loaded BulletML document."""
165 actions
= [action(None, Action
, params
, rank
)
166 for action
in doc
.actions
]
167 return cls(x
=x
, y
=y
, direction
=direction
, speed
=speed
,
168 target
=target
, actions
=actions
, rank
=rank
)
171 return ("%s(%r, %r, accel=%r, direction=%r, speed=%r, "
172 "actions=%r, target=%r, appearance=%r, vanished=%r)") % (
173 type(self
).__name
__, self
.x
, self
.y
, (self
.mx
, self
.my
),
174 self
.direction
, self
.speed
, self
.actions
, self
.target
,
175 self
.appearance
, self
.vanished
)
179 """Angle to the target, in radians.
181 If the target does not exist or cannot be found, return 0.
184 target_x
= self
.target
.x
185 target_y
= self
.target
.y
186 except AttributeError:
189 return atan2(target_x
- self
.x
, target_y
- self
.y
)
193 """Check if this bullet is finished running.
195 A bullet is finished when it has vanished, and all its
196 actions have finished.
198 If this is true, the bullet should be removed from the screen.
199 (You will probably want to cull it under other circumstances
202 if not self
.vanished
:
204 for action
in self
.actions
:
205 if not action
.finished
:
210 """Vanish this bullet and stop all actions."""
212 for action
in self
.actions
:
216 def replace(self
, old
, new
):
217 """Replace an active action with another.
219 This is mostly used by actions internally to queue children.
222 idx
= self
.actions
.index(old
)
226 self
.actions
[idx
] = new
229 """Advance by one frame.
231 This updates the position and velocity, and may also set the
234 It returns any new bullets this bullet spawned during this step.
238 for action
in self
.actions
:
239 action
.step(self
, created
)
242 direction
= self
.direction
245 self
.x
+= self
.mx
+ sin(direction
) * speed
246 self
.y
+= -self
.my
+ cos(direction
) * speed