# HG changeset patch # User Emmanuel Gil Peyrot # Date 1319406644 25200 # Node ID 184196480f59e7468e29ae003073e082144fecf5 # Parent 5a1533677a9a78642deaa8d12d71dff3380aa89e Don’t use the useless eff00.anm and implement particles (grazing, death, and more). diff --git a/pytouhou/game/effect.py b/pytouhou/game/effect.py --- a/pytouhou/game/effect.py +++ b/pytouhou/game/effect.py @@ -15,6 +15,8 @@ from pytouhou.game.sprite import Sprite from pytouhou.vm.anmrunner import ANMRunner +from pytouhou.utils.interpolator import Interpolator +from math import pi @@ -27,6 +29,7 @@ class Effect(object): self.x, self.y = pos + def update(self): if self._anmrunner and not self._anmrunner.run_frame(): self._anmrunner = None @@ -34,3 +37,41 @@ class Effect(object): if self._sprite: if self._sprite._removed: self._sprite = None + + +class Particle(object): + def __init__(self, start_pos, index, anm_wrapper, size, end_pos): + self._sprite = Sprite() + self._sprite.anm, self._sprite.texcoords = anm_wrapper.get_sprite(index) + self._removed = False + + self.x, self.y = start_pos + self.frame = 0 + self._sprite.alpha = 128 + self._sprite.blendfunc = 1 + + self.pos_interpolator = Interpolator(start_pos, 0, + end_pos, 24, formula=(lambda x: 2. * x - x ** 2)) + self.scale_interpolator = Interpolator((size, size), 0, + (0., 0.), 24) + self.rotations_interpolator = Interpolator((0., 0., 0.), 0, + (0., 0., 2*pi), 24) + self._sprite._changed = True + + + def update(self): + self.pos_interpolator.update(self.frame) + self.x, self.y = self.pos_interpolator.values + + self.scale_interpolator.update(self.frame) + self._sprite.rescale = self.scale_interpolator.values + + self.rotations_interpolator.update(self.frame) + self._sprite.rotations_3d = self.rotations_interpolator.values + + self._sprite._changed = True + + if self.frame == 24: + self._removed = True + + self.frame += 1 diff --git a/pytouhou/game/enemy.py b/pytouhou/game/enemy.py --- a/pytouhou/game/enemy.py +++ b/pytouhou/game/enemy.py @@ -156,7 +156,11 @@ class Enemy(object): def die_anim(self): - self._game.new_effect((self.x, self.y), self.death_anim) + self._game.new_death((self.x, self.y), self.death_anim) + #TODO: 8 white particles are used only in stage 3 to 6, + # in other stages they are 2 red and 6 blue. + for i in range(8): + self._game.new_particle((self.x, self.y), 0, 3., 192) def set_pos(self, x, y, z): diff --git a/pytouhou/game/game.py b/pytouhou/game/game.py --- a/pytouhou/game/game.py +++ b/pytouhou/game/game.py @@ -21,6 +21,7 @@ from pytouhou.game.player import Player from pytouhou.game.enemy import Enemy from pytouhou.game.item import Item from pytouhou.game.effect import Effect +from pytouhou.game.effect import Particle @@ -52,7 +53,7 @@ class Game(object): self.enm_anm_wrapper = resource_loader.get_anm_wrapper2(('stg%denm.anm' % stage, 'stg%denm2.anm' % stage)) - self.eff00 = resource_loader.get_anm_wrapper(('eff00.anm',)) + self.etama4 = resource_loader.get_anm_wrapper(('etama4.anm',)) ecl = resource_loader.get_ecl('ecldata%d.ecl' % stage) self.ecl_runner = ECLMainRunner(ecl, self) @@ -73,8 +74,15 @@ class Game(object): self.bullets = [] - def new_effect(self, pos, anim): - self.effects.append(Effect(pos, anim, self.eff00)) + def new_death(self, pos, index): + anim = {0: 3, 1: 4, 2: 5}[index % 256] # The TB is wanted, if index isn’t in these values the original game crashs. + self.effects.append(Effect(pos, anim, self.etama4)) + + + def new_particle(self, pos, color, size, amp): + self.effects.append(Particle(pos, 7 + 4 * color + self.prng.rand_uint16() % 4, self.etama4, size, + (pos[0] + amp * self.prng.rand_double() - amp/2, + pos[1] + amp * self.prng.rand_double() - amp/2))) def new_enemy(self, pos, life, instr_type, bonus_dropped, die_score): @@ -152,9 +160,13 @@ class Game(object): if player.state.invulnerable_time == 0: player.collide() - elif not (bx2 < gx1 or bx1 > gx2 + elif not bullet.grazed and not (bx2 < gx1 or bx1 > gx2 or by2 < gy1 or by1 > gy2): - pass#TODO: graze + bullet.grazed = True + player.state.score += 500 # found experimentally + self.new_particle((px, py), 0, .8, 192) + #TODO: display a static particle during one frame at + # 12 pixels of the player, in the axis of the “collision”. for enemy in self.enemies: half_size_x, half_size_y = enemy.hitbox_half_size diff --git a/pytouhou/game/player.py b/pytouhou/game/player.py --- a/pytouhou/game/player.py +++ b/pytouhou/game/player.py @@ -77,7 +77,7 @@ class Player(object): def collide(self): if not self.state.invulnerable_time and not self.death_time and self.state.touchable: # Border Between Life and Death self.death_time = self._game.frame - self._game.new_effect((self.state.x, self.state.y), 2) + self._game.new_death((self.state.x, self.state.y), 2) def collect(self, item): @@ -131,6 +131,8 @@ class Player(object): for i in range(5): self._game.drop_bonus(self.state.x, self.state.y, 0, end_pos=None) #TODO: find the formula self.state.lives -= 1 + for i in range(16): + self._game.new_particle((self.state.x, self.state.y), 0, 4., 256) elif time == 7: self._sprite.mirrored = False diff --git a/pytouhou/vm/eclrunner.py b/pytouhou/vm/eclrunner.py --- a/pytouhou/vm/eclrunner.py +++ b/pytouhou/vm/eclrunner.py @@ -743,7 +743,7 @@ class ECLRunner(object): @instruction(100) def set_death_anim(self, sprite_index): - self._enemy.death_anim = sprite_index % 256 #TODO + self._enemy.death_anim = sprite_index @instruction(101)