1
2
3
4
5
6
7
8
9 import pilas
10 from pilas import utils
11 from pilas.estudiante import Estudiante
12
13 IZQUIERDA = ["izquierda"]
14 DERECHA = ["derecha"]
15 ARRIBA = ["arriba", "superior"]
16 CENTRO = ["centro", "centrado", "medio", "arriba"]
17 ABAJO = ["abajo", "inferior", "debajo"]
18
19
20 -class Actor(object, Estudiante):
21 """Representa un objeto visible en pantalla, algo que se ve y tiene
22 posicion.
23
24 .. image:: images/actores/actor.png
25
26 Un objeto Actor se tiene que crear siempre indicando una imagen. Si no
27 se especifica una imagen, se verá una pila de color gris cómo la que
28 está mas arriba.
29
30 Una forma de crear el actor con una imagen es:
31
32 >>> protagonista = Actor("protagonista_de_frente.png")
33
34 incluso, es equivalente hacer lo siguiente:
35
36 >>> imagen = pilas.imagenes.cargar("protagonista_de_frente.png")
37 >>> protagonista = Actor(imagen)
38
39 Luego, una vez que ha sido ejecutada la sentencia aparecerá
40 el nuevo actor para que puedas manipularlo. Por ejemplo
41 alterando sus propiedades:
42
43 >>> protagonista.x = 100
44 >>> protagonista.escala = 2
45 >>> protagonista.rotacion = 30
46
47 Estas propiedades también se pueden manipular mediante
48 interpolaciones. Por ejemplo, para aumentar el tamaño del
49 personaje de 1 a 5 en 7 segundos:
50
51 >>> protagonista.escala = 1
52 >>> protagonista.escala = [5], 7
53
54 Si quieres que el actor sea invisible, un truco es crearlo
55 con la imagen ``invisible.png``:
56
57 >>> invisible = pilas.actores.Actor('invisible.png')
58 """
59
60 - def __init__(self, imagen="sin_imagen.png", x=0, y=0):
61 """ Constructor del Actor.
62
63 :param imagen: Ruta de la imagen del Actor.
64 :type imagen: string
65 :param x: Posición horizontal del Actor.
66 :type x: int
67 :param y: Posición vertical del Actor.
68 :type y: int
69 """
70
71 if not pilas.mundo:
72 mensaje = "Tiene que invocar a la funcion ``pilas.iniciar()`` " \
73 "para comenzar."
74 print mensaje
75 raise Exception(mensaje)
76
77 Estudiante.__init__(self)
78 self._actor = pilas.mundo.motor.obtener_actor(imagen, x=x, y=y)
79 self.centro = ('centro', 'centro')
80
81 self.id = ""
82
83 self.x = x
84 self.y = y
85 self.transparencia = 0
86
87
88 self.escena = None
89
90
91 self.z = 0
92 self._espejado = False
93 self.radio_de_colision = 10
94 pilas.actores.utils.insertar_como_nuevo_actor(self)
95 self._transparencia = 0
96 self.anexados = []
97 self._vivo = True
98
99
100 self._vx = 0
101 self._vy = 0
102 self._dx = self.x
103 self._dy = self.y
104
106 """ Define en que posición estará el centro del Actor.
107
108 Se puede definir la posición mediante unas coordenadas numéricas o
109 mediante texto.
110
111 La forma de definirlo mediante coordenadas numéricas seria así:
112
113 >>> mi_actor.definir_centro((10,50))
114
115 La otra forma de definirlo mediante texto sería:
116
117 >>> mi_actor.definir_centro(('centro','derecha'))
118
119 :param x: Coordenadas horizontal en la que se establecerá el centro del Actor.
120 :type x: int
121 :param y: Coordenadas vertical en la que se establecerá el centro del Actor.
122 :type y: int
123 """
124 if type(x) == str:
125 if x not in IZQUIERDA + CENTRO + DERECHA:
126 raise Exception("No puedes definir '%s' como eje horizontal." %(x))
127 x = self._interpretar_y_convertir_posicion(x, self.obtener_ancho())
128 if type(y) == str:
129 if y not in ARRIBA + CENTRO + ABAJO:
130 raise Exception("No puedes definir '%s' como eje vertical." %(y))
131 y = self._interpretar_y_convertir_posicion(y, self.obtener_alto())
132
133 self._centro = (x, y)
134 self._actor.definir_centro(x, y)
135
137 if posicion in IZQUIERDA + ARRIBA:
138 return 0
139 elif posicion in CENTRO:
140 return int(maximo_valor / 2.0)
141 elif posicion in DERECHA + ABAJO:
142 return maximo_valor
143 else:
144 raise Exception("El valor '%s' no corresponde a una posicion, use numeros o valores como 'izquierda', 'arriba' etc." %(posicion))
145
147 """ Obtiene las coordenadas del centro del Actor. """
148 return self._centro
149
150 centro = property(obtener_centro, definir_centro, doc="""
151 Cambia la posición del punto (x, y) dentro de actor.
152
153 Inicialmente, cuando tomamos un actor y definimos sus
154 atributos (x, y). Ese punto, será el que representa el centro
155 del personaje.
156
157 Eso hace que las rotaciones sean siempre sobre el centro
158 del personajes, igual que los cambios de escala y la posición.
159
160 En algunas ocasiones, queremos que el punto (x, y) sea otra
161 parte del actor. Por ejemplo sus pies. En esos casos
162 es útil definir el centro del actor.
163
164 Por ejemplo, si queremos mover el centro del actor podemos
165 usar sentencias cómo estas:
166
167 >>> actor.centro = ("izquierda", "abajo")
168 >>> actor.centro = ("centro", "arriba")
169
170 Pulsa la tecla **F8** para ver el centro del los actores
171 dentro de pilas. Es aconsejable pulsar la tecla **+** para
172 que el punto del modo **F8** se vea bien.
173 """)
174
176 """ Define la posición del Actor en el mundo.
177
178 :param x: Posición horizontal del Actor en el mundo.
179 :type x: int
180 :param y: Posición vertical del Actor en el mundo.
181 :type y: int
182 """
183 self._actor.definir_posicion(x, y)
184
186 """ Obtiene la posición del Actor en el mundo. """
187 return self._actor.obtener_posicion()
188
190 """ Metodo interno para el dibujado del Actor en pantalla. """
191 self._actor.dibujar(aplicacion)
192
196
197 @pilas.utils.interpolable
200
203
204 @pilas.utils.interpolable
208
209 @pilas.utils.interpolable
212
216
217 @pilas.utils.interpolable
219 if s < 0.001:
220 s = 0.001
221
222 ultima_escala = self.obtener_escala()
223
224
225
226
227
228
229 self.definir_escala(s)
230 self.radio_de_colision = (s * self.radio_de_colision) / max(ultima_escala, 0.0001)
231
232 @pilas.utils.interpolable
237
238 @pilas.utils.interpolable
243
246
248 return self._actor._escala_x
249
251 return self._actor._escala_y
252
255
256 @pilas.utils.interpolable
259
261 return self._espejado
262
264 if self._espejado != nuevo_valor:
265 self._espejado = nuevo_valor
266 self._actor.set_espejado(nuevo_valor)
267
268 @pilas.utils.interpolable
272
274 return self._transparencia
275
278
284
286 return self._actor.fijo
287
290
293
296
297 espejado = property(get_espejado, set_espejado, doc="Indica si se tiene que invertir horizonaltamente la imagen del actor.")
298 z = property(get_z, set_z, doc="Define lejania respecto del observador.")
299 x = property(get_x, set_x, doc="Define la posición horizontal.")
300 y = property(get_y, set_y, doc="Define la posición vertical.")
301 vx = property(get_vx, None, doc="Obtiene la velocidad horizontal del actor.")
302 vy = property(get_vy, None, doc="Obtiene la velocidad vertical del actor.")
303 rotacion = property(get_rotation, set_rotation, doc="Angulo de rotación (en grados, de 0 a 360)")
304 escala = property(get_scale, set_scale, doc="Escala de tamaño, 1 es normal, 2 al doble de tamaño etc...)")
305 escala_x = property(get_scale_x, set_scale_x, doc="Escala de tamaño horizontal, 1 es normal, 2 al doble de tamaño etc...)")
306 escala_y = property(get_scale_y, set_scale_y, doc="Escala de tamaño vertical, 1 es normal, 2 al doble de tamaño etc...)")
307 transparencia = property(get_transparencia, set_transparencia, doc="Define el nivel de transparencia, 0 indica opaco y 100 la maxima transparencia.")
308 imagen = property(get_imagen, set_imagen, doc="Define la imagen a mostrar.")
309 fijo = property(get_fijo, set_fijo, doc="Indica si el actor debe ser independiente a la camara.")
310
315
324
326 """Actualiza el estado del actor.
327
328 Este metodo se llama una vez por frame, y generalmente se suele
329 usar para implementar el comportamiento del actor.
330
331 Si estás haciendo una subclase de Actor, es aconsejable que re-definas
332 este método."""
333 pass
334
342
344 """ Calcula la velocidad horizontal y vertical del actor. """
345
346 if (self._dx != self.x):
347 self._vx = abs(self._dx - self.x)
348 self._dx = self.x
349 else:
350 self._vx = 0
351
352 if (self._dy != self.y):
353 self._vy = abs(self._dy - self.y)
354 self._dy = self.y
355 else:
356 self._vy = 0
357
359 """Compara dos actores para determinar cual esta mas cerca de la camara.
360
361 Este metodo se utiliza para ordenar los actores antes de imprimirlos
362 en pantalla. De modo tal que un usuario pueda seleccionar que
363 actores se ven mas arriba de otros cambiando los valores de
364 los atributos `z`."""
365
366 if otro_actor.z >= self.z:
367 return 1
368 else:
369 return -1
370
373
374 @pilas.utils.interpolable
377
378 izquierda = property(get_izquierda, set_izquierda, doc="Establece el " \
379 "espacio entre la izquierda del actor y el centro " \
380 "de coordenadas del mundo.")
381
384
385 @pilas.utils.interpolable
388
389 derecha = property(get_derecha, set_derecha, doc="Establece el " \
390 "espacio entre la derecha del actor y el centro " \
391 "de coordenadas del mundo.")
392
395
396 @pilas.utils.interpolable
399
400 abajo = property(get_abajo, set_abajo, doc="Establece el " \
401 "espacio entre la parte inferior del actor y el " \
402 "centro de coordenadas del mundo.")
403
406
407 @pilas.utils.interpolable
410
411 arriba = property(get_arriba, set_arriba, doc="Establece el " \
412 "espacio entre la parte superior del actor y el " \
413 "centro de coordenadas del mundo.")
414
416 """Determina si un punto colisiona con el area del actor.
417
418 Todos los actores tienen un area rectangular, pulsa la
419 tecla **F10** para ver el area de colision.
420
421 :param x: Posición horizontal del punto.
422 :type x: int
423 :param y: Posición vertical del punto.
424 :type y: int
425 """
426 return self.izquierda <= x <= self.derecha and self.abajo <= y <= self.arriba
427
429 """Determina la distancia con el ``otro_actor``
430
431 :param otro_actor: El otro actor para ver la distancia
432 :type otro_actor: pilas.actores.Actor
433
434 """
435 return utils.distancia_entre_dos_actores(self, otro_actor)
436
440
442 """Determina la distancia desde el centro del actor hasta el punto
443 determinado
444
445 Todos los actores tienen un area rectangular, pulsa la
446 tecla **F10** para ver el area de colision.
447
448 :param x: Posición horizontal del punto.
449 :type x: int
450 :param y: Posición vertical del punto.
451 :type y: int
452 """
453 return utils.distancia_entre_dos_puntos((self.x, self.y), (x, y))
454
456 """Determina si este actor colisiona con ``otro_actor``
457
458 :param otro_actor: El otro actor para verificar si colisiona.
459 :type otro_actor: pilas.actores.Actor
460
461 """
462 return utils.colisionan(self, otro_actor)
463
466
470
473
475 """ Obtinene la imagen del Actor. """
476 return self._actor.obtener_imagen()
477
479 """ Define la imagen del Actor y establece el centro del mismo a
480 ('centro,'centro').
481
482 :param imagen: Ruta de la imagen del Actor.
483 :type imagen: string
484 """
485 self._actor.definir_imagen(imagen)
486 self.centro = ('centro', 'centro')
487
489 """ Duplica un Actor.
490
491 :return: `Actor`.
492 """
493 duplicado = self.__class__()
494
495 for clave in kv:
496 setattr(duplicado, clave, kv[clave])
497
498 return duplicado
499
502
505
506 ancho = property(obtener_ancho, doc="Obtiene el ancho del Actor.")
507 alto = property(obtener_alto, doc="Obtiene el alto del Actor.")
508
510 if type(cantidad) is not int or cantidad < 1:
511 raise TypeError("Solo puede multiplicar por numeros enteros " \
512 "mayores a 1.")
513
514 grupo = pilas.atajos.fabricar(self.__class__, cantidad - 1)
515 grupo.append(self)
516 return grupo
517
519 return "<%s en (%d, %d)>" % (self.__class__.__name__, self.x, self.y)
520
523
526
529
530 - def imitar(self, otro_actor_o_figura):
531 """ Hace que un Actor copie la posición y la rotación de otro Actor o
532 Figura fisica.
533
534 Por ejemplo:
535
536 >>> circulo_dinamico = pilas.fisica.Circulo(10, 200, 50)
537 >>> mi_actor.imitar(circulo_dinamico)
538
539 :param otro_actor_o_figura: Actor o Figura física a imitar.
540 :type otro_actor_o_figura: `Actor`, `Figura`
541 """
542 self.aprender(pilas.habilidades.Imitar, otro_actor_o_figura)
543
544 - def decir(self, mensaje, autoeliminar=True):
545 """Emite un mensaje usando un globo similar al de los comics.
546
547 :param mensaje: Texto a mostrar en el mensaje.
548 :type mensaje: string
549 :param autoeliminar: Establece si se eliminará el globo al cabo de unos segundos.
550 :type autoeliminar: boolean
551 """
552 nuevo_actor = pilas.actores.Globo(mensaje, self.x, self.y, autoeliminar=autoeliminar)
553 nuevo_actor.aprender(pilas.habilidades.Imitar, self, False)
554 nuevo_actor.z = self.z - 1
555 self.anexar(nuevo_actor)
556 pilas.atajos.leer(mensaje)
557
558 - def anexar(self, otro_actor):
559 """ Agrega un Actor a la lista de actores anexados al Actor actual.
560 Cuando se elimina un Actor, se eliminan los actores anexados.
561
562 :param otro_actor: Actor a anexar.
563 :type otro_actor: `Actor`
564 """
565 self.anexados.append(otro_actor)
566
570
579
581 """ Comprueba si el actor es un fondo del juego.
582
583 :return: boolean"""
584 return False
585