1. Sami Loone
  2. Fat x Fast

Source

Fat x Fast / FatxFast / tilemap / gamemap.py


# This file is part of FatxFast.
#
#    FatxFast 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, either version 3 of the License, or
#    (at your option) any later version.
#
#    FatxFast 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.
#
#    You should have received a copy of the GNU General Public License
#    along with FatxFast.  If not, see <http://www.gnu.org/licenses/>.

# Versioning based on: 
# http://en.wikipedia.org/wiki/Versioning#Designating_development_stage
__author__ = "dryatu (c) 2013"
__version__ = "1.2.4"

import pygame
from FatxFast.tilemap.editor import tilemap_editor 
from FatxFast.tilemap import tiledtmxloader, spawnarea
from FatxFast.tilemap.maze import maze
import FatxFast.camera as camera
from FatxFast.objects import entity, triggers
from FatxFast.fileio import LOGGER
from FatxFast.resource import resource_manager
from FatxFast.tilemap.editor.layer import (GROUND_LAYER, 
    OBJECT_LAYER, COLLIDE_LAYER, ROOF_LAYER)
from FatxFast.tilemap.editor import tile
import time

"""
Not in use but can be used if needed.

class MapRenderer(object):

    def __init__(self, layercount):
        self.camera_rect = None
        self.cache = []
        for idx in xrange(layercount):
            self.cache.append({})

    def set_camera_rect(self, rect):
        self.camera_rect = rect

    def render_layer(self, surface, layer):
        Blit the big surface of maze at a desired location.
        Defaults to the topleft corner of its rect
        xstart = TileMap.get_tile_xpos(self.camera_rect.x)
        ystart = TileMap.get_tile_ypos(self.camera_rect.y)
        xend = TileMap.get_tile_xpos(self.camera_rect.right)+1
        yend = TileMap.get_tile_ypos(self.camera_rect.bottom)+1
        surface.fill((0,0,0))
        if xstart < 0:
            xstart = 0
        if ystart < 0:
            ystart = 0
        if xend > len(layer.content2D[0]):
            xend = len(layer.content2D[0])
        if yend > len(layer.content2D):
            yend = len(layer.content2D)
        self.cache[layer._level]["start"] = (xstart,ystart)
        self.cache[layer._level]["end"] = (xend, yend)
        for x in xrange(xstart, xend):
            for y in xrange(ystart, yend):
                tile = layer.content2D[y][x]
                if tile:
                    surface.blit(tile.image,
                        (tile.rect.x-self.camera_rect.x, 
                            tile.rect.y-self.camera_rect.y))"""


class TileMap(object):
 
    def __init__(self, renderer=None):
        self.world = camera.CameraGroup()
        self.triggers = camera.CameraGroup()
        self.sprite_layers = []
        self._entity_types = {
            tile.NOTHING_ID: entity.GameEntity,
            triggers.COFFEE_ID: triggers.CoffeeTrigger,
            triggers.START_ID: triggers.StartTrigger,
            triggers.END_ID: triggers.EndTrigger,
            triggers.WARP_ID: triggers.WarpTrigger,
            spawnarea.SPAWNAREA_ID: spawnarea.SpawnArea}

        self.renderer = tiledtmxloader.helperspygame.RendererPygame()
        self.properties = {}
        self.spawnareas = camera.CameraGroup()

    def _create_entity(self, class_id, **kwargs): 
        init_object = class_id(**kwargs)
        self.world.add(init_object)
        return init_object

    def _create_object(self, obj, obj_class, **properties):
        func_name = "_create_"+str(obj.type)
        if hasattr(self, func_name):
            getattr(self, func_name)(obj_class, **properties)
        else:
            LOGGER.log_message(
                "Undefined object type {0} for object {1}.".format(
                    str(obj.type), properties.get("name", "Unnamed")))

    def _create_objects(self, **kwargs):
        objects = self.sprite_layers[OBJECT_LAYER].objects
        for obj in objects: 
            object_id = int(obj.properties.get("entity_id", 0))
            # If object of that id is not available jump to the next iter
            if object_id not in self._entity_types:
                continue
            else:
                obj_class = self._entity_types[object_id]
            if "save" in kwargs:
                self._load_saved_properties(obj, kwargs["save"])
            # object shouldn't carry its id around after creation.
            # removes possible conflicts with double kwargs
            if "entity_id" in obj.properties:
                del obj.properties["entity_id"]
            obj.properties["rect"] = pygame.Rect(
                obj.x, obj.y, obj.width, obj.height)
            
            self._create_object(obj, obj_class, **obj.properties)

    def _create_spawn(self, class_id, **kwargs):
        # Creates a spawn object. Entity_id IDs the spawnable objects
        init_object = self._entity_types[spawnarea.SPAWNAREA_ID](self.world, 
            **kwargs)
        init_object.add_entity_class(class_id)
        init_object.spawn_everything()
        self.spawnareas.add(init_object)
    
    def _create_trigger(self, class_id, **kwargs):
        self.triggers.add(self._create_entity(class_id, **kwargs))

    def draw(self, surface, camera):
        surface.fill((0,0,0))
        self.renderer.set_camera_rect(camera.rect)
        self.renderer.render_layer(surface, self.sprite_layers[GROUND_LAYER]) 
        self.draw_sprites(surface, camera)
        self.renderer.render_layer(surface, self.sprite_layers[ROOF_LAYER]) 

    def draw_map(self, surface, camera):
        """Blit the big surface of maze at a desired location.
        Defaults to the topleft corner of its rect"""
        self.renderer.set_camera_rect(camera.rect)
        for layer in self.sprite_layers:
            if layer.visible and not layer.is_object_group:
                self.renderer.render_layer(surface, layer)

    def draw_sprites(self, surface, camera):
        self.world.draw(surface, camera)

    @staticmethod
    def get_coord_position(tilepos):
        return (tilepos[0]*tile.TILEWIDTH, tilepos[1]*tile.TILEHEIGHT)

    def get_normalized_position(self, pos):
        return self.get_coord_position(self.get_tile_position(pos))

    def get_tile_position(self, coordpos):
        return (self.get_tile_xpos(coordpos[0]),self.get_tile_ypos(coordpos[1]))

    @staticmethod
    def get_tile_xpos(coordx):
        return int(coordx/tile.TILEWIDTH)

    @staticmethod
    def get_tile_ypos(coordy):
        return int(coordy/tile.TILEHEIGHT)

    def _load(self, tiled_map, **kwargs):
        self.width, self.height = tiled_map.width, tiled_map.height
        self.properties = tiled_map.properties
        self._create_objects(**kwargs)

    def load_file(self, filename, **kwargs):
        start = time.time()
        tiled_map = tiledtmxloader.tmxreader.TileMapParser().parse_decode(
            resource_manager.get_resource_path(filename))
        resources = tiledtmxloader.helperspygame.ResourceLoaderPygame()
        self.width, self.height = tiled_map.width, tiled_map.height
        resources.load(tiled_map)
        self.sprite_layers = tiledtmxloader.helperspygame.get_layers_from_map(
            resources)
        self._load(tiled_map, **kwargs)
        self.sprite_layers[GROUND_LAYER] = tiledtmxloader.helperspygame \
            .SpriteLayer.collapse(self.sprite_layers[GROUND_LAYER]) 
        if __debug__:
            print "Map {0} loaded in {1} seconds".format(
                tiled_map.map_file_name, time.time()-start)

    def load_generated(self, **kwargs):
        editor = tilemap_editor.WorldEditor()
        mazefier = maze.Mazefier(editor)
        mazefier.run(**kwargs)
        tiled_map = editor.export_map()
        self.sprite_layers = tiled_map.layers
        self._load(tiled_map, **kwargs)
        #self.renderer = MapRenderer(len(self.sprite_layers))

    def _load_saved_properties(self, obj, save):
        # Merge saved data to the object's properties - ID'd by obj_name
        obj_name = obj.properties.get("name")
        if not obj_name is None and obj_name in save.mapdata:
            obj.properties.update(save.mapdata[obj_name])

    def unload_map(self):
        for obj in self.world:
            obj.kill()
        for spawnarea in self.spawnareas:
            spawnarea.kill()

    def update(self, dt):
        self.spawnareas.update(dt)
        self.world.update(dt)