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

Source Code for Module pilas.utils

  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  from __future__ import division 
  9  import os 
 10  import interpolaciones 
 11  import sys 
 12  import subprocess 
 13  import math 
 14  import uuid 
 15  import pilas 
 16   
 17   
 18  PATH = os.path.dirname(os.path.abspath(__file__)) 
 19   
 20   
21 -def es_interpolacion(an_object):
22 """Indica si un objeto se comportará como una interpolación. 23 24 :param an_object: El objeto a consultar. 25 """ 26 return isinstance(an_object, interpolaciones.Interpolacion)
27 28
29 -def obtener_ruta_al_recurso(ruta):
30 """Busca la ruta a un archivo de recursos. 31 32 Los archivos de recursos (como las imagenes) se buscan en varios 33 directorios (ver docstring de image.load), así que esta 34 función intentará dar con el archivo en cuestión. 35 36 :param ruta: Ruta al archivo (recurso) a inspeccionar. 37 """ 38 39 dirs = ['./', os.path.dirname(sys.argv[0]), 'data', PATH, PATH + '/data'] 40 41 42 for x in dirs: 43 full_path = os.path.join(x, ruta) 44 #DEBUG: print "buscando en: '%s'" %(full_path) 45 46 if os.path.exists(full_path): 47 return full_path 48 49 # Si no ha encontrado el archivo lo reporta. 50 raise IOError("El archivo '%s' no existe." %(ruta))
51 52
53 -def esta_en_sesion_interactiva():
54 """Indica si pilas se ha ejecutado desde una consola interactiva de python.""" 55 import sys 56 try: 57 cursor = sys.ps1 58 return True 59 except AttributeError: 60 try: 61 in_ipython = sys.ipcompleter 62 return True 63 except AttributeError: 64 if sys.stdin.__class__.__module__.startswith("idle"): 65 return True 66 67 return False
68
69 -def distancia(a, b):
70 """Retorna la distancia entre dos numeros. 71 72 >>> distancia(30, 20) 73 10 74 75 :param a: Un valor numérico. 76 :param b: Un valor numérico. 77 """ 78 return abs(b - a)
79
80 -def distancia_entre_dos_puntos((x1, y1), (x2, y2)):
81 """Retorna la distancia entre dos puntos en dos dimensiones. 82 83 :param x1: Coordenada horizontal del primer punto. 84 :param y1: Coordenada vertical del primer punto. 85 :param x2: Coordenada horizontal del segundo punto. 86 :param y2: Coordenada vertical del segundo punto. 87 """ 88 return math.sqrt(distancia(x1, x2) ** 2 + distancia(y1, y2) ** 2)
89
90 -def distancia_entre_dos_actores(a, b):
91 """Retorna la distancia en pixels entre dos actores. 92 93 :param a: El primer actor. 94 :param b: El segundo actor. 95 """ 96 return distancia_entre_dos_puntos((a.x, a.y), (b.x, b.y))
97
98 -def actor_mas_cercano_al_actor(actor):
99 """Retorna el actor de la escena que esté mas cercano a otro indicado por parámetro. 100 101 :param actor: El actor tomado como referencia. 102 """ 103 actor_mas_cercano = None 104 distancia = 999999 105 for actor_cercano in pilas.escena_actual().actores: 106 if id(actor_cercano) != id(actor): 107 if distancia_entre_dos_actores(actor,actor_cercano) < distancia: 108 actor_mas_cercano = actor_cercano 109 110 return actor_mas_cercano
111
112 -def colisionan(a, b):
113 """Retorna True si dos actores estan en contacto. 114 115 :param a: Un actor. 116 :param b: El segundo actor a verificar. 117 """ 118 return distancia_entre_dos_actores(a, b) < a.radio_de_colision + b.radio_de_colision
119
120 -def interpolable(f):
121 """Decorador que se aplica a un metodo para que permita animaciones de interpolaciones. 122 123 Ejemplo:: 124 125 @interpolable 126 def set_x(self, valor_x): 127 [...] 128 129 :param f: Método sobre el que va a trabajar el interpolador. 130 """ 131 132 def inner(*args, **kwargs): 133 value = args[1] 134 135 # Si le indican dos argumentos, el primer sera 136 # el valor de la interpolacion y el segundo la 137 # velocidad. 138 if isinstance(value, tuple) and len(value) == 2: 139 duracion = value[1] 140 value = value[0] 141 else: 142 duracion = 1 143 144 if isinstance(value, list): 145 value = interpolar(value, duracion=duracion, tipo='lineal') 146 elif isinstance(value, xrange): 147 value = interpolar(list(value), duracion=duracion, tipo='lineal') 148 149 if es_interpolacion(value): 150 value.apply(args[0], function=f.__name__) 151 else: 152 f(args[0], value, **kwargs)
153 154 return inner 155
156 -def hacer_coordenada_mundo(x, y):
157 """Convierte una coordenada de pantalla a una coordenada dentro del motor de física. 158 159 :param x: Coordenada horizontal. 160 :param y: Coordenada vertical. 161 """ 162 dx, dy = pilas.mundo.motor.centro_fisico() 163 return (x + dx, dy - y)
164
165 -def hacer_coordenada_pantalla_absoluta(x, y):
166 # TODO: Duplicado del codigo anterior? 167 dx, dy = pilas.mundo.motor.centro_fisico() 168 return (x + dx, dy - y)
169
170 -def listar_actores_en_consola():
171 """Imprime una lista de todos los actores en la escena sobre la consola.""" 172 todos = pilas.escena_actual().actores 173 174 print "Hay %d actores en la escena:" %(len(todos)) 175 print "" 176 177 for s in todos: 178 print "\t", s 179 180 print ""
181
182 -def obtener_angulo_entre(punto_a, punto_b):
183 """Retorna el ángulo entro dos puntos de la pantalla. 184 185 :param punto_a: Una tupla con la coordenada del primer punto. 186 :param punto_b: Una tupla con la coordenada del segundo punto. 187 """ 188 (x, y) = punto_a 189 (x1, y1) = punto_b 190 return math.degrees(math.atan2(y1 - y, x1 -x))
191
192 -def convertir_de_posicion_relativa_a_fisica(x, y):
193 dx, dy = pilas.mundo.motor.centro_fisico() 194 return (x + dx, dy - y)
195
196 -def convertir_de_posicion_fisica_relativa(x, y):
197 dx, dy = pilas.mundo.motor.centro_fisico() 198 return (x - dx, dy - y)
199
200 -def calcular_tiempo_en_recorrer(distancia_en_pixeles, velocidad):
201 """Calcula el tiempo que se tardará en recorrer una distancia en 202 pixeles con una velocidad constante. 203 204 :param distancia_en_pixeles: La longitud a recorrer medida en pixels. 205 :param velocidad: La velocida medida en pixels. 206 """ 207 if (pilas.mundo.motor.canvas.fps.cuadros_por_segundo_numerico > 0): 208 return (distancia_en_pixeles / (pilas.mundo.motor.canvas.fps.cuadros_por_segundo_numerico * velocidad)) 209 else: 210 return 0
211
212 -def interpolar(valor_o_valores, duracion=1, demora=0, tipo='lineal'):
213 """Retorna un objeto que representa cambios de atributos progresivos. 214 215 El resultado de esta función se puede aplicar a varios atributos 216 de los actores, por ejemplo: 217 218 >>> bomba = pilas.actores.Bomba() 219 >>> bomba.escala = pilas.interpolar(3) 220 221 Esta función también admite otros parámetros cómo: 222 223 :param duracion: es la cantidad de segundos que demorará toda la interpolación. 224 :param demora: cuantos segundos se deben esperar antes de iniciar. 225 :param tipo: es el algoritmo de la interpolación, puede ser 'lineal'. 226 """ 227 228 import interpolaciones 229 230 algoritmos = { 231 'lineal': interpolaciones.Lineal, 232 'aceleracion_gradual': interpolaciones.AceleracionGradual, 233 'desaceleracion_gradual': interpolaciones.DesaceleracionGradual, 234 'rebote_inicial': interpolaciones.ReboteInicial, 235 'rebote_final': interpolaciones.ReboteFinal, 236 'elastico_inicial': interpolaciones.ElasticoInicial, 237 'elastico_final': interpolaciones.ElasticoFinal 238 } 239 240 if algoritmos.has_key(tipo): 241 clase = algoritmos[tipo] 242 else: 243 raise ValueError("El tipo de interpolacion %s es invalido" %(tipo)) 244 245 # Permite que los valores de interpolacion sean un numero o una lista. 246 if not isinstance(valor_o_valores, list): 247 valor_o_valores = [valor_o_valores] 248 249 return clase(valor_o_valores, duracion, demora)
250 251
252 -def deneter_interpolacion(objeto, propiedad):
253 """Deteiene una interpolación iniciada en un campo de un objeto. 254 255 >>> pilas.utils.deneter_interpolacion(actor, 'y') 256 257 :param objeto: Actor del que se desea detener al interpolacion. 258 :para propiedad: Cadena de texto que indica la propiedad del objeto cuya interpolación se desea terminar. 259 """ 260 setter = 'set_' + propiedad 261 try: 262 getattr(objeto, setter) 263 pilas.escena_actual().tweener.removeTweeningFromObjectField(objeto, setter) 264 except: 265 print "El obejto %s no tiene esa propiedad %s" %(objeto.__class__.__name__, setter)
266
267 -def obtener_area():
268 """Retorna el area que ocupa la ventana""" 269 return pilas.mundo.motor.obtener_area()
270
271 -def obtener_bordes():
272 """Retorna los bordes de la pantalla en forma de tupla.""" 273 ancho, alto = pilas.mundo.motor.obtener_area() 274 return -ancho/2, ancho/2, alto/2, -alto/2
275
276 -def obtener_area_de_texto(texto):
277 """Informa el ancho y alto que necesitara un texto para imprimirse. 278 279 :param texto: La cadena de texto que se quiere imprimir. 280 """ 281 return pilas.mundo.motor.obtener_area_de_texto(texto)
282
283 -def realizar_pruebas():
284 """Imprime pruebas en pantalla para detectar si pilas tiene todas las dependencias instaladas.""" 285 print "Realizando pruebas de dependencias:" 286 print "" 287 288 print "Box 2D:", 289 290 if pilas.fisica.obtener_version().startswith("2.1"): 291 print "OK, versión", pilas.fisica.obtener_version() 292 else: 293 print "Error -> la versión está obsoleta, instale una versión de la serie 2.1" 294 295 print "pyqt:", 296 297 try: 298 from PyQt4 import Qt 299 print "OK, versión", Qt.PYQT_VERSION_STR 300 except ImportError: 301 print "Error -> no se encuentra pyqt." 302 303 print "pyqt con aceleracion:", 304 305 try: 306 from PyQt4 import QtOpenGL 307 from PyQt4.QtOpenGL import QGLWidget 308 print "OK" 309 except ImportError: 310 print "Error -> no se encuentra pyqt4gl." 311 312 print "PIL para soporte de jpeg (opcional):", 313 314 try: 315 from PIL import Image 316 print "OK" 317 except ImportError: 318 print "Cuidado -> no se encuentra PIL."
319
320 -def ver_codigo(objeto, imprimir, retornar):
321 """Imprime en pantalla el codigo fuente asociado a un objeto. 322 323 :param objeto: El objeto que se quiere inspeccionar. 324 :param imprimir: Un valor True o False indicando si se quiere imprimir directamente sobre la pantalla. 325 :param retornar: Un valor True o False indicando si se quiere obtener el código como un string. 326 """ 327 import inspect 328 329 try: 330 codigo = inspect.getsource(objeto.__class__) 331 except TypeError: 332 codigo = inspect.getsource(objeto) 333 334 if imprimir: 335 print codigo 336 337 if retornar: 338 return codigo
339
340 -def obtener_uuid():
341 """Genera un identificador único.""" 342 return str(uuid.uuid4())
343
344 -def abrir_archivo_con_aplicacion_predeterminada(ruta_al_archivo):
345 """Intenta abrir un archivo con la herramienta recomenda por el sistema operativo. 346 347 :param ruta_al_archivo: La ruta al archivo que se quiere abrir. 348 """ 349 if sys.platform.startswith('darwin'): 350 subprocess.call(('open', ruta_al_archivo)) 351 elif os.name == 'nt': 352 os.startfile(ruta_al_archivo) 353 elif os.name == 'posix': 354 subprocess.call(('xdg-open', ruta_al_archivo))
355
356 -def centrar_ventana(widget):
357 """Coloca la ventana o widget directamente en el centro del escritorio. 358 359 :param widget: Widget que representa la ventana. 360 """ 361 from PyQt4 import QtGui 362 desktop = QtGui.QApplication.desktop() 363 widget.move(desktop.screen().rect().center() - widget.rect().center())
364
365 -def descargar_archivo_desde_internet(parent, url, archivo_destino):
366 """Inicia la descarga de una archivo desde Internet. 367 368 :param parent: El widget que será padre de la ventana. 369 :param url: La URL desde donde se descargará el archivo. 370 :param archivo_destino: La ruta en donde se guardará el archivo. 371 """ 372 import descargar 373 ventana = descargar.Descargar(parent, url, archivo_destino) 374 ventana.show()
375
376 -def imprimir_todos_los_eventos():
377 """Muestra en consola los eventos activos y a quienes invocan""" 378 import pilas 379 380 for x in dir(pilas.escena_actual()): 381 attributo = getattr(pilas.escena_actual(), x) 382 383 if isinstance(attributo, pilas.evento.Evento): 384 print "Evento:", attributo.nombre 385 attributo.imprimir_funciones_conectadas() 386 print ""
387
388 -def habilitar_depuracion():
389 """Permite habilitar un breakpoint para depuracion una vez inicializado pilas.""" 390 from PyQt4.QtCore import pyqtRemoveInputHook 391 from pdb import set_trace 392 pyqtRemoveInputHook() 393 set_trace()
394
395 -def mostrar_mensaje_de_error_y_salir(motivo):
396 """Muestra un mensaje de error y termina con la ejecución de pilas. 397 398 :param motivo: Un mensaje que explica el problema o la razón del cierre de pilas. 399 """ 400 from PyQt4 import QtGui 401 app = QtGui.QApplication(sys.argv[:1]) 402 app.setApplicationName("pilas-engine error") 403 main_window = QtGui.QMainWindow() 404 main_window.show() 405 main_window.raise_() 406 QtGui.QMessageBox.critical(main_window, "Error", motivo) 407 app.exit() 408 sys.exit(1)
409
410 -def obtener_archivo_a_ejecutar_desde_argv():
411 """Obtiene la ruta del archivo a ejecutar desde la linea de argumentos del programa.""" 412 import sys, copy 413 414 argv = copy.copy(sys.argv) 415 416 if '-i' in argv: 417 argv.remove('-i') 418 419 return " ".join(sys.argv[1:])
420