Mercurial > touhou
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 |