# HG changeset patch # User Emmanuel Gil Peyrot # Date 1320079137 25200 # Node ID 8ec34c56fed0896e8a4305850f2d3e8f99254e2e # Parent 13918723d1bcc2768b1371dad8a279a9d445c082 Implement orbs. diff --git a/pytouhou/game/orb.py b/pytouhou/game/orb.py new file mode 100644 --- /dev/null +++ b/pytouhou/game/orb.py @@ -0,0 +1,44 @@ +# -*- encoding: utf-8 -*- +## +## Copyright (C) 2011 Emmanuel Gil Peyrot +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation; version 3 only. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## + + +from pytouhou.game.sprite import Sprite +from pytouhou.vm.anmrunner import ANMRunner + + +class Orb(object): + def __init__(self, anm_wrapper, index, player_state, fire_func): + self._sprite = Sprite() + self._anmrunner = ANMRunner(anm_wrapper, index, self._sprite) + self._anmrunner.run_frame() + + self.offset_x = 0 + self.offset_y = 0 + + self.player_state = player_state + self.fire = fire_func + + + @property + def x(self): + return self.player_state.x + self.offset_x + + + @property + def y(self): + return self.player_state.y + self.offset_y + + + def update(self): + self._anmrunner.run_frame() diff --git a/pytouhou/game/player.py b/pytouhou/game/player.py --- a/pytouhou/game/player.py +++ b/pytouhou/game/player.py @@ -16,6 +16,7 @@ from pytouhou.game.sprite import Sprite from pytouhou.vm.anmrunner import ANMRunner from pytouhou.game.bullettype import BulletType +from pytouhou.utils.interpolator import Interpolator from math import pi @@ -40,6 +41,7 @@ class PlayerState(object): self.invulnerable_time = 240 self.touchable = True + self.focused = False self.power_bonus = 0 # Never goes over 30. @@ -72,6 +74,9 @@ class Player(object): self.death_time = 0 + self.orb_dx_interpolator = None + self.orb_dy_interpolator = None + @property def x(self): @@ -83,6 +88,10 @@ class Player(object): return self.state.y + def objects(self): + return self.orbs if self.state.power >= 8 else [] + + def set_anim(self, index): self._sprite = Sprite() self._anmrunner = ANMRunner(self.anm_wrapper, index, self._sprite) @@ -124,6 +133,32 @@ class Player(object): self.state.x += dx self.state.y += dy + if not self.state.focused and keystate & 4: + self.orb_dx_interpolator = Interpolator((24,), self._game.frame, + (8,), self._game.frame + 8, + lambda x: x ** 2) + self.orb_dy_interpolator = Interpolator((0,), self._game.frame, + (-32,), self._game.frame + 8) + self.state.focused = True + elif self.state.focused and not keystate & 4: + self.orb_dx_interpolator = Interpolator((8,), self._game.frame, + (24,), self._game.frame + 8, + lambda x: x ** 2) + self.orb_dy_interpolator = Interpolator((-32,), self._game.frame, + (0,), self._game.frame + 8) + self.state.focused = False + + if self.orb_dx_interpolator: + self.orb_dx_interpolator.update(self._game.frame) + dx, = self.orb_dx_interpolator.values + self.orbs[0].offset_x = -dx + self.orbs[1].offset_x = dx + if self.orb_dy_interpolator: + self.orb_dy_interpolator.update(self._game.frame) + dy, = self.orb_dy_interpolator.values + self.orbs[0].offset_y = dy + self.orbs[1].offset_y = dy + if self.state.invulnerable_time > 0: self.state.invulnerable_time -= 1 @@ -192,5 +227,9 @@ class Player(object): self.death_time = 0 + for orb in self.orbs: + orb.update() + + self._anmrunner.run_frame() diff --git a/pytouhou/games/eosd.py b/pytouhou/games/eosd.py --- a/pytouhou/games/eosd.py +++ b/pytouhou/games/eosd.py @@ -18,6 +18,7 @@ from pytouhou.game.bullettype import Bul from pytouhou.game.itemtype import ItemType from pytouhou.game.player import Player from pytouhou.game.bullet import Bullet +from pytouhou.game.orb import Orb from math import pi @@ -72,7 +73,7 @@ class Reimu(Player): bullets_per_shot = 3 elif self.state.power < 128: bullets_per_shot = 4 - elif self.state.power >= 128: + else: bullets_per_shot = 5 bullets = self._game.players_bullets @@ -89,12 +90,15 @@ class Reimu(Player): 0, self, self._game, player_bullet=True)) bullet_angle += self.bullet_angle + for orb in self.orbs: + orb.fire(orb) + class ReimuA(Reimu): def __init__(self, state, game, resource_loader): Reimu.__init__(self, state, game, resource_loader) - self.bulletA_type = BulletType(self.anm_wrapper, 65, 97, 0, 0, 0, hitbox_size=4, damage=48) #TODO: verify the hitbox and damages. + self.bulletA_type = BulletType(self.anm_wrapper, 65, 97, 0, 0, 0, hitbox_size=4, damage=14) #TODO: verify the hitbox. self.bulletA_speed = 12. @@ -112,70 +116,67 @@ class ReimuB(Reimu): def __init__(self, state, game, resource_loader): Reimu.__init__(self, state, game, resource_loader) - self.bulletB_type = BulletType(self.anm_wrapper, 66, 98, 0, 0, 0, hitbox_size=4, damage=48) #TODO: verify the hitbox and damages. + self.bulletB_type = BulletType(self.anm_wrapper, 66, 98, 0, 0, 0, hitbox_size=4, damage=12) #TODO: verify the hitbox. self.bulletB_speed = 22. + self.orbs = [Orb(self.anm_wrapper, 128, self.state, self.orb_fire), + Orb(self.anm_wrapper, 129, self.state, self.orb_fire)] + self.orbs[0].dx = -24 + self.orbs[1].dx = 24 - def fire_spine(self, offset_x): + + def fire_spine(self, orb, offset_x): bullets = self._game.players_bullets nb_bullets_max = self._game.nb_bullets_max if nb_bullets_max is not None and len(bullets) == nb_bullets_max: return - bullets.append(Bullet((self.x + offset_x, self.y), self.bulletB_type, 0, + bullets.append(Bullet((orb.x + offset_x, orb.y), self.bulletB_type, 0, self.bullet_launch_angle, self.bulletB_speed, (0, 0, 0, 0, 0., 0., 0., 0.), 0, self, self._game, player_bullet=True)) - - def fire(self): - Reimu.fire(self) - + def orb_fire(self, orb): if self.state.power < 8: return elif self.state.power < 16: if self.fire_time % 15 == 0: - for offset in (-24, 24): - self.fire_spine(offset) + self.fire_spine(orb, 0) elif self.state.power < 32: if self.fire_time % 10 == 0: - for offset in (-24, 24): - self.fire_spine(offset) + self.fire_spine(orb, 0) elif self.state.power < 48: if self.fire_time % 8 == 0: - for offset in (-24, 24): - self.fire_spine(offset) + self.fire_spine(orb, 0) elif self.state.power < 96: + if self.fire_time % 8 == 0: + self.fire_spine(orb, -8) if self.fire_time % 5 == 0: - for offset in (-16, 32): - self.fire_spine(offset) - if self.fire_time % 8 == 0: - for offset in (-32, 16): - self.fire_spine(offset) + self.fire_spine(orb, 8) elif self.state.power < 128: + if self.fire_time % 5 == 0: + self.fire_spine(orb, -12) + if self.fire_time % 10 == 0: + self.fire_spine(orb, 0) if self.fire_time % 3 == 0: - for offset in (-12, 36): - self.fire_spine(offset) - if self.fire_time % 5 == 0: - for offset in (-36, 12): - self.fire_spine(offset) - if self.fire_time % 10 == 0: - for offset in (-24, 24): - self.fire_spine(offset) + self.fire_spine(orb, 12) else: if self.fire_time % 3 == 0: - for offset in (-36, -12, 12, 36): - self.fire_spine(offset) + self.fire_spine(orb, -12) + self.fire_spine(orb, 12) if self.fire_time % 5 == 0: - for offset in (-24, 24): - self.fire_spine(offset) + self.fire_spine(orb, 0) + + + def update(self, keystate): + Player.update(self, keystate) class Marisa(Player): @@ -194,7 +195,7 @@ class Marisa(Player): bullets_per_shot = 2 elif self.state.power < 128: bullets_per_shot = 3 - elif self.state.power >= 128: + else: bullets_per_shot = 5 bullets = self._game.players_bullets @@ -217,10 +218,10 @@ class MarisaA(Marisa): Marisa.__init__(self, state, game, resource_loader) #TODO: verify the hitbox and damages. - self.bulletA_types = [BulletType(self.anm_wrapper, 65, 0, 0, 0, 0, hitbox_size=4, damage=48), - BulletType(self.anm_wrapper, 66, 0, 0, 0, 0, hitbox_size=4, damage=48), - BulletType(self.anm_wrapper, 67, 0, 0, 0, 0, hitbox_size=4, damage=48), - BulletType(self.anm_wrapper, 68, 0, 0, 0, 0, hitbox_size=4, damage=48)] + self.bulletA_types = [BulletType(self.anm_wrapper, 65, 0, 0, 0, 0, hitbox_size=4, damage=40), + BulletType(self.anm_wrapper, 66, 0, 0, 0, 0, hitbox_size=4), + BulletType(self.anm_wrapper, 67, 0, 0, 0, 0, hitbox_size=4), + BulletType(self.anm_wrapper, 68, 0, 0, 0, 0, hitbox_size=4)] self.bulletA_speed_interpolator = None @@ -238,7 +239,17 @@ class MarisaB(Marisa): def __init__(self, state, game, resource_loader): Marisa.__init__(self, state, game, resource_loader) - self.laser_type = None + #TODO: power damages period + # 8 240 120 + # 16 390 170 + # 32 480 ??? + # 48 510 ??? + # 64 760 ??? + # 80 840 ??? + # 96 1150 270 + # 128 1740 330 + # The duration of the laser is period - 42. + # The damages are given for one laser shot on one enemy for its entire duration. def fire(self): diff --git a/pytouhou/opengl/gamerenderer.pyx b/pytouhou/opengl/gamerenderer.pyx --- a/pytouhou/opengl/gamerenderer.pyx +++ b/pytouhou/opengl/gamerenderer.pyx @@ -152,6 +152,8 @@ cdef class GameRenderer: self.render_elements(game.enemies) self.render_elements(game.effects) self.render_elements(game.players) + for player in game.players: + self.render_elements(player.objects()) self.render_elements(game.bullets) self.render_elements(game.cancelled_bullets) self.render_elements(game.players_bullets)