# HG changeset patch # User Emmanuel Gil Peyrot # Date 1379349724 -7200 # Node ID 06f0eeb519bbab245b89dd18a4d5f0d7daf4c195 # Parent 98995d8ac7448a6efdade2eec3111174049d2f4f Make Laser and Orb extension types, and use that where possible. diff --git a/pytouhou/game/enemy.pyx b/pytouhou/game/enemy.pyx --- a/pytouhou/game/enemy.pyx +++ b/pytouhou/game/enemy.pyx @@ -17,7 +17,7 @@ from libc.math cimport cos, sin, atan2, from pytouhou.vm.anmrunner import ANMRunner from pytouhou.game.sprite import Sprite from pytouhou.game.bullet cimport Bullet, LAUNCHED -from pytouhou.game.laser import Laser +from pytouhou.game.laser cimport Laser, PlayerLaser from pytouhou.game.effect cimport Effect @@ -301,8 +301,9 @@ cdef class Enemy(Element): cdef void check_collisions(self): cdef Bullet bullet cdef Player player + cdef PlayerLaser laser cdef long damages - cdef double half_size[2], lx, ly, phalf_size + cdef double half_size[2], phalf_size # Check for collisions ex, ey = self.x, self.y diff --git a/pytouhou/game/game.pxd b/pytouhou/game/game.pxd --- a/pytouhou/game/game.pxd +++ b/pytouhou/game/game.pxd @@ -21,6 +21,7 @@ cdef class Game: cpdef drop_bonus(self, double x, double y, long _type, end_pos=*) cdef void autocollect(self, Player player) except * cdef void cancel_bullets(self) except * + cdef void cancel_player_lasers(self) except * cpdef change_bullets_into_star_items(self) cpdef change_bullets_into_bonus(self) cpdef kill_enemies(self) diff --git a/pytouhou/game/game.pyx b/pytouhou/game/game.pyx --- a/pytouhou/game/game.pyx +++ b/pytouhou/game/game.pyx @@ -19,6 +19,7 @@ from pytouhou.game.bullet cimport Bullet from pytouhou.game.enemy cimport Enemy from pytouhou.game.item cimport Item from pytouhou.game.effect cimport Particle +from pytouhou.game.laser cimport Laser, PlayerLaser from pytouhou.game.text import Text, NativeText from pytouhou.game.face import Face @@ -145,17 +146,24 @@ cdef class Game: cdef void cancel_bullets(self): cdef Bullet bullet - #TODO: cdef Laser laser + cdef Laser laser for bullet in self.bullets: bullet.cancel() for laser in self.lasers: laser.cancel() + cdef void cancel_player_lasers(self): + cdef PlayerLaser laser + for laser in self.players_lasers: + if laser is not None: + laser.cancel() + cpdef change_bullets_into_star_items(self): cdef Player player cdef Bullet bullet + cdef Laser laser player = self.players[0] #TODO item_type = self.item_types[6] @@ -253,6 +261,7 @@ cdef class Game: cpdef run_iter(self, long keystate): + cdef Laser laser # 1. VMs. for runner in self.ecl_runners: runner.run_iter() @@ -371,6 +380,9 @@ cdef class Game: cdef Player player cdef Bullet bullet cdef Item item + cdef PlayerLaser player_laser + cdef Laser laser + cdef double player_pos[2] if self.time_stop: return @@ -381,9 +393,9 @@ cdef class Game: for bullet in self.bullets: bullet.update() - for laser in self.players_lasers: - if laser is not None: - laser.update() + for player_laser in self.players_lasers: + if player_laser is not None: + player_laser.update() for item in self.items: item.update() @@ -395,6 +407,7 @@ cdef class Game: continue px, py = player_state.x, player_state.y + player_pos[:] = [px, py] phalf_size = player.sht.hitbox px1, px2 = px - phalf_size, px + phalf_size py1, py2 = py - phalf_size, py + phalf_size @@ -404,10 +417,10 @@ cdef class Game: gy1, gy2 = py - ghalf_size, py + ghalf_size for laser in self.lasers: - if laser.check_collision((px, py)): + if laser.check_collision(player_pos): if player_state.invulnerable_time == 0: player.collide() - elif laser.check_grazing((px, py)): + elif laser.check_grazing(player_pos): player_state.graze += 1 #TODO player_state.score += 500 #TODO player.play_sound('graze') @@ -460,6 +473,7 @@ cdef class Game: cdef Enemy enemy cdef Bullet bullet cdef Item item + cdef PlayerLaser laser cdef long i # Filter out non-visible enemies diff --git a/pytouhou/game/laser.pxd b/pytouhou/game/laser.pxd new file mode 100644 --- /dev/null +++ b/pytouhou/game/laser.pxd @@ -0,0 +1,44 @@ +from pytouhou.game.element cimport Element +from pytouhou.game.sprite cimport Sprite +from pytouhou.game.game cimport Game + +cdef enum State: + STARTING, STARTED, STOPPING + + +cdef class LaserLaunchAnim(Element): + cdef Laser _laser + + cpdef update(self) + + +cdef class Laser(Element): + cdef public unsigned long frame + cdef public double angle + + cdef unsigned long start_duration, duration, stop_duration, grazing_delay, + cdef unsigned long grazing_extra_duration, sprite_idx_offset + cdef double base_pos[2], speed, start_offset, end_offset, max_length, width + cdef State state + cdef Game _game + cdef object _laser_type + + cdef void set_anim(self, long sprite_idx_offset=*) except * + cpdef set_base_pos(self, double x, double y) + cdef bint _check_collision(self, double point[2], double border_size) + cdef bint check_collision(self, double point[2]) + cdef bint check_grazing(self, double point[2]) + #def get_bullets_pos(self) + cpdef cancel(self) + cpdef update(self) + + +cdef class PlayerLaser(Element): + cdef double hitbox[2], angle, offset + cdef unsigned long frame, duration, sprite_idx_offset, damage + cdef Element origin + cdef object _laser_type + + cdef void set_anim(self, long sprite_idx_offset=*) except * + cdef void cancel(self) except * + cdef void update(self) except * diff --git a/pytouhou/game/laser.py b/pytouhou/game/laser.pyx rename from pytouhou/game/laser.py rename to pytouhou/game/laser.pyx --- a/pytouhou/game/laser.py +++ b/pytouhou/game/laser.pyx @@ -12,18 +12,13 @@ ## GNU General Public License for more details. ## -from math import cos, sin, pi +from libc.math cimport cos, sin, M_PI as pi -from pytouhou.game.element import Element from pytouhou.vm.anmrunner import ANMRunner -from pytouhou.game.sprite import Sprite -STARTING, STARTED, STOPPING = range(3) - - -class LaserLaunchAnim(Element): - def __init__(self, laser, anm, index): +cdef class LaserLaunchAnim(Element): + def __init__(self, Laser laser, anm, unsigned long index): Element.__init__(self, (0, 0)) self._laser = laser @@ -33,9 +28,9 @@ class LaserLaunchAnim(Element): self.sprite.blendfunc = 1 - def update(self): + cpdef update(self): laser = self._laser - length = min(laser.end_offset - laser.start_offset, laser.max_length) + length = min(laser.end_offset - laser.start_offset, laser.max_length) offset = laser.end_offset - length dx, dy = cos(laser.angle), sin(laser.angle) @@ -51,12 +46,14 @@ class LaserLaunchAnim(Element): -class Laser(Element): - def __init__(self, base_pos, laser_type, sprite_idx_offset, - angle, speed, start_offset, end_offset, max_length, width, - start_duration, duration, stop_duration, - grazing_delay, grazing_extra_duration, - game): +cdef class Laser(Element): + def __init__(self, tuple base_pos, laser_type, + unsigned long sprite_idx_offset, double angle, double speed, + double start_offset, double end_offset, double max_length, + double width, unsigned long start_duration, + unsigned long duration, unsigned long stop_duration, + unsigned long grazing_delay, + unsigned long grazing_extra_duration, Game game): Element.__init__(self, (0, 0)) self._game = game @@ -77,7 +74,7 @@ class Laser(Element): self.grazing_extra_duration = grazing_extra_duration self.sprite_idx_offset = sprite_idx_offset - self.base_pos = base_pos + self.set_base_pos(base_pos[0], base_pos[1]) self.angle = angle self.speed = speed self.start_offset = start_offset @@ -88,8 +85,8 @@ class Laser(Element): self.set_anim() - def set_anim(self, sprite_idx_offset=None): - if sprite_idx_offset is not None: + cdef void set_anim(self, long sprite_idx_offset=-1): + if sprite_idx_offset >= 0: self.sprite_idx_offset = sprite_idx_offset lt = self._laser_type @@ -99,19 +96,25 @@ class Laser(Element): self.sprite, self.sprite_idx_offset) - def _check_collision(self, point, border_size): + cpdef set_base_pos(self, double x, double y): + self.base_pos[:] = [x, y] + + + cdef bint _check_collision(self, double point[2], double border_size): + cdef double c1[2], c2[2], c3[2] + x, y = point[0] - self.base_pos[0], point[1] - self.base_pos[1] dx, dy = cos(self.angle), sin(self.angle) dx2, dy2 = -dy, dx - length = min(self.end_offset - self.start_offset, self.max_length) + length = min(self.end_offset - self.start_offset, self.max_length) offset = self.end_offset - length - border_size / 2. end_offset = self.end_offset + border_size / 2. half_width = self.width / 4. + border_size / 2. - c1 = dx * offset - dx2 * half_width, dy * offset - dy2 * half_width - c2 = dx * offset + dx2 * half_width, dy * offset + dy2 * half_width - c3 = dx * end_offset + dx2 * half_width, dy * end_offset + dy2 * half_width + c1[:] = [dx * offset - dx2 * half_width, dy * offset - dy2 * half_width] + c2[:] = [dx * offset + dx2 * half_width, dy * offset + dy2 * half_width] + c3[:] = [dx * end_offset + dx2 * half_width, dy * end_offset + dy2 * half_width] vx, vy = x - c2[0], y - c2[1] v1x, v1y = c1[0] - c2[0], c1[1] - c2[1] v2x, v2y = c3[0] - c2[0], c3[1] - c2[1] @@ -120,14 +123,14 @@ class Laser(Element): and 0 <= vx * v2x + vy * v2y <= v2x * v2x + v2y * v2y) - def check_collision(self, point): + cdef bint check_collision(self, double point[2]): if self.state != STARTED: return False return self._check_collision(point, 2.5) - def check_grazing(self, point): + cdef bint check_grazing(self, double point[2]): #TODO: quadruple check! if self.state == STOPPING and self.frame >= self.grazing_extra_duration: return False @@ -141,7 +144,7 @@ class Laser(Element): def get_bullets_pos(self): #TODO: check - length = min(self.end_offset - self.start_offset, self.max_length) + length = min(self.end_offset - self.start_offset, self.max_length) offset = self.end_offset - length dx, dy = cos(self.angle), sin(self.angle) while self.start_offset <= offset < self.end_offset: @@ -149,20 +152,20 @@ class Laser(Element): offset += 48. - def cancel(self): + cpdef cancel(self): self.grazing_extra_duration = 0 if self.state != STOPPING: self.frame = 0 self.state = STOPPING - def update(self): + cpdef update(self): if self.anmrunner is not None and not self.anmrunner.run_frame(): self.anmrunner = None self.end_offset += self.speed - length = min(self.end_offset - self.start_offset, self.max_length) # TODO + length = min(self.end_offset - self.start_offset, self.max_length) # TODO if self.state == STARTING: if self.frame == self.start_duration: self.frame = 0 @@ -182,7 +185,8 @@ class Laser(Element): width = self.width * (1. - float(self.frame) / self.stop_duration) #TODO offset = self.end_offset - length / 2. - self.x, self.y = self.base_pos[0] + offset * cos(self.angle), self.base_pos[1] + offset * sin(self.angle) + self.x = self.base_pos[0] + offset * cos(self.angle) + self.y = self.base_pos[1] + offset * sin(self.angle) self.sprite.visible = (width > 0 and length > 0) self.sprite.width_override = width self.sprite.height_override = length @@ -193,15 +197,16 @@ class Laser(Element): self.frame += 1 -class PlayerLaser(Element): - def __init__(self, laser_type, sprite_idx_offset, hitbox, damage, - angle, offset, duration, origin): +cdef class PlayerLaser(Element): + def __init__(self, laser_type, unsigned long sprite_idx_offset, + tuple hitbox, unsigned long damage, double angle, + double offset, unsigned long duration, Element origin): Element.__init__(self) self._laser_type = laser_type self.origin = origin - self.hitbox = hitbox[0], hitbox[1] + self.hitbox[:] = [hitbox[0], hitbox[1]] self.frame = 0 self.duration = duration @@ -214,18 +219,8 @@ class PlayerLaser(Element): self.set_anim() - @property - def x(self): - return self.origin.x + self.offset * cos(self.angle) - - - @property - def y(self): - return self.origin.y / 2. + self.offset * sin(self.angle) - - - def set_anim(self, sprite_idx_offset=None): - if sprite_idx_offset is not None: + cdef void set_anim(self, long sprite_idx_offset=-1): + if sprite_idx_offset >= 0: self.sprite_idx_offset = sprite_idx_offset lt = self._laser_type @@ -235,11 +230,11 @@ class PlayerLaser(Element): #self.sprite.blendfunc = 1 #XXX - def cancel(self): + cdef void cancel(self): self.anmrunner.interrupt(1) - def update(self): + cdef void update(self): if self.anmrunner is not None and not self.anmrunner.run_frame(): self.anmrunner = None self.removed = True @@ -252,5 +247,7 @@ class PlayerLaser(Element): self.sprite.height_override = length self.sprite.changed = True #TODO + self.x = self.origin.x + self.offset * cos(self.angle) + self.y = self.origin.y / 2. + self.offset * sin(self.angle) + self.frame += 1 - diff --git a/pytouhou/game/orb.pxd b/pytouhou/game/orb.pxd new file mode 100644 --- /dev/null +++ b/pytouhou/game/orb.pxd @@ -0,0 +1,10 @@ +from pytouhou.game.element cimport Element +from pytouhou.game.sprite cimport Sprite +from pytouhou.game.player cimport PlayerState + +cdef class Orb(Element): + cdef public double offset_x, offset_y + cdef PlayerState player_state + cdef object fire + + cpdef update(self) diff --git a/pytouhou/game/orb.py b/pytouhou/game/orb.py --- a/pytouhou/game/orb.py +++ b/pytouhou/game/orb.py @@ -12,16 +12,11 @@ ## GNU General Public License for more details. ## - -from pytouhou.game.element import Element -from pytouhou.game.sprite import Sprite from pytouhou.vm.anmrunner import ANMRunner class Orb(Element): - __slots__ = ('offset_x', 'offset_y', 'player_state', 'fire') - - def __init__(self, anm, index, player_state, fire_func): + def __init__(self, anm, index, player_state): Element.__init__(self) self.sprite = Sprite() @@ -31,19 +26,9 @@ class Orb(Element): 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() - + self.x = self.player_state.x + self.offset_x + self.y = self.player_state.y + self.offset_y diff --git a/pytouhou/game/player.pyx b/pytouhou/game/player.pyx --- a/pytouhou/game/player.pyx +++ b/pytouhou/game/player.pyx @@ -19,7 +19,7 @@ from pytouhou.vm.anmrunner import ANMRun from pytouhou.game.bullettype import BulletType from pytouhou.game.bullet cimport Bullet from pytouhou.game.lasertype import LaserType -from pytouhou.game.laser import PlayerLaser +from pytouhou.game.laser cimport PlayerLaser class GameOver(Exception): @@ -247,9 +247,7 @@ cdef class Player(Element): self.state.power -= 16 else: self.state.power = 0 - for laser in self._game.players_lasers: - if laser is not None: - laser.cancel() + self._game.cancel_player_lasers() self.state.miss += 1 self.state.lives -= 1 diff --git a/pytouhou/games/eosd.py b/pytouhou/games/eosd.py --- a/pytouhou/games/eosd.py +++ b/pytouhou/games/eosd.py @@ -275,8 +275,8 @@ class EoSDPlayer(Player): Player.__init__(self, state, game, self.anm) - self.orbs = [Orb(self.anm, 128, self.state, None), - Orb(self.anm, 129, self.state, None)] + self.orbs = [Orb(self.anm, 128, self.state), + Orb(self.anm, 129, self.state)] self.orbs[0].offset_x = -24 self.orbs[1].offset_x = 24 diff --git a/pytouhou/vm/eclrunner.py b/pytouhou/vm/eclrunner.py --- a/pytouhou/vm/eclrunner.py +++ b/pytouhou/vm/eclrunner.py @@ -728,7 +728,7 @@ class ECLRunner(object): except KeyError: pass #TODO else: - laser.base_pos = self._enemy.x + ox, self._enemy.y + oy + laser.set_base_pos(self._enemy.x + ox, self._enemy.y + oy) @instruction(92)