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

Author Topic: Saving a tile map  (Read 1908 times)

0 Members and 1 Guest are viewing this topic.

JohannesMerkt

  • Newbie
  • *
  • Posts: 4
    • View Profile
Saving a tile map
« on: August 27, 2013, 04:04:10 pm »
Hello SFML Community,

I have created a class map. Now I want to save this map and therefor I wrote 2 functions within my class Map:

This is the function to open a file
bool Map::open(sf::String dir) // dir will be the directory were the file is but i dont use this for now
{
        delete [] ptiles; //clear the tileset from the old map
        ptiles = 0; //pointer ptiles set to 0 for savety reasons
        tilesetdir.clear(); // clear the old sf::String

        std::fstream in("maps/map2.map", std::ios::in | std::ios::binary);
        if(!in) return false;
        in.read( (char *) &tilesetdir,sizeof(sf::String));

        if(!tileset.loadFromFile(tilesetdir)) return false; //here i try to load the texture
        drawingsprite.setTexture(tileset); // and i set the texture

        in.read( (char *) &mapsize, sizeof(sf::Vector2i));

        ptiles = new textile[mapsize.x*mapsize.y];

        in.read( (char *) ptiles,sizeof(textile)*mapsize.x+mapsize.y);
        in.close();
        return true;
}

And this is the function to save the map:
bool Map::save(sf::String dir) // dir is directory were I want to save to but it is also not used for now
{
        std::fstream out("maps/map2.map", std::ios::out | std::ios::binary );
        if(!out) return false;
        out.write( (char *) &tilesetdir, sizeof(sf::String));
        out.write( (char *) &mapsize, sizeof(sf::Vector2i));
        out.write( (char *) ptiles, sizeof(textile)*mapsize.x*mapsize.y);
        out.flush();
        out.close();
        return true;
}

The data i want to save is:
textile * ptiles; //a pointer on an array of textiles (one dimension)
-----------------------------------------------------------------------------------------------------------------
//this is how the textile looks:
        struct textile
        {
                sf::Vector2<unsigned char> tilepos;
                unsigned char type;
        };
ptiles has the size[mapsize.x*mapsize.y]
sf::String tilesetdir; //a string of the directory of the tileset
sf::Vector2i mapsize; //a vector that stores the mapsize
the masize is used to know how big the array *ptiles has to be

when I try to use the functions it seems to save and when I try to open it it returns false
Now my question is what do i do wrong?
I tried several different ways but none worked properly
« Last Edit: August 27, 2013, 04:12:40 pm by JohannesMerkt »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11035
    • View Profile
    • development blog
    • Email
Re: Saving a tile map
« Reply #1 on: August 27, 2013, 04:07:50 pm »
Well that's not really strange, if you look again closely at your code:

    std::fstream in("maps/map2.map", std::ios::in | std::ios::binary);
    if(!in) {} return false;
    in.read( (char *) &tilesetdir,sizeof(sf::String));
<=>
    std::fstream in("maps/map2.map", std::ios::in | std::ios::binary);
    if(!in)
    {
    }
    return false;
    in.read( (char *) &tilesetdir,sizeof(sf::String));

That's why I find it a good practice to always use new lines. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

JohannesMerkt

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Saving a tile map
« Reply #2 on: August 27, 2013, 04:12:21 pm »
thank you for you fast reply,

I forgot to remove those brackets when posting it here, this was not the mistake there must be something else.
(i will remove them now)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Saving a tile map
« Reply #3 on: August 27, 2013, 04:13:09 pm »
Serializing variables is more complicated than doing a simple bit copy.

For example, what you'll find at the address of a sf::String is typically a size and a pointer to the actual characters. Not the characters themselves -- they are elsewhere in memory.

Other example: if you serialize an integer like this, and later read the file on a different machine where either the size or the endianness of the integer type is not the same, you'll read garbage.

These are the two main problems that show that direct copy is the wrong approach to serialization.

A much better solution is to serialize in text format; and in any case, you'll need to handle the specificities of non-primitive types, not just throw their bits in your stream. For example, you must serialize tilesetdir.c_str() to get the actual characters of the string. You must serialize mapsize.x and mapsize.y separately. Etc...
Laurent Gomila - SFML developer

JohannesMerkt

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Saving a tile map
« Reply #4 on: August 27, 2013, 05:04:06 pm »
Thank you that was very helpful

One more question how can i get from "c_str" back to sf::String?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Saving a tile map
« Reply #5 on: August 27, 2013, 07:51:14 pm »
Very easy, just read the doc.

// sf::String to const sf::Uint32*
const sf::Uint32* ptr = str.c_str();

// const sf::Uint32* to sf::String
sf::String str = ptr;
Laurent Gomila - SFML developer