Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: 'Tiled' Tile-map Loader  (Read 202179 times)

0 Members and 5 Guests are viewing this topic.

Walker

  • Full Member
  • ***
  • Posts: 181
    • View Profile
'Tiled' Tile-map Loader
« on: August 16, 2010, 09:23:55 am »
Hi guys, I've been using the Tiled (http://www.mapeditor.org/) map format in a game I've been working on and thought I would share the love around.

I've basically rewritten it, as I was using it with Box2D. This new version is more general purpose.

It should work with any size level you throw at it. You can have as many tile layers as you want (and transparency works).

Any objects you place in the editor will be picked up and stored and can be accessed.

You should be able to get going just from looking at the header file and reading the README.txt.

Download: https://sourceforge.net/projects/tiledsfmlloader/files/TiledMapLoader0.1.zip/download

Note that I'm not affiliated with Tiled or it's author.

Suggestions, bug reports etc are more than welcome!

Don't forget to read the README.txt!!!

Elgan

  • Jr. Member
  • **
  • Posts: 77
    • AOL Instant Messenger - Flat+1,+17+st+Cl
    • View Profile
'Tiled' Tile-map Loader
« Reply #1 on: December 18, 2011, 09:37:35 pm »
Really great work thank you! :)

I just wanted to say, I extended it a little bit to support multiple tilesets, and properties for  layers, tiles and objects.

NOTE: this could probably be done a bit more "pro", as I used this to teach myself c++. I could not quite get templates working, so get properties methods are pretty much copied, for each object.

its still in a long thread and still only supports XML. (I like to be able to manually read the maps anyway)

--I removed some stuff that's useless TO ME,

and I am about to change it to just render a single background, (no tiles), (I KNOW??) so it will be faster for me. So I have not finished playing with it, posting as before I edit it for me, (which would make it useless for others).

I don't plan on using objects for collision, but might.  

I think in tild you can do object layers? I don't have support for that? just same as above, objects...

be glad to see further feedback.

no idea about uploading, so ill just post code, sorry.
Compare with above for feature sets.

I mainly just use tiles to get info, ...ie......map.getproperyat(layer, x, y).  ...I can then find certain things on maps...

getobjectat(x,y)

also reworked the objects , as not all objects have width, height.


apart from other optimizations..things to do.

somehow work out how to link or make a list of the objects which point to their objects in the multi
  • [y] layer. So easier to loop through...
Code: [Select]
/*********************************************************************
Quinn Schwab
16/08/2010

SFML Tiled Map Loader

The zlib license has been used to make this software fully compatible
with SFML. See http://www.sfml-dev.org/license.php

This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented;
   you must not claim that you wrote the original software.
   If you use this software in a product, an acknowledgment
   in the product documentation would be appreciated but
   is not required.

2. Altered source versions must be plainly marked as such,
   and must not be misrepresented as being the original software.

3. This notice may not be removed or altered from any
   source distribution.
*********************************************************************/

#ifndef MAP_H
#define Map_H

#include <string>
#include <vector>
#include <map>
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>



//Object class. Everything is kept public in case you want to get a different type to the supported ones.
//Also you will be able to modify things. For example doors/changing walls etc (Just give the door a static type and a unique name)
//Kept in same files as Map just for convenience. (only have to add two files to your project)
class Object{
    public:
        int GetPropertyInt(std::string name);
        float GetPropertyFloat(std::string name);
        std::string GetPropertyString(std::string name);

        std::string name;
        std::string type;
        sf::Rect <int> rect;
//All properties of the object. Values are stored as strings and mapped by strings(names provided in editor).
        std::map <std::string, std::string> properties;
};

class TileSet{
public:
int GetPropertyInt(std::string name);
float GetPropertyFloat(std::string name);
std::string GetPropertyString(std::string name);

int rows;
int columns;
int firstTileID;

sf::String name;
std::string ImgSource;

    //The tileset image.
    sf::Image TilesetImage;

int width;
int height;
int tileHeight;
int tileWidth;
int spacing;
int margin;

std::map <std::string, std::string> properties;//All properties of the object. Values are stored as strings and mapped by strings(names provided in editor).
};

class Tile{
public:
int GetPropertyInt(std::string name);
float GetPropertyFloat(std::string name);
std::string GetPropertyString(std::string name);

bool drawable;

//the id in the tileset
int tilesettileid;

sf::Vector2i position;
sf::Vector2f coords;

sf::Sprite sprite;
int id;
TileSet *tileset;

//All properties of the object. Values are stored as strings and mapped by strings(names provided in editor).
    std::map <std::string, std::string> properties;
};

class Layer{
public:
int GetPropertyInt(std::string name);
float GetPropertyFloat(std::string name);
std::string GetPropertyString(std::string name);

int rows;
int columns;

std::map <int , std::map <int , Tile> > XYTiles;

std::map <int , Tile > YTiles;

std::vector <Tile> tiles;

int visible;
    int opacity;
 
    std::map <std::string, std::string> properties;//All properties of the object. Values are stored as strings and mapped by strings(names provided in editor).
};

typedef std::map <int, TileSet> Tilesets;

class Map
{
    public:
        Map();
        virtual ~Map();
        //Loads the map. Returns false if it fails.
        bool LoadFromFile(std::string filename);
        //Returns true if the given tile is solid.
        bool IsSolidTile(int x, int y);
        //Set the area to draw. This rect is usually provided directly from the view you are using.
        void SetDrawingBounds(sf::Rect<float> bounds);
        //Draws the map to the provided window.
        void Draw(sf::RenderWindow &window);

//Width(tiles), height(tiles), tile width(pixels), tile height(pixels) of the map.
        int width, height, tileWidth, tileHeight;
int rows;
int columns;

std::string GetTilePropertyStringAt(int layer, int x, int y, std::string );
float GetTilePropertyFloatAt(int layer, int x, int y, std::string );
int GetTilePropertyIntAt(int layer, int x, int y, std::string );

std::string GetObjectPropertyStringAt(int x, int y,std::string name);
float GetObjectPropertyFloatAt( int x, int y, std::string name);
int GetObjectPropertyIntAt(int x, int y, std::string name);

    private:
bool GetTileSetFromGID(int tileGid, Tile &Tile);

        //Used to offset the t  ile number.
        int firstTileID;

        //Used to clip anything off screen.
        sf::Rect <float> drawingBounds;
sf::Image TilesetImage;

        //This stores all the solid areas (objects with type 'solid'). This gets checked by the IsSolid function.
        std::vector <sf::Rect <int> > solidObjects;


        //This stores all objects (including 'solid' types)
//        std::vector <Object> objects;
std::map <int , std::map <int , Object> > XYObjects;

        //This stores each layer of sprites/tiles so they can be drawn in order.
        std::vector <Layer> layers;
//tilesets
        //std::vector <TileSet> TileSets;
Tilesets m_Tilesets;
};
#endif // Map_H


Code: [Select]
/*********************************************************************
Quinn Schwab
16/08/2010

SFML Tiled Map Loader

The zlib license has been used to make this software fully compatible
with SFML. See http://www.sfml-dev.org/license.php

This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented;
   you must not claim that you wrote the original software.
   If you use this software in a product, an acknowledgment
   in the product documentation would be appreciated but
   is not required.

2. Altered source versions must be plainly marked as such,
   and must not be misrepresented as being the original software.

3. This notice may not be removed or altered from any
   source distribution.
*********************************************************************/

#include "MapLoader.h"
#include <iostream>
#include "tinyxml/tinyxml.h"


std::string Map::GetTilePropertyStringAt(int layer, int x, int y, std::string name)
{
return layers[layer].XYTiles[x][y].GetPropertyString(name);
}


float Map::GetTilePropertyFloatAt(int layer, int x, int y, std::string name)
{
return layers[layer].XYTiles[x][y].GetPropertyFloat(name);
}

int Map::GetTilePropertyIntAt(int layer, int x, int y, std::string name)
{
return layers[layer].XYTiles[x][y].GetPropertyInt(name);
}



std::string Map::GetObjectPropertyStringAt(int x, int y, std::string name)
{
return XYObjects[x][y].GetPropertyString(name);
}

float Map::GetObjectPropertyFloatAt(int x, int y, std::string name)
{
return XYObjects[x][y].GetPropertyFloat(name);
}

int Map::GetObjectPropertyIntAt(int x, int y, std::string name)
{
return XYObjects[x][y].GetPropertyInt(name);
}


int Object::GetPropertyInt(std::string name)
{
    int i;
    i = atoi(properties[name].c_str());
    return i;
}

float Object::GetPropertyFloat(std::string name)
{
    float f;
    f = (float)strtod(properties[name].c_str(), NULL);

    return f;
}

std::string Object::GetPropertyString(std::string name)
{
    return properties[name];
}


int Layer::GetPropertyInt(std::string name)
{
    int i;
    i = atoi(properties[name].c_str());

    return i;
}

float Layer::GetPropertyFloat(std::string name)
{
    float f;
    f = (float)strtod(properties[name].c_str(), NULL);

    return f;
}

std::string Layer::GetPropertyString(std::string name)
{
    return properties[name];
}


int Tile::GetPropertyInt(std::string name)
{
    int i;
    i = atoi(properties[name].c_str());

    return i;
}

float Tile::GetPropertyFloat(std::string name)
{
    float f;
    f = (float)strtod(properties[name].c_str(), NULL);
    return f;
}

std::string Tile::GetPropertyString(std::string name)
{
    return properties[name];
}


int TileSet::GetPropertyInt(std::string name)
{
    int i;
    i = atoi(properties[name].c_str());

    return i;
}

float TileSet::GetPropertyFloat(std::string name)
{
    float f;
    f = (float)strtod(properties[name].c_str(), NULL);

    return f;
}

std::string TileSet::GetPropertyString(std::string name)
{
    return properties[name];
}

Map::Map()
{
    //ctor
}

Map::~Map()
{
    //dtor
}

bool Map::LoadFromFile(std::string filename)
{
    TiXmlDocument MapFile(filename.c_str());

    if (!MapFile.LoadFile())
    {
        std::cout << "Loading Map \"" << filename << "\" failed." << std::endl;
        return false;
    }

    //Map element. This is the root element for the whole file.
    TiXmlElement *map;
    map = MapFile.FirstChildElement("map");

    //Set up misc map properties.
    width = atoi(map->Attribute("width"));
    height = atoi(map->Attribute("height"));
    tileWidth = atoi(map->Attribute("tilewidth"));
    tileHeight = atoi(map->Attribute("tileheight"));

columns = width / tileWidth;
rows = height / tileHeight;


    //Tileset stuff
    TiXmlElement *tilesetElement;
tilesetElement = map->FirstChildElement("tileset");

//while we want tilesets
    while(tilesetElement)
    {
TileSet TileSet;

TileSet.firstTileID = atoi(tilesetElement->Attribute("firstgid"));

//Tileset image
TiXmlElement *image;
image = tilesetElement->FirstChildElement("image");
TileSet.ImgSource = image->Attribute("source");

if (!TileSet.TilesetImage.LoadFromFile(TileSet.ImgSource))//Load the tileset image
{
std::cout << "Failed to load tile sheet." << std::endl;
return false;
}

TileSet.TilesetImage.CreateMaskFromColor(sf::Color(255, 0, 255));
TileSet.TilesetImage.SetSmooth(false);

        if (tilesetElement->Attribute("spacing") != NULL)
        {
            TileSet.spacing = atoi(tilesetElement->Attribute("spacing"));            
        }
        else
        {
            TileSet.spacing = 0;
        }

        if (tilesetElement->Attribute("margin") != NULL)
        {
            TileSet.margin = atoi(tilesetElement->Attribute("margin"));            
        }
        else
        {
            TileSet.margin = 0;
        }

        if (tilesetElement->Attribute("tilewidth") != NULL)
        {
            TileSet.tileWidth = atoi(tilesetElement->Attribute("tilewidth"));            
        }
        else
        {
            TileSet.tileWidth = 0;
        }
        if (tilesetElement->Attribute("tileheight") != NULL)
        {
            TileSet.tileHeight = atoi(tilesetElement->Attribute("tileheight"));            
        }
        else
        {
            TileSet.tileHeight = 0;
        }

//Columns and rows (of tileset image)
TileSet.width = TileSet.TilesetImage.GetWidth();
TileSet.height = TileSet.TilesetImage.GetHeight();
TileSet.columns = TileSet.width / TileSet.tileWidth;
TileSet.rows = TileSet.height / TileSet.tileHeight;

//do layer properties
TiXmlElement *properties;
properties = tilesetElement->FirstChildElement("properties");
if (properties != NULL)
{
TiXmlElement *prop;
prop = properties->FirstChildElement("property");
if (prop != NULL)
{
while(prop)
{
std::string propertyName = prop->Attribute("name");
std::string propertyValue = prop->Attribute("value");

TileSet.properties[propertyName] = propertyValue;

prop = prop->NextSiblingElement("property");
}
}
}

   tilesetElement = tilesetElement->NextSiblingElement("tileset");

//set by tile first id
m_Tilesets[TileSet.firstTileID] = TileSet;

}












    //Layers
    TiXmlElement *layerElement;
    layerElement = map->FirstChildElement("layer");
    while (layerElement)
    {
        Layer layer;
        if (layerElement->Attribute("opacity") != NULL)//check if opacity attribute exists
        {
            float opacity = (int)strtod(layerElement->Attribute("opacity"), NULL);//convert the (string) opacity element to float
            layer.opacity = 255 * opacity;
        }
        else
        {
            layer.opacity = 255;//if the attribute doesnt exist, default to full opacity
        }

//is visible
        if (layerElement->Attribute("visible") != NULL)
        {
layer.visible = atoi(layerElement->Attribute("opacity"));
        }
        else
        {
            layer.visible = 1;
        }

        //Tiles
        TiXmlElement *layerDataElement;
        layerDataElement = layerElement->FirstChildElement("data");

        if (layerDataElement == NULL)
        {
            std::cout << "Bad map. No layer information found." << std::endl;
        }

        TiXmlElement *tileElement;
        tileElement = layerDataElement->FirstChildElement("tile");

        if (tileElement == NULL)
        {
            std::cout << "Bad map. No tile information found." << std::endl;
            return false;
        }

        int x = 0;
        int y = 0;

bool GotTileSet = false;

        while (tileElement)
        {
            int tileGID = atoi(tileElement->Attribute("gid"));            

Tile CurrentTile;
sf::Rect <int> rect;

CurrentTile.id = tileGID;

if(!GotTileSet)
{
GotTileSet = GetTileSetFromGID(tileGID, CurrentTile);
if(!GotTileSet)
{
std::cout << "Could not find tileset for tile." << std::endl;
return false;
}

//get the layers rows, They should really match the tileset.
//unless someone used half size tileset..EEK? but I won so I'm not worried! ha
layer.rows = CurrentTile.tileset->rows;
layer.columns = CurrentTile.tileset->columns;

}


//Work out the subrect ID to 'chop up' the tilesheet image.
CurrentTile.tilesettileid = tileGID - CurrentTile.tileset->firstTileID;

if(CurrentTile.tilesettileid >= 0)//we only need to (and only can) create a sprite/tile if there is one to display
            {
CurrentTile.drawable = true;

CurrentTile.sprite.SetImage(CurrentTile.tileset->TilesetImage);

rect.Top = y * CurrentTile.tileset->tileHeight;
rect.Bottom = y * CurrentTile.tileset->tileHeight + CurrentTile.tileset->tileHeight;
rect.Left = x * CurrentTile.tileset->tileWidth;
rect.Right = x * CurrentTile.tileset->tileWidth + CurrentTile.tileset->tileWidth;

CurrentTile.sprite.SetSubRect( rect );
CurrentTile.sprite.SetPosition(x * CurrentTile.tileset->tileWidth, y * CurrentTile.tileset->tileHeight);

CurrentTile.sprite.SetColor(sf::Color(255, 255, 255, layer.opacity));//Set opacity of the tile.

            }
else
            {
CurrentTile.drawable = false;
}


//set the position
sf::Vector2i position;
position.x = x;
position.y = x;
CurrentTile.position = position;


sf::Vector2f coords;
coords.x = x * CurrentTile.tileset->tileWidth;
coords.y = x * CurrentTile.tileset->tileHeight;
CurrentTile.coords = coords;

//do tiles properties
            TiXmlElement *properties;
            properties = tileElement->FirstChildElement("properties");
            if(properties != NULL)
            {
                TiXmlElement *prop;
                prop = properties->FirstChildElement("property");
                if(prop != NULL)
                {
                    while(prop)
                    {
                        std::string propertyName = prop->Attribute("name");
                        std::string propertyValue = prop->Attribute("value");

                        CurrentTile.properties[propertyName] = propertyValue;

                        prop = prop->NextSiblingElement("property");
                    }
                }
            }

//Link tile x, y to this tile

layer.XYTiles[x].insert(std::pair<int, Tile>(y, CurrentTile));

            //add tile to layer
           // layer.tiles.push_back(layer.XYTiles);
     
            tileElement = tileElement->NextSiblingElement("tile");

            //increment x, y
            x++;
            if (x >= width)//if x has "hit" the end (right) of the map, reset it to the start (left)
            {
                x = 0;
                y++;
                if (y >= height)
                {
                    y = 0;
                }
            }
        }


//do layer properties
TiXmlElement *properties;
properties = layerElement->FirstChildElement("properties");
if (properties != NULL)
{
TiXmlElement *prop;
prop = properties->FirstChildElement("property");
if (prop != NULL)
{
while(prop)
{
std::string propertyName = prop->Attribute("name");
std::string propertyValue = prop->Attribute("value");

layer.properties[propertyName] = propertyValue;

prop = prop->NextSiblingElement("property");
}
}
}

layers.push_back(layer);

        layerElement = layerElement->NextSiblingElement("layer");
    }








    //Objects
    TiXmlElement *objectGroupElement;
    if (map->FirstChildElement("objectgroup") != NULL)//Check that there is atleast one object layer
    {
        objectGroupElement = map->FirstChildElement("objectgroup");
        while (objectGroupElement)//loop through object layers
        {
            TiXmlElement *objectElement;
            objectElement = objectGroupElement->FirstChildElement("object");
            while (objectElement)//loop through objects
            {
                std::string objectType;
int width = 0;
int height = 0;

                if (objectElement->Attribute("type") != NULL)
                {
                    objectType = objectElement->Attribute("type");
                }
                std::string objectName;
                if (objectElement->Attribute("name") != NULL)
                {
                    objectName = objectElement->Attribute("name");
                }
                int x = atoi(objectElement->Attribute("x"));
                int y = atoi(objectElement->Attribute("y"));

                if (objectElement->Attribute("width") != NULL)
                {
                    width = atoi(objectElement->Attribute("width"));
                }
                if (objectElement->Attribute("height") != NULL)
                {
                    height = atoi(objectElement->Attribute("height"));
                }

                Object object;
                object.name = objectName;
                object.type = objectType;

                sf::Rect <int> objectRect;
                objectRect.Top = y;
                objectRect.Left = x;
                objectRect.Bottom = y + height;
                objectRect.Right = x + width;

x = x / tileWidth;
y = y / tileHeight;

                if (objectType == "solid")
                {
                    solidObjects.push_back(objectRect);
                }

                object.rect = objectRect;

                TiXmlElement *properties;
                properties = objectElement->FirstChildElement("properties");
                if (properties != NULL)
                {
                    TiXmlElement *prop;
                    prop = properties->FirstChildElement("property");
                    if (prop != NULL)
                    {
                        while(prop)
                        {
                            std::string propertyName = prop->Attribute("name");
                            std::string propertyValue = prop->Attribute("value");

                            object.properties[propertyName] = propertyValue;

                            prop = prop->NextSiblingElement("property");
                        }
                    }
                }

//                objects.push_back(object);

XYObjects[x][y] = object;

                objectElement = objectElement->NextSiblingElement("object");
            }
            objectGroupElement = objectGroupElement->NextSiblingElement("objectgroup");
        }
    }
    else
    {
        std::cout << "No object layers found..." << std::endl;
    }

    return true;
}


void Map::SetDrawingBounds(sf::Rect<float> bounds)
{
    drawingBounds = bounds;

    //Adjust the rect so that tiles are drawn just off screen, so you don't see them disappearing.
    drawingBounds.Top -= tileHeight;
    drawingBounds.Left -= tileWidth;
}




bool Map::GetTileSetFromGID(int tileGid, Tile &Tile)
{
//sort the tile sets by their first id
//std::sort(TileSets.begin(), TileSets.end(), comp_hungarian_strings);

//Tilesets, loop through and find
// if the ID (I) if bigger than tilegid, its not the one we want.
// if its lower, its the first lowest.

Tilesets::reverse_iterator iter;
for ( iter = m_Tilesets.rbegin();
      iter != m_Tilesets.rend(); iter++)  
{
//if the tileset ID is bigger
if(iter->first > tileGid)
{
continue;
}

//this is the highest ID, lower than our ID

Tile.tileset = &m_Tilesets[1];
return true;
}

return false;
}


void Map::Draw(sf::RenderWindow &window)
{
    for (int layer = 0; layer < layers.size(); layer++)
    {
for (int x = 0; x < layers[layer].columns; x++)
{
for (int y = 0; y < layers[layer].rows; y++)
{
window.Draw(layers[layer].XYTiles[x][y].sprite);
}
}
    }
return;
/*
for (int x = 0; x < layers[layer].columns; x++)
{
for (int y = 0; y < layers[layer].rows; y++)
{
std::map <int , std::map <int , Tile> >::iterator XTile;
std::map <int , Tile>::const_iterator YTile;

XTile = layers[layer].XYTiles.find(x);

window.Draw(YTile->second.sprite);
}
}

std::map <int , std::map <int , Tile> >::const_iterator iter;
for ( iter = layers[layer].XYTiles.begin(); iter != layers[layer].XYTiles.end(); iter++)  
{
std::map <int , Tile>::const_iterator tilesy;
for (tilesy = iter->second.begin(); tilesy != iter->second.end(); tilesy++)  
{
window.Draw(tilesy->second.sprite);
}
}

for (int tile = 0; tile < layers[layer].tiles.size(); tile++)
        {
           // if( drawingBounds.Contains(layers[layer].tiles[tile].position.x, layers[layer].tiles[tile].position.y) )
            {
if(layers[layer].tiles[tile].drawable)
{
window.Draw(layers[layer].tiles[tile].sprite);
}
            }
        }
*/
sf::Sprite sprite;

sf::Rect <int> rect;
rect.Top = 0 * m_Tilesets[1].tileHeight;
rect.Bottom = 0 * m_Tilesets[1].tileHeight + m_Tilesets[1].tileHeight;
rect.Left = 0 * m_Tilesets[1].tileWidth;
rect.Right = 0 * m_Tilesets[1].tileWidth + m_Tilesets[1].tileWidth;


sprite.SetImage(m_Tilesets[1].TilesetImage);

sprite.SetSubRect( rect );

sprite.SetPosition(0, 0);
window.Draw(sprite);
}

jordanske

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: 'Tiled' Tile-map Loader
« Reply #2 on: April 15, 2012, 07:29:59 pm »
hello,

I get errors when i use it with sfml 2.
i tried to fix it myself but with no luck.
i get black screen.

Could you update it please to sfml 2?

thanks,
Jordan

Sorry for my bad english

OutlawLee

  • Jr. Member
  • **
  • Posts: 50
  • This is my personal text. Dont read it.
    • View Profile
    • Email
Re: 'Tiled' Tile-map Loader
« Reply #3 on: May 06, 2012, 02:05:08 pm »
Yeah , i would love to see this for SFML 2.0

OutlawLee

  • Jr. Member
  • **
  • Posts: 50
  • This is my personal text. Dont read it.
    • View Profile
    • Email
Re: 'Tiled' Tile-map Loader
« Reply #4 on: September 09, 2012, 04:31:52 pm »
Here is the SFML 2 version, works just like the 1.6.

level.h
http://pastebin.com/gwasT3hR

level.cpp
http://pastebin.com/U1NG8eKD

fallahn

  • Hero Member
  • *****
  • Posts: 507
  • Buns.
    • View Profile
    • Trederia
Re: 'Tiled' Tile-map Loader
« Reply #5 on: September 18, 2012, 10:57:26 am »
I've been working on this for one of my own projects, so I thought I'd share what I've done:

Things it now does:
Works with SFML 2.0
Supports base64 and CSV encoded maps
Supports zlib and gzip compressed maps
Error handling when trying to find a non-existent object property
Error handling when trying to find a non-existent object
Support for *almost* all attribute tags in the latest version of the tmx format, including transparency colour, layer visibilty, margin and spacing (tested to work with the desert map example which comes with Tiled)
Object class now stores polygon and polyline objects as a vector of sf::vector2i points
Previously loaded maps are automatically cleared when loading a new map so a single instance of the class can be used to load multiple maps (successively, not at the same time)

What it still doesnt do:
No isometric map support - I'm not interested in this for my current project so unlikely I'll add it
No tsx tilemap support, only image file support - images must be in the same directory as the tmx file
Still only one tilemap currently supported
Not completely error safe because I haven't tested every outcome - missing attributes or corrupt tmx files may cause an assertion error.


To use zlib and gzip compressed maps you need to link the zlib library to your project. On debian you can apt-get install zlib1g-dev or download the source and configure/make/install (tested on Ubuntu 11.04 with zlib 1.2.7). Using VC on windows is a bit trickier but you can find a tutorial here (tested with VC10 on XP and Vista to work with static lib using 1.2.7). Presumably you can also do a configure/make/install with MinGW but I haven't tried.

You can download the files here.
« Last Edit: September 18, 2012, 11:06:38 am by fallahn »

OutlawLee

  • Jr. Member
  • **
  • Posts: 50
  • This is my personal text. Dont read it.
    • View Profile
    • Email
Re: 'Tiled' Tile-map Loader
« Reply #6 on: September 18, 2012, 06:13:31 pm »
Will this display objects that contain pictures ?
Im not sure how to use the objects.


Thanks man, this is a lot better than mine.

« Last Edit: September 18, 2012, 06:16:24 pm by OutlawLee »

fallahn

  • Hero Member
  • *****
  • Posts: 507
  • Buns.
    • View Profile
    • Trederia
Re: 'Tiled' Tile-map Loader
« Reply #7 on: September 18, 2012, 08:26:55 pm »
The object class just stores the data parsed from the object tags in the tmx file. All I've added to the original class is parsing of polygon and polyline points and storing them as sf::vector2i so you can draw out shapes or whatever you need using sfml. Now you mention it, no, it won't draw objects that contain pictures, although I did add parsing of objects with tile GIDs, so it wouldn't take much to update the draw method to draw the corresponding tile. This would probably be more useful if the class supported multiple tilemaps I guess. There is still much which could be added but I'm not sure if I'll do it myself unless I need something for a specific reason. I really just wanted to share the zlib compatibility as it was quite tricky to work out, and it's about time I gave something back to a very helpful community :)

Saiyomi

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: 'Tiled' Tile-map Loader
« Reply #8 on: September 27, 2012, 07:49:51 pm »
I am Having an issue where it is printing the tileset instead of the map.
I am using SFML 1.6.
Does anyone know how to fix this



« Last Edit: September 27, 2012, 08:54:04 pm by Saiyomi »

OutlawLee

  • Jr. Member
  • **
  • Posts: 50
  • This is my personal text. Dont read it.
    • View Profile
    • Email
Re: 'Tiled' Tile-map Loader
« Reply #9 on: September 27, 2012, 10:51:00 pm »
When you save a map with tiled its location of the tileset picture in the map is "../blabbal/mypicture"

so you have to open the map with notepad(text editor) and remove "../" and it will load corrently then, and when editing it back to edit the map with tiled

check paths if they are correct

Saiyomi

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: 'Tiled' Tile-map Loader
« Reply #10 on: September 28, 2012, 12:30:07 am »
Okay I got it working thanks for all of the help.
How do I instantiate the objects I create in the Object layer. I want to use them for collisions and such. How would I call them. i have classes like class player. What should I have to make them functional.
« Last Edit: October 02, 2012, 11:14:07 pm by Saiyomi »

OutlawLee

  • Jr. Member
  • **
  • Posts: 50
  • This is my personal text. Dont read it.
    • View Profile
    • Email
Re: 'Tiled' Tile-map Loader
« Reply #11 on: October 03, 2012, 12:33:06 am »
Im not sure that myself, but i know you can add object property in tiled e.g. "collision" and set it true for certain tiles which you can identify within the script later on. If someone could show us, would be nice :D

Saiyomi

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: 'Tiled' Tile-map Loader
« Reply #12 on: October 04, 2012, 12:51:24 am »
So I understand Bassically how the collisions work, I can set certain collision variables and pass those into the World from box2D and that will take care of it, but How do I instatiate the tiles to objects from the XML. So I did the forground on one layer and made certain players on other layers, but how do I make it so that when I read my forground layer I can set them as fixtures?

fallahn

  • Hero Member
  • *****
  • Posts: 507
  • Buns.
    • View Profile
    • Trederia
Re: 'Tiled' Tile-map Loader
« Reply #13 on: October 10, 2012, 11:32:17 pm »
In the version I posted you can create 'solid' objects by going to edit->preferences->object types in Tiled and adding a new type called 'solid'. Then if you create a rectangular object in Tiled you can right click on it, go to properties and set its type to 'solid'. The map loader will then find any objects with this type and create a sf::rect with the object's dimensions and add it to a vector named m_solidObjects (this is all existing functionality, not anything I added and so should be valid in the 1.6 version). This you can iterate over and call each rectangle's contains() function passing a vector2f (player position or whatever) as a parameter to check for collision. I've more recently added a contains() function to the object class too, which will let you check any objects in the m_objects vector which contain a list of poly points to see if the polygonal shape contains a point specified via a vector2f:

Code: [Select]
bool Object::Contains(const sf::Vector2f point)
{
//only test if we have enough points to create at least a triangle
if(polypoints.size() < 3) return false;
//else see if the point is inside the poly
unsigned int i, j;
bool result = false;
for (i = 0, j = polypoints.size() - 1; i < polypoints.size(); j = i++)
{
if (((polypoints[i].y > point.y) != (polypoints[j].y > point.y)) &&
(point.x < (polypoints[j].x - polypoints[i].x) * (point.y - polypoints[i].y) / (polypoints[j].y - polypoints[i].y) + polypoints[i].x))
result = !result;
}
return result;
}

which works by casting a ray through the polygon and counting the number of times it enters and exits it. If the number is odd then the point is inside, even it's outside.

Spunkt

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: 'Tiled' Tile-map Loader
« Reply #14 on: February 06, 2013, 03:59:29 pm »
Sorry for writing in a old post but, i've used this code to try get a map loader up and running. But when I try to run it I get an Assertion failure. It says:

File: f:\dd\vctools\crt_bld\self_x86\crt\src\strtol.c
Line: 94

Expression: nptr != NULL

anyone know what this might be?

Thanks