pilas.actores.mapatiled

Package pilas :: Package actores :: Module mapatiled |
[hide private]
[frames] | no frames]

# Source Code for Module pilas.actores.mapatiled

      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 pilas
     10  from pilas.actores import Mapa
     11  from xml.dom import minidom
     12
     13 -class MapaTiled(Mapa):
     14      """Representa mapas creados a partir de imagenes mas pequeñas.
     15
     16      Este actor te permite crear escenarios tipo ``tiles``, a partir
     17      de archivos .tmx, creados con el programa **tiled** (ver http://www.mapeditor.org).
     18
     19      Por ejemplo, para crear un mapa desde un archivo del programa
     20      **tiled** puedes escribir:
     21
     22          >>> mapa = pilas.actores.MapaTiled('untitled2.tmx')
     23
     24      Tiled trabaja con capas, así que cuando pilas carga las capas las interpreta
     25      de la siguiente manera:
     26
     27          - La capa 0 define los bloques no sólidos, generalmente fondos o decoración.
     28          - La capa 1 define bloques sólidos, útiles para hacer suelos o paredes.
     29          - Las siguientes capas solo se almacenan, pero no se dibujan. Se pueden acceder con ``mapa.capas``.
     30      """
     31
     32 -    def __init__(self, ruta_mapa, x=0, y=0, restitucion=0.56):
     33          ruta_mapa = pilas.utils.obtener_ruta_al_recurso(ruta_mapa)
     34          self._cargar_datos_basicos_del_mapa(ruta_mapa)
     35          Mapa.__init__(self, self.grilla, x=x, y=y, filas=self.filas, columnas=self.columnas)
     36          self._dibujar_mapa(ruta_mapa)
     37
     38 -    def cuadro_ancho(self):
     39          """Retorna el ancho de un bloque del mapa"""
     40          return self.ancho_cuadro
     41
     42 -    def cuadro_alto(self):
     43          """Retorna el alto de un bloque del mapa"""
     44          return self.alto_cuadro
     45
     46 -    def _cargar_datos_basicos_del_mapa(self, archivo):
     47          nodo = makeRootNode(archivo)
     48          nodo_mapa = nodo.getChild('map')
     49          nodo_tileset = nodo_mapa.getChild('tileset')
     50
     51          self.columnas = int(nodo_mapa.getAttributeValue('width'))
     52          self.filas = int(nodo_mapa.getAttributeValue('height'))
     53
     54          self.ancho_imagen = int(nodo_tileset.getChild('image').getAttributeValue('width'))
     55          self.alto_imagen = int(nodo_tileset.getChild('image').getAttributeValue('height'))
     56
     57          self.ancho_cuadro = int(nodo_tileset.getAttributeValue('tilewidth'))
     58          self.alto_cuadro = int(nodo_tileset.getAttributeValue('tileheight'))
     59
     60          self._ruta = nodo_tileset.getChild('image').getAttributeValue('source')
     61          self._ruta = pilas.utils.obtener_ruta_al_recurso(self._ruta)
     62
     63          self.grilla = pilas.imagenes.cargar_grilla(self._ruta,
     64                  self.ancho_imagen / self.ancho_cuadro,
     65                  self.alto_imagen / self.alto_cuadro)
     66
     67 -    def _dibujar_mapa(self, archivo):
     68          nodo = makeRootNode(archivo)
     69          layers = nodo.getChild('map').getChildren('layer')
     70
     71          if len(layers) == 0:
     72              raise Exception("Debe tener al menos una capa (layer).")
     73
     74          self.capas = {}
     75
     76          # La capa 0 (inferior) define los bloques no-solidos.
     77          bloques = self._pintar_bloques(layers[0], solidos=False)
     78          self.capas[0] = bloques
     79
     80          # La capa 1 define bloques solidos.
     81          if len(layers) > 1:
     82              bloques = self._pintar_bloques(layers[1], solidos=True)
     83              self.capas[1] = bloques
     84
     85          # El resto de las capas solo definen matrices para acceder mediante
     86          # el atributo 'capas', no se imprimen automaticamente.
     87          for (indice, layer) in enumerate(layers[2:]):
     88              self.capas[indice + 2] = self._convertir_capa_en_bloques_enteros(layer)
     89
     90 -    def _pintar_bloques(self, capa, solidos):
     91          """Genera actores que representan los bloques del escenario.
     92
     93          Retorna una lista de los bloques convertidos a numeros.
     94          """
     95
     96          # Convierte todo el mapa en una matriz de numeros.
     97          bloques = self._convertir_capa_en_bloques_enteros(capa)
     98
     99          for (y, fila) in enumerate(bloques):
    100              for (x, bloque) in enumerate(fila):
    101                  if bloque:
    102                      self.pintar_bloque(y, x, bloque -1, solidos)
    103
    104          return bloques
    105
    106 -    def _convertir_capa_en_bloques_enteros(self, capa):
    107          datos = capa.getChild('data').getData()
    108          return [[int(x) for x in x.split(',') if x] for x in datos.split()]
    109
    110
    111
    112 -class XmlNode:
    113      """Representa un nodo XML."""
    114
    115 -    def __init__(self, domElement):
    116          """Construstor del nodo desde un elemento dom.
    117
    118          :param domElement: Elemento de DOM a convertir.
    119          """
    120          self.elem = domElement
    121
    122 -    def getData(self):
    123          """Extrae datos desde un nodo del DOM."""
    124          for child in self.elem.childNodes:
    125              if child.nodeType == child.TEXT_NODE:
    126                  return str(child.data)
    127          return None
    128
    129 -    def getAttributeValue(self, name):
    130          """Returns the value of the attribute having the specified name."""
    131          return str(self.elem.attributes[name].value)
    132
    133 -    def getChild(self, tag):
    134          """Retorna el primer nodo hijo que contenga el tag especificado."""
    135          return XmlNode(self.elem.getElementsByTagName(tag)[0])
    136
    137 -    def getChildren(self, tag):
    138          """Retorna una lista de todos los nodos hijos que tienen el tag especificado."""
    139          return [XmlNode(x) for x in self.elem.getElementsByTagName(tag)]
    140
    141 -def makeRootNode(xmlFileName):
    142      """Genera un nodo XML dado un archivo.
    143
    144      :param xmlFileName: El nombre del archivo .xml"""
    145      return XmlNode(minidom.parse(xmlFileName))
    146