comparison pytouhou/game/enemymanager.py @ 23:444ac7bca7bc

Refacto ECL stuff, add support for a few instructions, and add some culling
author Thibaut Girka <thib@sitedethib.com>
date Fri, 12 Aug 2011 19:13:43 +0200
parents fa87db09fc3a
children afa91be769ae
comparison
equal deleted inserted replaced
22:fa87db09fc3a 23:444ac7bca7bc
1 from itertools import chain 1 from itertools import chain
2 from io import BytesIO 2 from io import BytesIO
3 import os 3 import os
4 from struct import unpack, pack 4 from struct import unpack, pack
5 from pytouhou.utils.interpolator import Interpolator 5 from pytouhou.utils.interpolator import Interpolator
6 from pytouhou.game.eclrunner import ECLRunner
6 from pytouhou.game.sprite import Sprite 7 from pytouhou.game.sprite import Sprite
7 from math import cos, sin, atan2 8 from math import cos, sin, atan2
8 9
9 10
10 class Enemy(object): 11 class Enemy(object):
11 def __init__(self, pos, life, _type, script, anm_wrapper): 12 def __init__(self, pos, life, _type, ecl_runner, anm_wrapper):
12 self.anm_wrapper = anm_wrapper 13 self.anm_wrapper = anm_wrapper
13 self.anm = None 14 self.anm = None
14 self.script = list(script) 15 self.ecl_runner = ecl_runner
15 self.x, self.y = pos 16 self.x, self.y = pos
16 self.life = life 17 self.life = life
17 self.type = _type 18 self.type = _type
18 self.frame = 0 19 self.frame = 0
19 self.sprite = None 20 self.sprite = None
20 21
22 self.death_sprite = None
21 self.movement_dependant_sprites = None 23 self.movement_dependant_sprites = None
22 self.direction = None 24 self.direction = None
23 self.interpolator = None #TODO 25 self.interpolator = None #TODO
24 self.angle = 0. 26 self.angle = 0.
25 self.speed = 0. 27 self.speed = 0.
26 self.rotation_speed = 0. 28 self.rotation_speed = 0.
27 self.acceleration = 0. 29 self.acceleration = 0.
28 30
31 self.hitbox = (0, 0)
32
33 self.ecl_runner.implementation.update({97: ('I', self.set_sprite),
34 98: ('HHHHHH', self.set_multiple_sprites),
35 45: ('ff', self.set_angle_speed),
36 43: ('fff', self.set_pos),
37 46: ('f', self.set_rotation_speed),
38 47: ('f', self.set_speed),
39 48: ('f', self.set_acceleration),
40 51: ('If', self.target_player),
41 57: ('Ifff', self.move_to),
42 100: ('I', self.set_death_sprite),
43 103: ('fff', self.set_hitbox)}) #TODO
44
45
46 def set_death_sprite(self, sprite_index):
47 self.death_sprite = sprite_index % 256 #TODO
48
49
50 def set_hitbox(self, width, height, depth):
51 self.hitbox = (width, height)
52
53
54 def set_sprite(self, sprite_index):
55 self.anm, self.sprite = self.anm_wrapper.get_sprite(sprite_index)
56
57
58 def set_multiple_sprites(self, default, end_left, end_right, left, right, unknown):
59 self.movement_dependant_sprites = end_left, end_right, left, right, unknown
60 self.anm, self.sprite = self.anm_wrapper.get_sprite(default)
61
62
63 def set_angle_speed(self, angle, speed):
64 self.angle, self.speed = angle, speed
65
66
67 def set_pos(self, x, y, z):
68 self.x, self.y = x, y
69 self.interpolator = Interpolator((x, y))
70 self.interpolator.set_interpolation_start(self.frame, (x, y))
71
72
73 def set_rotation_speed(self, speed):
74 self.rotation_speed = speed
75
76
77 def set_speed(self, speed):
78 self.speed = speed
79
80
81 def set_acceleration(self, acceleration):
82 self.acceleration = acceleration
83
84
85 def target_player(self, unknown, speed):
86 self.speed = speed #TODO: unknown
87 player_x, player_y = 192., 400.#TODO
88 self.angle = atan2(player_y - self.y, player_x - self.x)
89
90
91 def move_to(self, duration, x, y, z):
92 self.interpolator.set_interpolation_end(self.frame + duration, (x, y))
93
94
95 def is_visible(self, screen_width, screen_height):
96 if not self.sprite:
97 return False
98 if min(x for x, y, z in self.sprite._vertices) >= screen_width - self.x:
99 return False
100 if max(x for x, y, z in self.sprite._vertices) <= -self.x:
101 return False
102 if min(y for x, y, z in self.sprite._vertices) >= screen_height - self.y:
103 return False
104 if max(y for x, y, z in self.sprite._vertices) <= -self.y:
105 return False
106 return True
107
29 108
30 def update(self, frame): 109 def update(self, frame):
31 if not self.script: 110 #TODO
32 return True 111 #if not self.script:
33 if self.script[0][0] == self.frame: 112 # return True
34 for instr_type, rank_mask, param_mask, args in self.script.pop(0)[1]: 113 #if self.script[0][0] == self.frame:
35 if instr_type == 1: # delete 114 # for instr_type, rank_mask, param_mask, args in self.script.pop(0)[1]:
36 return False 115 # if instr_type == 1: # delete
37 elif instr_type == 97: # set_enemy_sprite 116 # return False
38 script_index, = unpack('<I', args) 117 self.ecl_runner.update()
39 self.anm, self.sprite = self.anm_wrapper.get_sprite(script_index)
40 elif instr_type == 98: #TODO
41 default, end_left, end_right, left, right, unknown = unpack('<HHHHHH', args)
42 self.movement_dependant_sprites = end_left, end_right, left, right, unknown
43 self.anm, self.sprite = self.anm_wrapper.get_sprite(default)
44 elif instr_type == 43: # set_pos
45 self.x, self.y, z = unpack('<fff', args)
46 self.interpolator = Interpolator((self.x, self.y)) #TODO: better interpolation
47 self.interpolator.set_interpolation_start(self.frame, (self.x, self.y))
48 elif instr_type == 45: # set_angle_speed
49 self.angle, self.speed = unpack('<ff', args)
50 elif instr_type == 46: # set_angle
51 self.rotation_speed, = unpack('<f', args)
52 elif instr_type == 47: # set_speed
53 self.speed, = unpack('<f', args)
54 elif instr_type == 48: # set_acceleration
55 self.acceleration, = unpack('<f', args)
56 elif instr_type == 51: # move_towards_player #TODO: main
57 unknown, self.speed = unpack('<If', args) #TODO: unknown
58 player_x, player_y = 192., 400.#TODO
59 self.angle = atan2(player_y - self.y, player_x - self.x)
60 elif instr_type == 57:
61 duration, x, y, z = unpack('<Ifff', args)
62 self.interpolator.set_interpolation_end(self.frame + duration, (x, y))
63 118
64 x, y = self.x, self.y 119 x, y = self.x, self.y
65 if self.interpolator: 120 if self.interpolator:
66 self.interpolator.update(self.frame) 121 self.interpolator.update(self.frame)
67 x, y = self.interpolator.values 122 x, y = self.interpolator.values
101 class EnemyManager(object): 156 class EnemyManager(object):
102 def __init__(self, stage, anm_wrapper, ecl): 157 def __init__(self, stage, anm_wrapper, ecl):
103 self.stage = stage 158 self.stage = stage
104 self.anm_wrapper = anm_wrapper 159 self.anm_wrapper = anm_wrapper
105 self.main = [] 160 self.main = []
106 self.subs = {} 161 self.ecl = ecl
107 self.objects_by_texture = {} 162 self.objects_by_texture = {}
108 self.enemies = [] 163 self.enemies = []
109 164
110 # Populate main 165 # Populate main
111 for frame, sub, instr_type, args in ecl.main: 166 for frame, sub, instr_type, args in ecl.main:
113 self.main.append((frame, [(sub, instr_type, args)])) 168 self.main.append((frame, [(sub, instr_type, args)]))
114 elif self.main[-1][0] == frame: 169 elif self.main[-1][0] == frame:
115 self.main[-1][1].append((sub, instr_type, args)) 170 self.main[-1][1].append((sub, instr_type, args))
116 171
117 172
118 # Populate subs
119 for i, sub in enumerate(ecl.subs):
120 for frame, instr_type, rank_mask, param_mask, args in sub:
121 if i not in self.subs:
122 self.subs[i] = []
123 if not self.subs[i] or self.subs[i][-1][0] < frame:
124 self.subs[i].append((frame, [(instr_type, rank_mask, param_mask, args)]))
125 elif self.subs[i][-1][0] == frame:
126 self.subs[i][-1][1].append((instr_type, rank_mask, param_mask, args))
127
128
129 def update(self, frame): 173 def update(self, frame):
130 if self.main and self.main[0][0] == frame: 174 if self.main and self.main[0][0] == frame:
131 for sub, instr_type, args in self.main.pop(0)[1]: 175 for sub, instr_type, args in self.main.pop(0)[1]:
132 if instr_type in (0, 2, 4, 6): # Normal/mirrored enemy 176 if instr_type in (0, 2, 4, 6): # Normal/mirrored enemy
133 x, y, z, life, unknown1, unknown2, unknown3 = args 177 x, y, z, life, unknown1, unknown2, unknown3 = args
134 self.enemies.append(Enemy((x, y), life, instr_type, self.subs[sub], self.anm_wrapper)) 178 ecl_runner = ECLRunner(self.ecl, sub)
179 enemy = Enemy((x, y), life, instr_type, ecl_runner, self.anm_wrapper)
180
181 def _enemy_deleter(unknown): #TOOD: unknown
182 print('youhou!')
183 self.enemies.remove(enemy)
184
185 ecl_runner.implementation[1] = ('I', _enemy_deleter)
186
187 self.enemies.append(enemy)
135 188
136 # Update enemies 189 # Update enemies
137 for enemy in tuple(self.enemies): 190 for enemy in tuple(self.enemies):
138 if not enemy.update(frame): 191 if not enemy.update(frame):
139 self.enemies.remove(enemy) 192 self.enemies.remove(enemy)
141 194
142 # Add enemies to vertices/uvs 195 # Add enemies to vertices/uvs
143 self.objects_by_texture = {} 196 self.objects_by_texture = {}
144 for enemy in self.enemies: 197 for enemy in self.enemies:
145 ox, oy = enemy.x, enemy.y 198 ox, oy = enemy.x, enemy.y
146 if enemy.sprite: 199 if enemy.is_visible(384, 448): #TODO
147 key = enemy.anm.first_name, enemy.anm.secondary_name 200 key = enemy.anm.first_name, enemy.anm.secondary_name
148 if not key in self.objects_by_texture: 201 if not key in self.objects_by_texture:
149 self.objects_by_texture[key] = (0, [], []) 202 self.objects_by_texture[key] = (0, [], [])
150 vertices = tuple((x + ox, y + oy, z) for x, y, z in enemy.sprite._vertices) 203 vertices = tuple((x + ox, y + oy, z) for x, y, z in enemy.sprite._vertices)
151 self.objects_by_texture[key][2].extend(enemy.sprite._uvs) 204 self.objects_by_texture[key][2].extend(enemy.sprite._uvs)