pilas.habilidades

Package pilas :: Module habilidades |
[hide private]
[frames] | no frames]

# Source Code for Module pilas.habilidades

      1  # -*- encoding: utf-8 -*-
      2  # Pilas engine - A video game framework.
      3  #
      4  # Copyright 2010 - Hugo Ruscitti
      5  # License: LGPLv3 (see http://www.gnu.org/licenses/lgpl.html)
      6  #
      7  # Website - http://www.pilas-engine.com.ar
      8
      9  import random
     10  import pilas
     11  import math
     12
     13 -class Habilidad(object):
     14      """Representa una habilidad que un actor puede aprender."""
     15
     16 -    def __init__(self, receptor):
     17          self.receptor = receptor
     18
     19 -    def actualizar(self):
     20          pass
     21
     22 -    def eliminar(self):
     23          pass
     24
     25
     26 -class RebotarComoPelota(Habilidad):
     27      """Le indica al actor que rebote y colisiones como una pelota.
     28
     29      >>> un_actor = pilas.actores.Aceituna()
     30      >>> un_actor.aprender(pilas.habilidades.RebotarComoPelota)
     31      """
     32
     33 -    def __init__(self, receptor):
     34          Habilidad.__init__(self, receptor)
     35          error = random.randint(-10, 10) / 10.0
     36
     37          circulo = pilas.fisica.Circulo(receptor.x + error,
     38                                         receptor.y + error,
     39                                         receptor.radio_de_colision)
     40          receptor.aprender(pilas.habilidades.Imitar, circulo)
     41          self.circulo = circulo
     42          receptor.impulsar = self.impulsar
     43          receptor.empujar = self.empujar
     44
     45 -    def eliminar(self):
     46          self.circulo.eliminar()
     47
     48 -    def impulsar(self, dx, dy):
     49          self.circulo.impulsar(dx, dy)
     50
     51 -    def empujar(self, dx, dy):
     52          self.circulo.empujar(dx, dy)
     53
     54
     55 -class RebotarComoCaja(Habilidad):
     56      """Le indica al actor que rebote y colisiones como una caja cuadrada.
     57
     58      >>> un_actor = pilas.actores.Aceituna()
     59      >>> un_actor.aprender(pilas.habilidades.RebotarComoPelota)
     60      """
     61
     62 -    def __init__(self, receptor):
     63          Habilidad.__init__(self, receptor)
     64          error = random.randint(-10, 10) / 10.0
     65          rectangulo = pilas.fisica.Rectangulo(receptor.x + error,
     66                                               receptor.y + error,
     67                                               receptor.radio_de_colision*2 - 4,
     68                                               receptor.radio_de_colision*2 - 4,
     69                                               )
     70          receptor.aprender(pilas.habilidades.Imitar, rectangulo)
     71          self.rectangulo = rectangulo
     72
     73 -    def eliminar(self):
     74          self.rectangulo.eliminar()
     75
     76
     77 -class ColisionableComoPelota(RebotarComoPelota):
     78      """Le indica al actor que colisione como una pelota, pero que no rebote.
     79
     80      >>> un_actor = pilas.actores.Aceituna()
     81      >>> un_actor.aprender(pilas.habilidades.ColisionableComoPelota)
     82      """
     83
     84 -    def __init__(self, receptor):
     85          RebotarComoPelota.__init__(self, receptor)
     86
     87 -    def actualizar(self):
     88          self.figura.body.position.x = self.receptor.x
     89          self.figura.body.position.y = self.receptor.y
     90
     91 -    def eliminar(self):
     92          pilas.fisica.fisica.eliminar(self.figura)
     93
     94
     95 -class SeguirAlMouse(Habilidad):
     96      "Hace que un actor siga la posición del mouse en todo momento."
     97
     98 -    def __init__(self, receptor):
     99          Habilidad.__init__(self, receptor)
    100          pilas.escena_actual().mueve_mouse.conectar(self.mover)
    101
    102 -    def mover(self, evento):
    103          self.receptor.x = evento.x
    104          self.receptor.y = evento.y
    105
    106
    107 -class RotarConMouse(Habilidad):
    108      """"Hace que un actor rote con respecto a la posicion del mouse.
    109
    110      Ejemplo:
    111
    112          >>> actor.aprender(pilas.habilidades.RotarConMouse,
    113                             lado_seguimiento=pilas.habilidades.RotarConMouse.ABAJO)
    114
    115      """
    116      ARRIBA = 270
    117      ABAJO = 90
    118      IZQUIERDA = 180
    119      DERECHA = 0
    120
    121 -    def __init__(self, receptor, lado_seguimiento=ARRIBA):
    122          """Inicializa la Habilidad
    123
    124          :param receptor: La referencia al actor.
    125          :param lado_seguimiento: Establece el lado del actor que rotará para estar encarado hacia el puntero del mouse.
    126          """
    127          Habilidad.__init__(self, receptor)
    128          pilas.escena_actual().mueve_mouse.conectar(self.se_movio_el_mouse)
    129          pilas.escena_actual().actualizar.conectar(self.rotar)
    130          self.lado_seguimiento = lado_seguimiento
    131
    132          self.raton_x = receptor.x
    133          self.raton_y = receptor.y
    134
    135 -    def se_movio_el_mouse(self, evento):
    136          self.raton_x = evento.x
    137          self.raton_y = evento.y
    138
    139 -    def rotar(self, evento):
    140
    141          receptor = (self.receptor.x, self.receptor.y)
    142          raton = (self.raton_x, self.raton_y)
    143
    144          angulo = pilas.utils.obtener_angulo_entre(receptor, raton)
    145
    146          self.receptor.rotacion = -(angulo) - self.lado_seguimiento
    147
    148
    149 -class MirarAlActor(Habilidad):
    150      """"Hace que un actor rote para mirar hacia otro actor.
    151      """
    152      ARRIBA = 270
    153      ABAJO = 90
    154      IZQUIERDA = 180
    155      DERECHA = 0
    156
    157 -    def __init__(self, receptor, actor_a_seguir, lado_seguimiento=ARRIBA):
    158          """Inicializa la habilidad.
    159
    160          :param receptor: Actor que aprenderá la habilidad.
    161          :param actor_a_seguir : Actor al que se desea seguir con la mirada.
    162          :param lado_seguimiento: Establece el lado del actor que rotará para estar encarado hacia el actor que desea vigilar.
    163          """
    164          Habilidad.__init__(self, receptor)
    165          pilas.escena_actual().actualizar.conectar(self.rotar)
    166          self.lado_seguimiento = lado_seguimiento
    167
    168          self.actor_a_seguir = actor_a_seguir
    169
    170 -    def rotar(self, evento):
    171          receptor = (self.receptor.x, self.receptor.y)
    172          actor_a_seguir = (self.actor_a_seguir.x, self.actor_a_seguir.y)
    173
    174          angulo = pilas.utils.obtener_angulo_entre(receptor, actor_a_seguir)
    175
    176          self.receptor.rotacion = -(angulo) - self.lado_seguimiento
    177
    178
    179 -class AumentarConRueda(Habilidad):
    180      "Permite cambiar el tamaño de un actor usando la ruedita scroll del mouse."
    181
    182 -    def __init__(self, receptor):
    183          Habilidad.__init__(self, receptor)
    184          pilas.escena_actual().mueve_rueda.conectar(self.cambiar_de_escala)
    185
    186 -    def cambiar_de_escala(self, evento):
    187          self.receptor.escala += (evento.delta / 4.0)
    188
    189
    190 -class SeguirClicks(Habilidad):
    191      "Hace que el actor se coloque la posición del cursor cuando se hace click."
    192
    193 -    def __init__(self, receptor):
    194          Habilidad.__init__(self, receptor)
    195          pilas.escena_actual().click_de_mouse.conectar(self.moverse_a_este_punto)
    196
    197 -    def moverse_a_este_punto(self, evento):
    198          if (evento.boton == 1):
    199              self.receptor.x = [evento.x], 0.5
    200              self.receptor.y = [evento.y], 0.5
    201
    202
    203 -class Arrastrable(Habilidad):
    204      """Hace que un objeto se pueda arrastrar con el puntero del mouse.
    205
    206      Cuando comienza a mover al actor se llama al metodo ''comienza_a_arrastrar''
    207      y cuando termina llama a ''termina_de_arrastrar''. Estos nombres
    208      de metodos se llaman para que puedas personalizar estos eventos, dado
    209      que puedes usar polimorfismo para redefinir el comportamiento
    210      de estos dos metodos. Observa un ejemplo de esto en
    211      el ejemplo ``pilas.ejemplos.Piezas``.
    212
    213      """
    214
    215 -    def __init__(self, receptor):
    216          Habilidad.__init__(self, receptor)
    217          pilas.escena_actual().click_de_mouse.conectar(self.cuando_intenta_arrastrar)
    218
    219 -    def cuando_intenta_arrastrar(self, evento):
    220          "Intenta mover el objeto con el mouse cuando se pulsa sobre el."
    221          if (evento.boton == 1):
    222              if self.receptor.colisiona_con_un_punto(evento.x, evento.y):
    223                  pilas.escena_actual().termina_click.conectar(self.cuando_termina_de_arrastrar, id='cuando_termina_de_arrastrar')
    224                  pilas.escena_actual().mueve_mouse.conectar(self.cuando_arrastra, id='cuando_arrastra')
    225                  self.comienza_a_arrastrar()
    226
    227 -    def cuando_arrastra(self, evento):
    228          "Arrastra el actor a la posicion indicada por el puntero del mouse."
    229          if self._el_receptor_tiene_fisica():
    230              pilas.escena_actual().fisica.cuando_mueve_el_mouse(evento.x, evento.y)
    231          else:
    232              self.receptor.x += evento.dx
    233              self.receptor.y += evento.dy
    234
    235 -    def cuando_termina_de_arrastrar(self, evento):
    236          "Suelta al actor porque se ha soltado el botón del mouse."
    237          pilas.escena_actual().mueve_mouse.desconectar_por_id(id='cuando_arrastra')
    238          self.termina_de_arrastrar()
    239          pilas.escena_actual().termina_click.desconectar_por_id(id='cuando_termina_de_arrastrar')
    240
    241 -    def comienza_a_arrastrar(self):
    242          if self._el_receptor_tiene_fisica():
    243              pilas.escena_actual().fisica.capturar_figura_con_el_mouse(self.receptor.figura)
    244
    245 -    def termina_de_arrastrar(self):
    246          if self._el_receptor_tiene_fisica():
    247              pilas.escena_actual().fisica.cuando_suelta_el_mouse()
    248
    249 -    def _el_receptor_tiene_fisica(self):
    250          return hasattr(self.receptor, 'figura')
    251
    252
    253 -class MoverseConElTeclado(Habilidad):
    254      """Hace que un actor cambie de posición con pulsar el teclado."""
    255      CUATRO_DIRECCIONES = 4
    256      OCHO_DIRECCIONES = 8
    257
    258
    259 -    def __init__(self, receptor, control=None, direcciones=OCHO_DIRECCIONES, velocidad_maxima=4,
    260                   aceleracion=1, deceleracion=0.1, con_rotacion=False, velocidad_rotacion=1, marcha_atras=True):
    261          """Inicializa la habilidad.
    262
    263          :param receptor: Referencia al actor que aprenderá la habilidad.
    264          :param control: Control al que va a responder para mover el Actor.
    265          :param direcciones: Establece si puede mover en cualquier direccion o unicamente en 4 direcciones arriba, abajo, izquierda y derecha. El parametro con_rotacion establece las direcciones a OCHO_DIRECCIONES siempre.
    266          :param velocidad_maxima: Velocidad maxima en pixeles a la que se moverá el Actor.
    267          :param aceleracion: Indica lo rapido que acelera el actor hasta su velocidad máxima.
    268          :param deceleracion: Indica lo rapido que decelera el actor hasta parar.
    269          :param con_rotacion: Si deseas que el actor rote pulsando las teclas de izquierda y derecha.
    270          :param velocidad_rotacion: Indica lo rapido que rota un actor sobre si mismo.
    271          :param marcha_atras: Posibilidad de ir hacia atrás. (True o False)
    272          """
    273
    274          Habilidad.__init__(self, receptor)
    275          pilas.escena_actual().actualizar.conectar(self.on_key_press)
    276
    277          if control == None:
    278              self.control = self.receptor.escena.control
    279          else:
    280              self.control = control
    281
    282          self.direcciones = direcciones
    283
    284          self.velocidad = 0
    285          self.deceleracion = deceleracion
    286          self._velocidad_maxima = velocidad_maxima
    287          self._aceleracion = aceleracion
    288          self.con_rotacion = con_rotacion
    289          self.velocidad_rotacion = velocidad_rotacion
    290          self.marcha_atras = marcha_atras
    291
    292 -    def set_velocidad_maxima(self, velocidad):
    293          self._velocidad_maxima = velocidad
    294
    295 -    def get_velocidad_maxima(self):
    296          return self._velocidad_maxima
    297
    298 -    def get_aceleracion(self):
    299          return self._aceleracion
    300
    301 -    def set_aceleracion(self, aceleracion):
    302          self._aceleracion = aceleracion
    303
    304      velocidad_maxima = property(get_velocidad_maxima, set_velocidad_maxima, doc="Define la velocidad maxima.")
    305      aceleracion = property(get_aceleracion, set_aceleracion, doc="Define la acelaracion.")
    306
    307 -    def on_key_press(self, evento):
    308
    309          c = self.control
    310
    311          if self.con_rotacion:
    312
    313              if c.izquierda:
    314                  self.receptor.rotacion -= self.velocidad_rotacion * self.velocidad_maxima
    315              elif c.derecha:
    316                  self.receptor.rotacion += self.velocidad_rotacion * self.velocidad_maxima
    317
    318              if c.arriba:
    319                  self.avanzar(+1)
    320              elif c.abajo:
    321                  if self.marcha_atras:
    322                      self.avanzar(-1)
    323                  else:
    324                      self.decelerar()
    325              else:
    326                  self.decelerar()
    327
    328              rotacion_en_radianes = math.radians(-self.receptor.rotacion + 90)
    329              dx = math.cos(rotacion_en_radianes) * self.velocidad
    330              dy = math.sin(rotacion_en_radianes) * self.velocidad
    331              self.receptor.x += dx
    332              self.receptor.y += dy
    333
    334          else:
    335
    336              if self.direcciones == MoverseConElTeclado.OCHO_DIRECCIONES:
    337                  if c.izquierda:
    338                      self.receptor.x -= self.velocidad_maxima
    339                  elif c.derecha:
    340                      self.receptor.x += self.velocidad_maxima
    341
    342                  if c.arriba:
    343                      self.receptor.y += self.velocidad_maxima
    344                  elif c.abajo:
    345                      if self.marcha_atras:
    346                          self.receptor.y -= self.velocidad_maxima
    347              else:
    348                  if c.izquierda:
    349                      self.receptor.x -= self.velocidad_maxima
    350                  elif c.derecha:
    351                      self.receptor.x += self.velocidad_maxima
    352                  elif c.arriba:
    353                      self.receptor.y += self.velocidad_maxima
    354                  elif c.abajo:
    355                      if self.marcha_atras:
    356                          self.receptor.y -= self.velocidad_maxima
    357
    358 -    def decelerar(self):
    359          if self.velocidad > self.deceleracion:
    360              self.velocidad -= self.deceleracion
    361          elif self.velocidad < -self.deceleracion:
    362              self.velocidad += self.deceleracion
    363          else:
    364              self.velocidad = 0
    365
    366 -    def avanzar(self, delta):
    367          self.velocidad += self.aceleracion * delta
    368
    369          if self.velocidad > self.velocidad_maxima:
    370              self.velocidad = self.velocidad_maxima
    371          elif self.velocidad < - self.velocidad_maxima / 2:
    372              self.velocidad = - self.velocidad_maxima / 2
    373
    374
    375 -class MoverseComoCoche(MoverseConElTeclado):
    376      "Hace que un actor se mueva como un coche."
    377
    378 -    def __init__(self, receptor, control=None, velocidad_maxima=4,
    379                   aceleracion=0.06, deceleracion=0.1, rozamiento=0):
    380          MoverseConElTeclado.__init__(self, receptor,
    381                                       control=control,
    382                                       velocidad_maxima=velocidad_maxima,
    383                                       aceleracion=aceleracion,
    384                                       deceleracion=deceleracion,
    385                                       con_rotacion=True)
    386
    387          self._rozamiento = rozamiento
    388          self._velocidad_maxima_aux = self.velocidad_maxima
    389
    390 -    def set_rozamiento(self, nivel_rozamiento):
    391          self._rozamiento = nivel_rozamiento
    392          self.velocidad_maxima = self._velocidad_maxima_aux - self._rozamiento
    393
    394 -    def get_rozamiento(self):
    395          return self._rozamiento
    396
    397 -    def set_velocidad_maxima(self, velocidad):
    398          self._velocidad_maxima = velocidad
    399          self._velocidad_maxima_aux = self._velocidad_maxima
    400
    401 -    def get_velocidad_maxima(self):
    402          return self.velocidad_maxima
    403
    404      rozamiento = property(get_rozamiento, set_rozamiento, doc="Define el rozamiento del coche con la superficie por donde circula.")
    405
    406
    407 -class PuedeExplotar(Habilidad):
    408      "Hace que un actor se pueda hacer explotar invocando al metodo eliminar."
    409
    410 -    def __init__(self, receptor):
    411          Habilidad.__init__(self, receptor)
    412          receptor.eliminar = self.eliminar_y_explotar
    413
    414 -    def eliminar_y_explotar(self):
    415          explosion = pilas.actores.Explosion()
    416          explosion.x = self.receptor.x
    417          explosion.y = self.receptor.y
    418          explosion.escala = self.receptor.escala * 2
    419          pilas.actores.Actor.eliminar(self.receptor)
    420
    421 -class SiempreEnElCentro(Habilidad):
    422      """Hace que un actor siempre esté en el centro de la camara y la desplace
    423      cuando el actor se desplaza."""
    424
    425 -    def __init__(self, receptor):
    426          Habilidad.__init__(self, receptor)
    427
    428 -    def actualizar(self):
    429          pilas.escena_actual().camara.x = self.receptor.x
    430          pilas.escena_actual().camara.y = self.receptor.y
    431
    432
    433 -class SeMantieneEnPantalla(Habilidad):
    434      """Se asegura de que el actor regrese a la pantalla si sale o que no
    435      salga en nigún momento de la pantalla.
    436
    437      Si el actor sale por la derecha de la pantalla, entonces regresa
    438      por la izquiera. Si sale por arriba regresa por abajo y asi...
    439
    440      """
    441 -    def __init__(self, receptor, permitir_salida=True):
    442          """Inicializa la habilidad.
    443
    444          :param receptor: El actor que aprenderá la habilidad.
    445          :param permitir_salida: Valor booleano que establece si el actor puede salir por los lados de la ventana y regresar por el lado opuesto. Si se establece a False, el actor no puede salir de la ventana en ningún momento.
    446          """
    447          Habilidad.__init__(self, receptor)
    448          self.ancho, self.alto = pilas.mundo.motor.obtener_area()
    449          self.permitir_salida = permitir_salida
    450
    451 -    def actualizar(self):
    452          if self.permitir_salida :
    453              # Se asegura de regresar por izquierda y derecha.
    454              if self.receptor.derecha < -(self.ancho/2):
    455                  self.receptor.izquierda = (self.ancho/2)
    456              elif self.receptor.izquierda > (self.ancho/2):
    457                  self.receptor.derecha = -(self.ancho/2)
    458
    459              # Se asegura de regresar por arriba y abajo.
    460              if self.receptor.abajo > (self.alto/2):
    461                  self.receptor.arriba = -(self.alto/2)
    462              elif self.receptor.arriba < -(self.alto/2):
    463                  self.receptor.abajo = (self.alto/2)
    464          else:
    465              if self.receptor.izquierda <= -(self.ancho/2):
    466                  self.receptor.izquierda = -(self.ancho/2)
    467              elif self.receptor.derecha >=  (self.ancho/2):
    468                  self.receptor.derecha = self.ancho/2
    469
    470              if self.receptor.arriba > (self.alto/2):
    471                  self.receptor.arriba = (self.alto/2)
    472              elif self.receptor.abajo < -(self.alto/2):
    473                  self.receptor.abajo = -(self.alto/2)
    474
    475
    476 -class PisaPlataformas(Habilidad):
    477      """Enseña al actor a pisar plataformas físicas."""
    478
    479 -    def __init__(self, receptor):
    480          Habilidad.__init__(self, receptor)
    481          error = random.randint(-10, 10) / 10.0
    482          self.figura = pilas.fisica.fisica.crear_figura_cuadrado(receptor.x + error,
    483                                                                 receptor.y + error,
    484                                                                 receptor.radio_de_colision,
    485                                                                 masa=10,
    486                                                                 elasticidad=0,
    487                                                                 friccion=0)
    488          self.ultimo_x = receptor.x
    489          self.ultimo_y = receptor.y
    490
    491 -    def actualizar(self):
    492          # Mueve el objeto siempre y cuando no parezca que algo
    493          # no fisico (es decir de pymunk) lo ha afectado.
    494          self.receptor.x = self.figura.body.position.x
    495          self.receptor.y = self.figura.body.position.y
    496
    497 -    def eliminar(self):
    498          pilas.fisica.fisica.eliminar(self.figura)
    499
    500
    501 -class Imitar(Habilidad):
    502      "Logra que el actor imite las propiedades de otro."
    503
    504 -    def __init__(self, receptor, objeto_a_imitar, con_rotacion=True):
    505          """Inicializa la habilidad.
    506
    507          :param receptor: Referencia al actor.
    508          :param objeto_a_imitar: Cualquier objeto con atributos rotacion, x e y (por ejemplo otro actor).
    509          :param con_rotacion: Si debe imitar o no la rotación.
    510          """
    511          Habilidad.__init__(self, receptor)
    512          self.objeto_a_imitar = objeto_a_imitar
    513
    514          # Establecemos el mismo id para el actor y el objeto fisico
    515          # al que imita. Así luego en las colisiones fisicas sabremos a que
    516          # actor corresponde esa colisión.
    517          receptor.id = objeto_a_imitar.id
    518
    519          # Y nos guardamos una referencia al objeto físico al que imita.
    520          # Posterormente en las colisiones fisicas comprobaremos si el
    521          # objeto tiene el atributo "figura" para saber si estamos delante
    522          # de una figura fisica o no.
    523          receptor.figura = objeto_a_imitar
    524
    525          self.con_rotacion = con_rotacion
    526
    527 -    def actualizar(self):
    528          self.receptor.x = self.objeto_a_imitar.x
    529          self.receptor.y = self.objeto_a_imitar.y
    530          if (self.con_rotacion):
    531              self.receptor.rotacion = self.objeto_a_imitar.rotacion
    532
    533 -    def eliminar(self):
    534          if isinstance(self.objeto_a_imitar, pilas.fisica.Figura):
    535              self.objeto_a_imitar.eliminar()
    536
    537
    538 -class Disparar(Habilidad):
    539      """Establece la habilidad de poder disparar un Actor o un objeto de tipo
    540      pilas.municion.Municion."""
    541
    542 -    def __init__(self, receptor,
    543                   municion = pilas.actores.Bala,
    544                   parametros_municion = {},
    545                   grupo_enemigos=[],
    546                   cuando_elimina_enemigo=None,
    547                   frecuencia_de_disparo=10,
    548                   angulo_salida_disparo=0,
    549                   offset_disparo=(0,0),
    550                   offset_origen_actor=(0,0),
    551                   cuando_dispara=None,
    552                   escala=1):
    553          """
    554          Construye la habilidad.
    555
    556          :param municion: Municion o Actor que se disparará.
    557          :param grupo_enemigos: Actores que son considerados enemigos y con los que colisionará la munición disparada.
    558          :param cuando_elimina_enemigo: Método que será llamado cuando se produzca un impacto con un enemigo.
    559          :param frecuencia_de_disparo: El número de disparos por segundo que realizará.
    560          :param angulo_salida_disparo: Especifica el angulo por donde saldrá el disparo efectuado por el Actor.
    561          :param offset_disparo: Separación en pixeles (x,y) del disparo con respecto al centro del Actor.
    562          :param offset_origen_actor: Si el Actor no tiene su origen en el centro, con este parametro podremos colocar correctamente el disparo.
    563          :param cuando_dispara: Metodo que será llamado cuando se produzca un disparo.
    564          :param escala: Escala de los actores que serán disparados.
    565
    566          :example:
    567
    568          >>> mono = pilas.actores.Mono()
    569          >>> mono.aprender(pilas.habilidades.Disparar,
    570          >>>               municion=pilas.actores.proyectil.Bala,
    571          >>>               grupo_enemigos=enemigos,
    572          >>>               cuando_elimina_enemigo=eliminar_enemigo)
    573
    574          ..
    575          """
    576
    577          Habilidad.__init__(self, receptor)
    578          self.receptor = receptor
    579
    580          self._municion = municion
    581          self.parametros_municion = parametros_municion
    582
    583          self.offset_disparo_x = offset_disparo[0]
    584          self.offset_disparo_y = offset_disparo[1]
    585
    586          self.offset_origen_actor_x = offset_origen_actor[0]
    587          self.offset_origen_actor_y = offset_origen_actor[1]
    588
    589          self.angulo_salida_disparo = angulo_salida_disparo
    590          self.frecuencia_de_disparo = frecuencia_de_disparo
    591          self.contador_frecuencia_disparo = 0
    592          self.proyectiles = []
    593
    594          self.grupo_enemigos = grupo_enemigos
    595
    596          self.definir_colision(self.grupo_enemigos, cuando_elimina_enemigo)
    597
    598          self.cuando_dispara = cuando_dispara
    599
    600          self.escala = escala
    601
    602 -    def set_frecuencia_de_disparo(self, valor):
    603          self._frecuencia_de_disparo = 60 / valor
    604
    605 -    def get_frecuencia_de_disparo(self):
    606          return self._frecuencia_de_disparo
    607
    608 -    def set_municion(self, valor):
    609          self._municion = valor
    610          self.parametros_municion = {}
    611
    612 -    def get_municion(self):
    613          return self._municion
    614
    615      frecuencia_de_disparo = property(get_frecuencia_de_disparo, set_frecuencia_de_disparo, doc="Número de disparos por segundo.")
    616      municion = property(get_municion, set_municion, doc="Establece el tipo de municion que dispara.")
    617
    618 -    def definir_colision(self, grupo_enemigos, cuando_elimina_enemigo):
    619          self.grupo_enemigos = grupo_enemigos
    620          pilas.escena_actual().colisiones.agregar(self.proyectiles, self.grupo_enemigos,
    621                                                   cuando_elimina_enemigo)
    622 -    def actualizar(self):
    623          self.contador_frecuencia_disparo += 1
    624
    625          if self.pulsa_disparar():
    626              if self.contador_frecuencia_disparo > self._frecuencia_de_disparo:
    627                  self.contador_frecuencia_disparo = 0
    628                  self.disparar()
    629
    630          self._eliminar_disparos_innecesarios()
    631
    632 -    def _agregar_disparo(self, proyectil):
    633          proyectil.escala = self.escala
    634          self._desplazar_proyectil(proyectil, self.offset_disparo_x, self.offset_disparo_y)
    635          self.proyectiles.append(proyectil)
    636
    637 -    def _eliminar_disparos_innecesarios(self):
    638          for d in list(self.proyectiles):
    639              if d.esta_fuera_de_la_pantalla():
    640                  d.eliminar()
    641                  self.proyectiles.remove(d)
    642
    643 -    def _desplazar_proyectil(self, proyectil, offset_x, offset_y):
    644          rotacion_en_radianes = math.radians(-proyectil.rotacion)
    645          dx = math.cos(rotacion_en_radianes)
    646          dy = math.sin(rotacion_en_radianes)
    647
    648          proyectil.x += dx * offset_x
    649          proyectil.y += dy * offset_y
    650
    651 -    def disparar(self):
    652          if (self.receptor.espejado):
    653              offset_origen_actor_x = -self.offset_origen_actor_x
    654          else:
    655              offset_origen_actor_x = self.offset_origen_actor_x
    656
    657          if issubclass(self.municion, pilas.municion.Municion):
    658
    659              objeto_a_disparar = self.municion(**self.parametros_municion)
    660
    661              objeto_a_disparar.disparar(x=self.receptor.x+offset_origen_actor_x,
    662                                     y=self.receptor.y+self.offset_origen_actor_y,
    663                                     angulo_de_movimiento=self.receptor.rotacion + -(self.angulo_salida_disparo),
    664                                     rotacion=self.receptor.rotacion - 90,
    665                                     offset_disparo_x=self.offset_disparo_x,
    666                                     offset_disparo_y=self.offset_disparo_y)
    667
    668              for disparo in objeto_a_disparar.proyectiles:
    669                  self._agregar_disparo(disparo)
    670
    671          elif issubclass(self.municion, pilas.actores.Actor):
    672
    673              objeto_a_disparar = self.municion(x=self.receptor.x+offset_origen_actor_x,
    674                                                y=self.receptor.y+self.offset_origen_actor_y,
    675                                                rotacion=self.receptor.rotacion - 90,
    676                                                angulo_de_movimiento=self.receptor.rotacion + -(self.angulo_salida_disparo))
    677
    678              self._agregar_disparo(objeto_a_disparar)
    679
    680          else:
    681              raise "No se puede disparar este objeto."
    682
    683          if self.cuando_dispara:
    684              self.cuando_dispara()
    685
    686
    687 -    def eliminar(self):
    688          pass
    689
    690 -    def pulsa_disparar(self):
    691          return pilas.escena_actual().control.boton
    692
    693
    694 -class DispararConClick(Disparar):
    695      """Establece la habilidad de poder disparar un Actor o un objeto de tipo
    696      pilas.municion.Municion pulsando el boton izquierdo del ratón."""
    697
    698 -    def __init__(self, *k, **kv):
    699          super(DispararConClick, self).__init__(*k, **kv)
    700          self.boton_pulsado = False
    701          pilas.eventos.click_de_mouse.conectar(self.cuando_hace_click)
    702          pilas.eventos.termina_click.conectar(self.cuando_termina_click)
    703
    704 -    def cuando_hace_click(self, evento):
    705          if evento.boton == 1:
    706              self.boton_pulsado = True
    707
    708 -    def cuando_termina_click(self, evento):
    709          if evento.boton == 1:
    710              self.boton_pulsado = False
    711
    712 -    def pulsa_disparar(self):
    713          return self.boton_pulsado
    714