Mercurial > touhou
view pytouhou/game/laser.pyx @ 612:73f134f84c7f
Request a RGB888 context, since SDL2’s default of RGB332 sucks.
On X11/GLX, it will select the first config available, that is the best
one, while on EGL it will iterate over them to select the one closest
to what the application requested.
Of course, anything lower than RGB888 looks bad and we really don’t
want that.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Thu, 26 Mar 2015 20:20:37 +0100 |
parents | 3c2f96f1d715 |
children | a6af3ff86612 |
line wrap: on
line source
# -*- encoding: utf-8 -*- ## ## Copyright (C) 2012 Thibaut Girka <thib@sitedethib.com> ## ## 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 libc.math cimport cos, sin, M_PI as pi from pytouhou.game.game cimport Game from pytouhou.vm import ANMRunner cdef class LaserLaunchAnim(Element): def __init__(self, Laser laser, anm, unsigned long index): Element.__init__(self, (0, 0)) self._laser = laser self.sprite = Sprite() self.sprite.anm = anm self.sprite.texcoords = anm.sprites[index] self.sprite.blendfunc = 1 cpdef update(self): laser = self._laser length = <double>min(laser.end_offset - laser.start_offset, laser.max_length) offset = laser.end_offset - length dx, dy = cos(laser.angle), sin(laser.angle) self.x = laser.base_pos[0] + offset * dx self.y = laser.base_pos[1] + offset * dy scale = laser.width / 10. - (offset - laser.start_offset) #TODO: check self.sprite._rescale[:] = [scale, scale] self.sprite.changed = True if laser.removed or scale <= 0.: self.removed = True cdef class Laser(Element): def __init__(self, tuple base_pos, LaserType 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)) launch_anim = LaserLaunchAnim(self, laser_type.anm, laser_type.launch_anim_offsets[sprite_idx_offset] + laser_type.launch_sprite_idx) game.effects.append(launch_anim) self._laser_type = laser_type self.state = STARTING #TODO: hitbox self.frame = 0 self.start_duration = start_duration self.duration = duration self.stop_duration = stop_duration self.grazing_delay = grazing_delay self.grazing_extra_duration = grazing_extra_duration self.sprite_idx_offset = sprite_idx_offset self.set_base_pos(base_pos[0], base_pos[1]) self.angle = angle self.speed = speed self.start_offset = start_offset self.end_offset = end_offset self.max_length = max_length self.width = width self.set_anim() cdef void set_anim(self, long sprite_idx_offset=-1) except *: if sprite_idx_offset >= 0: self.sprite_idx_offset = sprite_idx_offset lt = self._laser_type self.sprite = Sprite() self.sprite.angle = self.angle self.anmrunner = ANMRunner(lt.anm, lt.anim_index, self.sprite, self.sprite_idx_offset) 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] cdef double c2[2] cdef double 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 = <double>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] 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] return (0 <= vx * v1x + vy * v1y <= v1x * v1x + v1y * v1y and 0 <= vx * v2x + vy * v2y <= v2x * v2x + v2y * v2y) cdef bint check_collision(self, double point[2]): if self.state != STARTED: return False return self._check_collision(point, 2.5) cdef bint check_grazing(self, double point[2]): #TODO: quadruple check! if self.state == STOPPING and self.frame >= self.grazing_extra_duration: return False if self.state == STARTING and self.frame <= self.grazing_delay: return False if self.frame % 12 != 0: return False return self._check_collision(point, 96 + 2.5) def get_bullets_pos(self): #TODO: check length = <double>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: yield (self.base_pos[0] + offset * dx, self.base_pos[1] + offset * dy) offset += 48. cpdef cancel(self): self.grazing_extra_duration = 0 if self.state != STOPPING: self.frame = 0 self.state = STOPPING cpdef update(self): if self.anmrunner is not None and not self.anmrunner.run_frame(): self.anmrunner = None self.end_offset += self.speed length = <double>min(self.end_offset - self.start_offset, self.max_length) # TODO width = 0. if self.state == STARTING: if self.frame == self.start_duration: self.frame = 0 self.state = STARTED else: width = self.width * float(self.frame) / self.start_duration #TODO elif self.state == STARTED: width = self.width #TODO if self.frame == self.duration: self.frame = 0 self.state = STOPPING elif self.state == STOPPING: if self.frame == self.stop_duration: self.removed = True else: width = self.width * (1. - float(self.frame) / self.stop_duration) #TODO offset = self.end_offset - length / 2. 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 self.sprite.update_orientation(pi/2. - self.angle, True) self.sprite.changed = True #TODO self.frame += 1 cdef class PlayerLaser(Element): def __init__(self, LaserType 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.frame = 0 self.duration = duration self.sprite_idx_offset = sprite_idx_offset self.angle = angle self.offset = offset self.damage = damage self.set_anim() cdef void set_anim(self, long sprite_idx_offset=-1) except *: if sprite_idx_offset >= 0: self.sprite_idx_offset = sprite_idx_offset lt = self._laser_type self.sprite = Sprite() self.anmrunner = ANMRunner(lt.anm, lt.anim_index, self.sprite, self.sprite_idx_offset) #self.sprite.blendfunc = 1 #XXX cdef void cancel(self) except *: self.anmrunner.interrupt(1) cdef void update(self) except *: if self.anmrunner is not None and not self.anmrunner.run_frame(): self.anmrunner = None self.removed = True length = self.origin.y if self.frame == self.duration: self.cancel() self.sprite.visible = (length > 0) 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