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

Author Topic: So, I want to save a tile map.  (Read 18457 times)

0 Members and 1 Guest are viewing this topic.

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: So, I want to save a tile map.
« Reply #15 on: April 26, 2014, 05:31:45 pm »
Learn to use a debugger.  Issues like this will almost certainly make themselves obvious if you just step through your code and look at how the contents of tileMap do or don't change.

The bug is probably that while (amountOfTiles << map.size()) doesn't do what you think it does.  I assume you meant to write < instead of <<.

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: So, I want to save a tile map.
« Reply #16 on: April 26, 2014, 05:43:09 pm »
Learn to use a debugger.  Issues like this will almost certainly make themselves obvious if you just step through your code and look at how the contents of tileMap do or don't change.

The bug is probably that while (amountOfTiles << map.size()) doesn't do what you think it does.  I assume you meant to write < instead of <<.

I AM using a debugger, of course. The "<<" error didn't show in the VS12 error log, but an error saying "vector subscript out of range" shows up when I manually close the window. I don't know what that means under these circumstances.

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: So, I want to save a tile map.
« Reply #17 on: April 26, 2014, 05:51:39 pm »
I wasn't talking about looking at error messages.  That's not using a debugger.  I meant setting breakpoints and stepping through your program one line at a time and checking the value of map to make sure it's what you expect it to be, so you know exactly where it goes wrong.  That's what a debugger does.  VS12 can't magically tell when your program starts doing something you didn't expect, so don't expect that sort of error to show up in its logs.

"vector subscript out of range" means exactly what it says: you did something like myVector[1000] when myVector has a size less than 1000.  I assume this means there's a bug in your loops, since you seem to be manually reinventing the for loop in SaveMap.

To save you some time, I took the liberty of rewriting your code from the last post a bit to fix several stylistic issues.  Haven't tested it but this should be close to what you're after.

#include <SFML/Graphics.hpp>
#include <iostream>
#include <fstream>
#include <cctype>
#include <string>
#include <vector>
#include <sstream>

using namespace sf;
 
void LoadMap(const std::string& mapFileName, RenderWindow& window);
void SaveMap(const std::string& mapFileName);

std::vector<std::vector<Vector2i>> map;

std::string tileLocation;

int main()
{
    RenderWindow window(VideoMode(640, 480, 32), "TileEngine");
       
    LoadMap("Map1.txt", window);
       
        while(window.isOpen())
    {
        Event event;
        while(window.pollEvent(event))
        {
            switch (event.type)
            {
            case Event::Closed:
                window.close();
                break;
            }
        }
 
        window.clear();
 
        for(int i = 0; i < map.size(); i++)
        {
            for(int j = 0; j < map[i].size(); j++)
            {
                if(map[i][j].x != -1 && map[i][j].y != -1)
                {
                    tiles.setPosition(j * 32, i * 32);
                    tiles.setTextureRect(IntRect(map[i][j].x * 32, map[i][j].y * 32, 32, 32));
                    window.draw(tiles);
                }
            }
        }
 
        window.display();
    }
       
    SaveMap("Map1Copy.txt");
}

void LoadMap(const std::string& mapFileName, RenderWindow& window)
{
    std::ifstream openfile(mapFileName);
 
    Texture tileTexture;
    Sprite tiles;

    std::vector<Vector2i> mapRow;
        std::string line;
       
        if(std::getline(openfile, line)) {
                tileLocation = line;
        tileTexture.loadFromFile(tileLocation);
        tiles.setTexture(tileTexture);
        } else {
                throw std::logic_error("Invalid tilemap file");
        }

        while(std::getline(openfile, line)) {
       
                int start_pos = 0;
                int end_pos;
                while(end_pos = line.find('|', start_pos)) {
               
                        int slash_pos = line.find('/', start_pos);
                       
                        std::string x = line.substr(start_pos, slash_pos - start_pos);
                        std::string y = line.substr(slash_pos - start_pos, end_pos);
               
                        mapRow.push_back(Vector2i(stoi(x), stoi(y)));
                }
               
        map.push_back(mapRow);
        mapRow.clear();
    }
}

void SaveMap(const std::string& mapFileName)
{
    std::ofstream savefile(mapFileName);
   
    savefile << tileLocation << '\n';

    for(std::size_t row = 0; row < map.size(); row++)
    {
                for(std::size_t col = 0; col < map[row].size(); col++) {
                        if(col > 0) {
                                savefile << "|";
                        }
                        savefile << map[row][col].x;
                        savefile << "/";
                        savefile << map[row][col].y;
                }
               
                savefile << "\n";
    }
}


Regarding how to store the map, again, I wouldn't worry about it just yet.  It would just be distracting or confusing to get into that before all of these more important and more basic issues are sorted out.
« Last Edit: April 26, 2014, 05:55:33 pm by Ixrec »

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: So, I want to save a tile map.
« Reply #18 on: April 26, 2014, 06:06:02 pm »
I thought that writing if (x << y) would be an error? Can you insert an integer into another integer? That's why I thought it strange that it didn't show up as an error.

Your code actually fixed it - well, your rewriting of "SaveMap" did, the code wouldn't actually run the way you wrote it. Thank you very much for the help!

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: So, I want to save a tile map.
« Reply #19 on: April 26, 2014, 06:16:17 pm »
<< is also a bit shift operator.  That's probably what you were inadvertently using.

Quote
the code wouldn't actually run the way you wrote it.
That's what I get for writing code without having a compiler nearby.  Oh well, at least it helped.
« Last Edit: April 26, 2014, 06:20:33 pm by Ixrec »

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: So, I want to save a tile map.
« Reply #20 on: April 27, 2014, 05:50:46 pm »
All right, so I don't quite understand this vector::resize function. I'm using the following code:

tileMap.resize(xTileAmount);

for (int i = 0; i < xTileAmount; i++)
{
        tileMap[i].resize(yTileAmount);
}

However, it doesn't actually work. Also, if the new size is greater than the old one, is there a simple way of telling it what to fill the new Vector2i:s with?

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: So, I want to save a tile map.
« Reply #21 on: April 27, 2014, 05:57:49 pm »
What do you mean by "doesn't actually work"?  You have to tell us exactly what happened or we have no way of knowing what the problem might be.

If you read some documentation on vector::resize() (like http://www.cplusplus.com/reference/vector/vector/resize/), you'll see that it has an optional second argument that tells it what value to use for any new elements.
« Last Edit: April 27, 2014, 06:00:02 pm by Ixrec »

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: So, I want to save a tile map.
« Reply #22 on: April 27, 2014, 06:07:48 pm »
What do you mean by "doesn't actually work"?  You have to tell us exactly what happened or we have no way of knowing what the problem might be.

If you read some documentation on vector::resize() (like http://www.cplusplus.com/reference/vector/vector/resize/), you'll see that it has an optional second argument that tells it what value to use for any new elements.

a) It doesn't change the size of the vector.
b) Yes, I read it, but using "tileMap.resize(xTileAmount, Vector2i(-1, -1));" doesn't work, so I must have misunderstood something.

EDIT:
Is there a simple way to edit the "LoadMap" functions to load from a file in a .zip library or the like? I need to "protect" the data, and I'd like to either use a protected .zip file or something like binary, which I don't quite understand how to read from.
« Last Edit: April 27, 2014, 06:35:57 pm by ineed.help »

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: So, I want to save a tile map.
« Reply #23 on: April 27, 2014, 06:43:11 pm »
If you just want binary, the standard iostreams support that (look up ios::binary).

If you want .zip files, you'll need a different library for that.  I believe zlib can do what you want, though I know nothing about it.

Quote
a) It doesn't change the size of the vector.
What code are you using to check the size afterward?

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: So, I want to save a tile map.
« Reply #24 on: April 27, 2014, 06:58:03 pm »
If you just want binary, the standard iostreams support that (look up ios::binary).

Yeah, I know how to export to binary, but I assume I can't just load a text file, export it as binary, load the binary file, export it as text again and expect the second .txt to be the same as the first. (Can I?)

What code are you using to check the size afterward?

std::cout << tileMap.size() << tileMap[0].size;
This shows (5, 5) after calling ResizeMap(5, 5), which is what it's supposed to show.

However, after calling "DrawMap":
void Map::DrawMap(RenderWindow& window)
{
        window.clear();
 
        for(int i = 0; i < tileMap.size(); i++)
        {
                for(int j = 0; j < tileMap[i].size(); j++)
                {
                        if(tileMap[i][j].x != -1 && tileMap[i][j].y != -1)
                        {
                    tileSprite.setPosition(j * 32, i * 32);
                    tileSprite.setTextureRect(IntRect(tileMap[i][j].x * 32, tileMap[i][j].y * 32, 32, 32));
                    window.draw(tileSprite);
                        }
                }
        }
 
        window.display();
}
... It doesn't draw it correctly, so I guess there might be a problem with the "DrawMap" method.

Here is what the screen looks like before resizing:


And after:
« Last Edit: April 27, 2014, 07:06:10 pm by ineed.help »

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: So, I want to save a tile map.
« Reply #25 on: April 27, 2014, 07:06:28 pm »
If you just want binary, the standard iostreams support that (look up ios::binary).

Yeah, I know how to export to binary, but I assume I can't just load a text file, export it as binary, load the binary file, export it as text again and expect the second .txt to be the same as the first. (Can I?)

I don't see why not.  You could easily write your load/save methods so that text and binary are just two different formats for the same data.  In principle "text" is just a very specific kind of binary data.

Quote
What code are you using to check the size afterward?

std::cout << tileMap.resize() << tileMap[0].resize;
This shows (5, 5) after calling ResizeMap(5, 5), which is what it's supposed to show.

resize() returns void, so that should be a compiler error.  Try calling size() or iterating through it.

Quote
... It doesn't draw it correctly, so I guess there might be a problem with the "DrawMap" method.

Have you checked (with cout or a debugger) what the actual values in tileMap are when DrawMap is called?  DrawMap may not be doing anything wrong.
« Last Edit: April 27, 2014, 07:09:25 pm by Ixrec »

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: So, I want to save a tile map.
« Reply #26 on: April 27, 2014, 09:31:50 pm »
Quote
resize() returns void, so that should be a compiler error.  Try calling size() or iterating through it.
You obviously missed my edit - I did not use "resize", I used "size".

Quote
Have you checked (with cout or a debugger) what the actual values in tileMap are when DrawMap is called?  DrawMap may not be doing anything wrong.
Well, when I check the x- and y-values of each vector, it shows exactly as in the tile map, and, as I said earlier, nothing seems to be wrong with the resizing - as you can see in the images I just posted, when I use "ResizeMap(10, 10);" --- tileMap is actually 9x10 ---, I guess it fills the first row with "Vector2i(0, 0)":s. When I use "tileMap[0][_].x" or "tileMap[0][_].y" (where _ can be more than just 0, it doesn't matter), it gives the error "vector subscript out of range". I don't understand anything here.

Would it help if I attached the code as it is now, you think?

BIG EDIT!:
I just tested adding "01/00" (the ground tile) to the top layer of the tilemap, and it turns out the map is drawn with the beginning in the SECOND row - this is what it looks like when I haven't resized it.

How can I stop this from happening? It seems like it is filling all empty tiles with grass tiles, but... well, I don't understand what is even happening.

EDIT AGAIN:
I found out that if I change Map1.txt from:
Code: [Select]
tiles.png
01/00|01/00|01/00|01/00|01/00|01/00|01/00|01/00|01/00|01/00
-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1
-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1
-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1
-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1
-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1
-1/-1|-1/-1|-1/-1|-1/-1|00/01|01/01|-1/-1|-1/-1|-1/-1|-1/-1
-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1
00/00|00/00|00/00|00/00|00/00|00/00|00/00|00/00|00/00|00/00

... to:

Code: [Select]
tiles.png 01/00|01/00|01/00|01/00|01/00|01/00|01/00|01/00|01/00|01/00
-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1
-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1
-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1
-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1
-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1
-1/-1|-1/-1|-1/-1|-1/-1|00/01|01/01|-1/-1|-1/-1|-1/-1|-1/-1
-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1|-1/-1
00/00|00/00|00/00|00/00|00/00|00/00|00/00|00/00|00/00|00/00

... it works out fine, and it starts drawing from the start of the window, so there must be something wrong with my "LoadMap" function...
« Last Edit: April 27, 2014, 09:43:05 pm by ineed.help »

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: So, I want to save a tile map.
« Reply #27 on: April 27, 2014, 09:44:40 pm »
It was resize before I posted, but oh well.

Thus far almost all of these errors are ones that could very easily be caught with proper debugger use.  Namely, setting breakpoints and stepping through one line at a time while checking variable values to see exactly where it goes wrong (just running your program in debug mode is NOT using a debugger).  Posting your current code would definitely help (otherwise all I can do is guess), but even then I'd basically just go use a debugger on it myself.  It would probably be more beneficial if you took this opportunity to learn to use your debugger properly so you won't need help with these simple mistakes anymore.

With this recent issue, it should become obvious what's going wrong if you simply set a breakpoint at the beginning of DrawMap and step through the first iteration of the loop.

Edit: Okay, step through LoadMap instead I guess.
« Last Edit: April 27, 2014, 09:47:55 pm by Ixrec »

ineed.help

  • Jr. Member
  • **
  • Posts: 56
    • View Profile
Re: So, I want to save a tile map.
« Reply #28 on: April 27, 2014, 09:55:09 pm »
It was resize before I posted, but oh well.

Thus far almost all of these errors are ones that could very easily be caught with proper debugger use.  Namely, setting breakpoints and stepping through one line at a time while checking variable values to see exactly where it goes wrong (just running your program in debug mode is NOT using a debugger).  Posting your current code would definitely help (otherwise all I can do is guess), but even then I'd basically just go use a debugger on it myself.  It would probably be more beneficial if you took this opportunity to learn to use your debugger properly so you won't need help with these simple mistakes anymore.

With this recent issue, it should become obvious what's going wrong if you simply set a breakpoint at the beginning of DrawMap and step through the first iteration of the loop.

Edit: Okay, step through LoadMap instead I guess.
How do I use these "breakpoints"? From what I understand, it's those red circles next to code that you can put up, put I don't understand how to use them.

EDIT:
Also, how do I set the default Vector2i here?
void Map::ResizeMap(int _columnAmount, int _rowAmount)
{
        columnAmount = _columnAmount;
        rowAmount = _rowAmount;

        tileMap.resize(columnAmount);

        for (int i = 0; i < columnAmount; i++)
        {
                tileMap[i].resize(rowAmount);
        }

        std::cout << tileMap.size() << "," << tileMap[0].size();
}
I tried using "tileMap.resize(columnAmount, Vector2i(-1, -1));", but that's apparently not a valid constructor for "resize".
« Last Edit: April 27, 2014, 10:02:18 pm by ineed.help »

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: So, I want to save a tile map.
« Reply #29 on: April 27, 2014, 10:09:00 pm »
As I said before, the second parameter to resize() is what you want.

You should google some proper tutorials on debugging with an IDE, but here's the one-minute version I feel like typing:

- Click on the left margin to create a red circle.  This is a breakpoint.
- Run your program in debug mode.  When the breakpoint is reached, your code will stop executing.
- Explore the various tabs or windows that appear in your IDE after execution stops.  These should allow you to inspect the current values of local variables (including all values inside classes and containers).
- Use the "step over", "step in" and "step out" buttons to step through your code one line at a time.  Step over will step through one line of code at a time, even if that line calls several other functions.  Step into will go to the next line of code that gets executed, even if it's inside a function.  Step out exits the current function and gets you to the next line of whatever was calling it.  ALL debuggers will have these three buttons.
- Use the play button if you want normal execution to resume.
- Visual Studio even lets you edit code during debugging, and it will attempt to compile your edits into the executable it's currently debugging.  This is very cool when it works (eg, I think you can't edit the line you're currently stopped on).

For the record, the main reason debug mode exists in the first place is to make all of these features possible.