comparison pytouhou/game/bullet.py @ 122:174324a4da51

Add support for launch animations! (Warning: slow :()
author Thibaut Girka <thib@sitedethib.com>
date Sat, 10 Sep 2011 01:26:30 +0200
parents 4300a832f033
children d1c82d43bbf3
comparison
equal deleted inserted replaced
121:1bc0ad774ed4 122:174324a4da51
18 from pytouhou.vm.anmrunner import ANMRunner 18 from pytouhou.vm.anmrunner import ANMRunner
19 from pytouhou.game.sprite import Sprite 19 from pytouhou.game.sprite import Sprite
20 20
21 21
22 class Bullet(object): 22 class Bullet(object):
23 __slots__ = ('x', 'y', 'angle', 'speed', 'frame', 'grazed', 23 def __init__(self, pos, type_idx, sprite_idx_offset,
24 'flags', 'attributes', 'anim_idx', 'sprite_idx_offset', 'player',
25 'speed_interpolator',
26 '_game_state', '_sprite', '_anmrunner',
27 '_removed', '_launched')
28
29 def __init__(self, pos, anim_idx, sprite_idx_offset,
30 angle, speed, attributes, flags, player, game_state): 24 angle, speed, attributes, flags, player, game_state):
31 self._game_state = game_state 25 self._game_state = game_state
32 self._sprite = None 26 self._sprite = None
33 self._anmrunner = None 27 self._anmrunner = None
34 self._removed = False 28 self._removed = False
35 self._launched = False 29 self._launched = False
30 self._bullet_type = game_state.bullet_types[type_idx]
36 31
37 self.speed_interpolator = None 32 self.speed_interpolator = None
38 self.frame = 0 33 self.frame = 0
39 self.grazed = False 34 self.grazed = False
40 35
41 self.player = player 36 self.player = player
42 37
43 self.anim_idx = anim_idx
44 self.sprite_idx_offset = sprite_idx_offset 38 self.sprite_idx_offset = sprite_idx_offset
45
46 #TODO
47 #if flags & (2|4|8):
48 # if flags & 2: #TODO: Huh?!
49 # index = 14
50 # elif flags & 4:
51 # index = 15
52 # else:
53 # index = 19
54 # self._sprite = Sprite()
55 # self._anmrunner = ANMRunner(self._game_state.resource_loader.get_anm_wrapper(('etama3.anm',)), #TODO
56 # index, self._sprite, 0) #TODO: offset
57 # self._anmrunner.run_frame()
58 39
59 self.flags = flags 40 self.flags = flags
60 self.attributes = list(attributes) 41 self.attributes = list(attributes)
61 42
62 self.x, self.y = pos 43 self.x, self.y = pos
63 self.angle = angle 44 self.angle = angle
64 self.speed = speed 45 self.speed = speed
65 46 dx, dy = cos(angle) * speed, sin(angle) * speed
66 if flags & 1: 47 self.delta = dx, dy
67 self.speed_interpolator = Interpolator((speed + 5.,)) 48
68 self.speed_interpolator.set_interpolation_start(0, (speed + 5.,)) 49 #TODO
69 self.speed_interpolator.set_interpolation_end(16, (speed,)) 50 if flags & 14:
70 if flags & 448: 51 bt = self._bullet_type
71 self.speed_interpolator = Interpolator((speed,)) 52 if flags & 2:
72 self.speed_interpolator.set_interpolation_start(0, (speed,)) 53 index = bt.launch_anim2_index
73 self.speed_interpolator.set_interpolation_end(attributes[0] - 1, (0,)) # TODO: really -1? Without, the new speed isn’t set. 54 launch_mult = bt.launch_anim_penalties[0]
74 55 elif flags & 4:
75 56 index = bt.launch_anim4_index
76 def get_player_angle(self): 57 launch_mult = bt.launch_anim_penalties[1]
77 return atan2(self.player.y - self.y, self.player.x - self.x) 58 else:
59 index = bt.launch_anim8_index
60 launch_mult = bt.launch_anim_penalties[2]
61 self.launch_delta = dx * launch_mult, dy * launch_mult
62 self._sprite = Sprite()
63 self._anmrunner = ANMRunner(bt.anm_wrapper,
64 index, self._sprite,
65 bt.launch_anim_offsets[sprite_idx_offset])
66 self._anmrunner.run_frame()
67 else:
68 self.launch()
69
70 self._sprite.angle = angle
78 71
79 72
80 def is_visible(self, screen_width, screen_height): 73 def is_visible(self, screen_width, screen_height):
81 if self._sprite: 74 tx, ty, tw, th = self._sprite.texcoords
82 tx, ty, tw, th = self._sprite.texcoords 75 if self._sprite.corner_relative_placement:
83 if self._sprite.corner_relative_placement: 76 raise Exception #TODO
84 raise Exception #TODO
85 else:
86 tx, ty, tw, th = 0., 0., 0., 0.
87 77
88 max_x = tw / 2. 78 max_x = tw / 2.
89 max_y = th / 2. 79 max_y = th / 2.
90 min_x = -max_x 80
91 min_y = -max_y 81 if any((max_x < self.x - screen_width,
92
93 if any((min_x > screen_width - self.x,
94 max_x < -self.x, 82 max_x < -self.x,
95 min_y > screen_height - self.y, 83 max_y < self.y - screen_height,
96 max_y < -self.y)): 84 max_y < -self.y)):
97 return False 85 return False
98 return True 86 return True
99 87
100 88
101 def set_anim(self, anim_idx=None, sprite_idx_offset=None): 89 def set_anim(self, sprite_idx_offset=None):
102 if anim_idx is not None:
103 self.anim_idx = anim_idx
104
105 if sprite_idx_offset is not None: 90 if sprite_idx_offset is not None:
106 self.sprite_idx_offset = sprite_idx_offset 91 self.sprite_idx_offset = sprite_idx_offset
107 92
93 bt = self._bullet_type
108 self._sprite = Sprite() 94 self._sprite = Sprite()
109 anm_wrapper = self._game_state.resource_loader.get_anm_wrapper(('etama3.anm',)) #TODO 95 self._sprite.angle = self.angle
110 self._anmrunner = ANMRunner(anm_wrapper, self.anim_idx, 96 self._anmrunner = ANMRunner(bt.anm_wrapper, bt.anim_index,
111 self._sprite, self.sprite_idx_offset) 97 self._sprite, self.sprite_idx_offset)
98 self._anmrunner.run_frame()
99
100
101 def launch(self):
102 self._launched = True
103 self.update = self.update_full
104 self.set_anim()
105 if self.flags & 1:
106 self.speed_interpolator = Interpolator((self.speed + 5.,), 0,
107 (self.speed,), 16)
112 108
113 109
114 def update(self): 110 def update(self):
115 if not self._sprite or self._sprite._removed: 111 dx, dy = self.launch_delta
116 self._launched = True 112 self.x += dx
117 self.set_anim() 113 self.y += dy
118 114
115 self.frame += 1
116
117 if not self._anmrunner.run_frame():
118 self.launch()
119
120
121 def update_simple(self):
122 dx, dy = self.delta
123 self.x += dx
124 self.y += dy
125
126
127 def update_full(self):
119 sprite = self._sprite 128 sprite = self._sprite
120 129
121 if self._anmrunner is not None and not self._anmrunner.run_frame(): 130 if self._anmrunner is not None and not self._anmrunner.run_frame():
122 self._anmrunner = None 131 self._anmrunner = None
123 if sprite.automatic_orientation and sprite.angle != self.angle:
124 sprite.angle = self.angle
125 sprite._changed = True
126 132
127 #TODO: flags 133 #TODO: flags
128 x, y = self.x, self.y 134 x, y = self.x, self.y
135 dx, dy = self.delta
129 136
130 if self.flags & 16: 137 if self.flags & 16:
131 frame, count = self.attributes[0:2] 138 frame, count = self.attributes[0:2]
132 length, angle = self.attributes[4:6] 139 length, angle = self.attributes[4:6]
133 angle = self.angle if angle < -900.0 else angle #TODO: is that right? 140 angle = self.angle if angle < -900.0 else angle #TODO: is that right?
134 dx = cos(self.angle) * self.speed + cos(angle) * length 141 dx, dy = dx + cos(angle) * length, dy + sin(angle) * length
135 dy = sin(self.angle) * self.speed + sin(angle) * length 142 self.delta = dx, dy
136 self.speed = (dx ** 2 + dy ** 2) ** 0.5
137 self.angle = atan2(dy, dx)
138 if self.frame == frame: #TODO: include last frame, or not? 143 if self.frame == frame: #TODO: include last frame, or not?
139 if count > 0: 144 if count > 0:
140 self.attributes[1] -= 1 145 self.attributes[1] -= 1
141 self.frame = 0 146 self.frame = 0
142 else: 147 else:
145 #TODO: check 150 #TODO: check
146 frame, count = self.attributes[0:2] 151 frame, count = self.attributes[0:2]
147 acceleration, angular_speed = self.attributes[4:6] 152 acceleration, angular_speed = self.attributes[4:6]
148 self.speed += acceleration 153 self.speed += acceleration
149 self.angle += angular_speed 154 self.angle += angular_speed
150 if self.frame != 0 and self.frame % frame == 0: 155 dx, dy = cos(self.angle) * self.speed, sin(self.angle) * self.speed
156 self.delta = dx, dy
157 sprite.angle = self.angle
158 if sprite.automatic_orientation:
159 sprite._changed = True
160 if self.frame % frame == 0:
151 if count > 0: 161 if count > 0:
152 self.attributes[1] -= 1 162 self.attributes[1] -= 1
153 else: 163 else:
154 self.flags ^= 32 164 self.flags ^= 32
155 elif self.flags & 448: 165 elif self.flags & 448:
156 #TODO: check 166 #TODO: check
157 frame, count = self.attributes[0:2] 167 frame, count = self.attributes[0:2]
158 angle, speed = self.attributes[4:6] 168 angle, speed = self.attributes[4:6]
159 if self.frame != 0 and self.frame % frame == 0: 169 if self.frame % frame == 0:
160 count = count - 1 170 count = count - 1
161 171
162 if self.flags & 64: 172 if self.flags & 64:
163 self.angle = self.angle + angle 173 self.angle += angle
164 elif self.flags & 128: 174 elif self.flags & 128:
165 self.angle = self.get_player_angle() + angle 175 self.angle = atan2(self.player.y - y, self.player.x - x) + angle
166 elif self.flags & 256: 176 elif self.flags & 256:
167 self.angle = angle 177 self.angle = angle
168 178
169 if count: 179 dx, dy = cos(self.angle) * speed, sin(self.angle) * speed
170 self.speed_interpolator.set_interpolation_start(self.frame, (speed,)) 180 self.delta = dx, dy
171 self.speed_interpolator.set_interpolation_end(self.frame + frame - 1, (0,)) # TODO: really -1? Without, the new speed isn’t set. 181 sprite.angle = self.angle
182 if sprite.automatic_orientation:
183 sprite._changed = True
184
185 if count > 0:
186 self.speed_interpolator = Interpolator((speed,), self.frame,
187 (0.,), self.frame + frame - 1)
172 else: 188 else:
173 self.flags &= ~448 189 self.flags &= ~448
174 self.speed = speed 190 self.speed = speed
175 191
176 self.attributes[1] = count 192 self.attributes[1] = count
177 #TODO: other flags 193 #TODO: other flags
194 elif not self.speed_interpolator and self._anmrunner is None:
195 self.update = self.update_simple
178 196
179 if self.speed_interpolator: 197 if self.speed_interpolator:
180 self.speed_interpolator.update(self.frame) 198 self.speed_interpolator.update(self.frame)
181 self.speed, = self.speed_interpolator.values 199 self.speed, = self.speed_interpolator.values
182 200
183 dx, dy = cos(self.angle) * self.speed, sin(self.angle) * self.speed
184 self.x, self.y = x + dx, y + dy 201 self.x, self.y = x + dx, y + dy
185 202
186 self.frame += 1 203 self.frame += 1
187 204