Mercurial > touhou
view pytouhou/game/enemymanager.py @ 21:bf225780973f
Small refactoring, and Rumia \o/
author | Thibaut Girka <thib@sitedethib.com> |
---|---|
date | Thu, 11 Aug 2011 12:39:12 +0200 |
parents | 6ebf9539c077 |
children | fa87db09fc3a |
line wrap: on
line source
from itertools import chain from io import BytesIO import os from struct import unpack, pack from pytouhou.utils.interpolator import Interpolator from pytouhou.game.sprite import Sprite from math import cos, sin, atan2 class Enemy(object): def __init__(self, pos, life, _type, script, anm_wrapper): self.anm_wrapper = anm_wrapper self.anm = None self.script = list(script) self.x, self.y = pos self.life = life self.type = _type self.frame = 0 self.sprite = None self.movement_dependant_sprites = None self.interpolator = None #TODO self.angle = 0. self.speed = 0. self.rotation_speed = 0. self.acceleration = 0. def update(self, frame): if not self.script: return True if self.script[0][0] == self.frame: for instr_type, rank_mask, param_mask, args in self.script.pop(0)[1]: if instr_type == 1: # delete return False elif instr_type == 97: # set_enemy_sprite script_index, = unpack('<I', args) self.anm, self.sprite = self.anm_wrapper.get_sprite(script_index) elif instr_type == 98: #TODO self.movement_dependant_sprites = unpack('<HHHHI', args) elif instr_type == 43: # set_pos self.x, self.y, z = unpack('<fff', args) self.interpolator = Interpolator((self.x, self.y)) #TODO: better interpolation self.interpolator.set_interpolation_start(self.frame, (self.x, self.y)) elif instr_type == 45: # set_angle_speed self.angle, self.speed = unpack('<ff', args) elif instr_type == 46: # set_angle self.rotation_speed, = unpack('<f', args) elif instr_type == 47: # set_speed self.speed, = unpack('<f', args) elif instr_type == 48: # set_acceleration self.acceleration, = unpack('<f', args) elif instr_type == 51: # move_towards_player #TODO: main unknown, self.speed = unpack('<If', args) #TODO: unknown player_x, player_y = 192., 400.#TODO self.angle = atan2(player_y - self.y, player_x - self.x) elif instr_type == 57: duration, x, y, z = unpack('<Ifff', args) self.interpolator.set_interpolation_end(self.frame + duration, (x, y)) x, y = self.x, self.y if self.interpolator: self.interpolator.update(self.frame) x, y = self.interpolator.values self.speed += self.acceleration #TODO: units? Execution order? self.angle += self.rotation_speed #TODO: units? Execution order? dx, dy = cos(self.angle) * self.speed, sin(self.angle) * self.speed if self.type & 2: x -= dx else: x += dx y += dy if self.movement_dependant_sprites: #TODO: is that really how it works? dx, dy = self.x - x, self.y - y if (dx, dy) == (0, 0): self.anm, self.sprite = self.anm_wrapper.get_sprite(self.movement_dependant_sprites[0]) elif abs(dx) > abs(dy): if dx < 0: self.anm, self.sprite = self.anm_wrapper.get_sprite(self.movement_dependant_sprites[2]) else: self.anm, self.sprite = self.anm_wrapper.get_sprite(self.movement_dependant_sprites[3]) else: if dy < 0: self.anm, self.sprite = self.anm_wrapper.get_sprite(self.movement_dependant_sprites[1]) else: self.anm, self.sprite = self.anm_wrapper.get_sprite(self.movement_dependant_sprites[2]) self.x, self.y = x, y if self.sprite: self.sprite.update() self.frame += 1 return True class EnemyManager(object): def __init__(self, stage, anm_wrapper, ecl): self.stage = stage self.anm_wrapper = anm_wrapper self.main = [] self.subs = {} self.objects_by_texture = {} self.enemies = [] # Populate main for frame, sub, instr_type, args in ecl.main: if not self.main or self.main[-1][0] < frame: self.main.append((frame, [(sub, instr_type, args)])) elif self.main[-1][0] == frame: self.main[-1][1].append((sub, instr_type, args)) # Populate subs for i, sub in enumerate(ecl.subs): for frame, instr_type, rank_mask, param_mask, args in sub: if i not in self.subs: self.subs[i] = [] if not self.subs[i] or self.subs[i][-1][0] < frame: self.subs[i].append((frame, [(instr_type, rank_mask, param_mask, args)])) elif self.subs[i][-1][0] == frame: self.subs[i][-1][1].append((instr_type, rank_mask, param_mask, args)) def update(self, frame): if self.main and self.main[0][0] == frame: for sub, instr_type, args in self.main.pop(0)[1]: if instr_type in (0, 2, 4, 6): # Normal/mirrored enemy x, y, z, life, unknown1, unknown2, unknown3 = args self.enemies.append(Enemy((x, y), life, instr_type, self.subs[sub], self.anm_wrapper)) # Update enemies for enemy in tuple(self.enemies): if not enemy.update(frame): self.enemies.remove(enemy) continue # Add enemies to vertices/uvs self.objects_by_texture = {} for enemy in self.enemies: ox, oy = enemy.x, enemy.y if enemy.sprite: key = enemy.anm.first_name, enemy.anm.secondary_name if not key in self.objects_by_texture: self.objects_by_texture[key] = (0, [], []) vertices = tuple((x + ox, y + oy, z) for x, y, z in enemy.sprite._vertices) self.objects_by_texture[key][2].extend(enemy.sprite._uvs) self.objects_by_texture[key][1].extend(vertices) for key, (nb_vertices, vertices, uvs) in self.objects_by_texture.items(): nb_vertices = len(vertices) vertices = pack('f' * (3 * nb_vertices), *chain(*vertices)) uvs = pack('f' * (2 * nb_vertices), *chain(*uvs)) self.objects_by_texture[key] = (nb_vertices, vertices, uvs)