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

Author Topic: Cant draw Tilemap with Class  (Read 6514 times)

0 Members and 1 Guest are viewing this topic.

Kaev

  • Newbie
  • *
  • Posts: 8
    • View Profile
Cant draw Tilemap with Class
« on: October 22, 2012, 01:11:52 pm »
Hello!

First: Sry for my bad english  :P
I wrote a class to load a map from my map1.txt.
Every value in the maparray is correct.
But i cant see anything in my window except my playercharacter and a black screen behind him, not one single tile.

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

using namespace std;

class Map
{
        public:
                int map_x, map_y;
                static int tile;
                int map[100][100];
                sf::Image image;
                sf::Texture textur;  
                vector<sf::Sprite> tiles;
                sf::RenderTexture rMap;
                sf::Sprite sMap;

        public:

                Map()
                {
                        map_x = 0;
                        map_y = 0;  
                       
            image.loadFromFile("graphics/boden.png");
            if(!image.loadFromFile("graphics/boden.png"))
            {
                std::cout << "boden.png konnte nicht geladen werden!\n";
            }
            textur.loadFromImage(image);
                };

                ~Map(){};

                void loadMap(const char *filename)
                {
                        int loadCounterX = 0, loadCounterY = 0;
                        std::ifstream file(filename);
                        if(file.is_open())
                        {
                                file >> map_x >> map_y;
                                while(!file.eof())
                                {
                                        file >> map[loadCounterX][loadCounterY];
                                        loadCounterX++;
                                        if(loadCounterX >= map_x)
                                        {
                                                loadCounterX = 0;
                                                loadCounterY++;
                                        }
                                }
                        }
                       
                        for(int x = 0; x < map_x; x++)
                        {
                                for(int y = 0;y < map_y; y++)
                                {
                                        int tileId = map[x][y];
                                        sf::Sprite tile;
                                        tile.setTexture(textur);
                                        tile.setTextureRect(sf::IntRect(map[y][x]*32, 0, 32, 32));
                                        tile.setPosition(x*32, y*32);
                                        tiles.push_back(tile);
                                }
                        }

                        for(int x = 0; x < tiles.size(); x++)
                        {
                                rMap.draw(tiles.at(x));
                                cout << "x";

                        }
                }

                sf::Sprite drawMap()
                {
                        rMap.display();

                        sMap.setTexture(rMap.getTexture());
                        return sMap;

                }
};
 

first i called this out of the mainloop:
Map map1;
map1.loadMap("map1.txt");
 

And in my mainloop i call:
Spiel.draw(map1.drawMap());
 

Hope you can help me.

Greetings!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10823
    • View Profile
    • development blog
    • Email
Re: Cant draw Tilemap with Class
« Reply #1 on: October 22, 2012, 01:27:38 pm »
I though I knew that problem from somewhere (spieleprogrammierer)... ;D

The problem I think lies in the call sMap.setTexture(rMap.getTexture());, because you set a new texture but you don't change the size of the texture rectangle, so you actually don't cut out anything from the render texture. (I think Schorsch already tried to point you in that direction).
Try changing it to: sMap.setTexture(rMap.getTexture(), true);
Also you shouldn't return a copy of the sprite when calling drawMap() but instead use a const reference. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Kaev

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Cant draw Tilemap with Class
« Reply #2 on: October 22, 2012, 01:58:47 pm »
I though I knew that problem from somewhere (spieleprogrammierer)... ;D

The problem I think lies in the call sMap.setTexture(rMap.getTexture());, because you set a new texture but you don't change the size of the texture rectangle, so you actually don't cut out anything from the render texture. (I think Schorsch already tried to point you in that direction).
Try changing it to: sMap.setTexture(rMap.getTexture(), true);
Also you shouldn't return a copy of the sprite when calling drawMap() but instead use a const reference. ;)

:P

sMap.setTexture(rMap.getTexture(), true);
Still everything black. :/

const sf::Sprite sMap
Error at
sMap.setTexture(rMap.getTexture(), true);
Error: The object has type qualifiers that are not compatible with the member function
(German error: Error: Das Objekt weist Typqualifizierer auf, die nicht mit der Memberfunktion kompatibel sind)


Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Cant draw Tilemap with Class
« Reply #3 on: October 22, 2012, 02:03:43 pm »
He means that:
const sf::Sprite& drawMap()
(you probably won't notice the difference on the performances though...)

Displaying and assigning the render-texture should only be done once, after drawing. This way, your getter can be const. And it should really have a different name. Calling "draw" something that only returns an object is misleading.
void loadMap(const char *filename)
{

    ...

    rMap.display();
    sMap.setTexture(rMap.getTexture());
}

const sf::Sprite& getSprite() const
{
    return sMap;
}
 

Additionnaly, an even better design would be to let the map draw itself, this way it can hide completely all the drawing details and provide a cleaner API to the caller:
void draw(sf::RenderTarget& target) const
{
    target.draw(sMap);
}

And... please fix your indentation, some parts of your code are hardly readable.
Laurent Gomila - SFML developer

Kaev

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Cant draw Tilemap with Class
« Reply #4 on: October 22, 2012, 02:17:02 pm »
#include <iostream>
#include <fstream>
#include <vector>
#include <SFML/Graphics.hpp>

using namespace std;

class Map
{
        public:
                int map_x, map_y;                       // width, height
                int map[100][100];                      // Maparray
                sf::Image image;                        // Image Tilemap
                sf::Texture textur;                     // Texture from Image Tilemap
                vector<sf::Sprite> tiles;               // Tilevector
                sf::RenderTexture rMap;         // Texture sMap
                sf::Sprite sMap;                        // Mapsprite

        public:

                Map()
                {
                        map_x = 0;
                        map_y = 0;  
                       
                        // Loading Texture
                        image.loadFromFile("graphics/boden.png");
                        if(!image.loadFromFile("graphics/boden.png"))
                       {
                              std::cout << "boden.png konnte nicht geladen werden!\n";
                       }
                       textur.loadFromImage(image);
                };

                ~Map(){};

                // Just tilesize
                static int getTile()
                {
                        return 32; // 1 Tile = 32 Pixel
                }

                void loadMap(const char *filename)
                {
                        // Load map from filename, first line width and height, other lines: id of tile
                        int loadCounterX = 0, loadCounterY = 0;
                        std::ifstream file(filename);
                        if(file.is_open())
                        {
                                file >> map_x >> map_y;
                                while(!file.eof())
                                {
                                        file >> map[loadCounterX][loadCounterY];
                                        loadCounterX++;
                                        if(loadCounterX >= map_x)
                                        {
                                                loadCounterX = 0;
                                                loadCounterY++;
                                        }
                                }
                        }
                       
                        // Create tiles
                        for(int x = 0; x < map_x; x++)
                        {
                                for(int y = 0;y < map_y; y++)
                                {
                                        int tileId = map[x][y];
                                        sf::Sprite tile;
                                        tile.setTexture(textur);
                                        tile.setTextureRect(sf::IntRect(map[y][x]*32, 0, 32, 32));
                                        tile.setPosition(x*32, y*32);
                                        tiles.push_back(tile);
                                }
                        }

                        // Draw tiles on rMap
                        for(int x = 0; x < tiles.size(); x++)
                        {
                                rMap.draw(tiles.at(x));

                        }

                        rMap.display();
                        sMap.setTexture(rMap.getTexture(), true);
                }

                // get Mapsprite
                const sf::Sprite& getSprite() const
                {
                        return sMap;

                }

                //draw Mapsprite on target
                void draw(sf::RenderTarget& target) const
                {
                        target.draw(sMap);
                }
};
 

Still everything black. :/
Indentation is changed a bit by the forum, sorry for this.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10823
    • View Profile
    • development blog
    • Email
Re: Cant draw Tilemap with Class
« Reply #5 on: October 22, 2012, 02:26:34 pm »
You should provide a minimal and complete example and include a map file, so we could test everything... ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Kaev

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Cant draw Tilemap with Class
« Reply #6 on: October 22, 2012, 02:35:48 pm »
map1.txt is like:
3 3
0 2 1
2 0 1
 

main.cpp (copied important lines from mine):
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/System.hpp>
#include "map.cpp"

sf::RenderWindow window(sf::VideoMode(800, 608, 32), "Spiel", sf::Style::Close);
Spiel.setVerticalSyncEnabled(true);

Map map1;
map1.loadMap("map1.txt");

while (window.isOpen())
{
        sf::Event event;
        while (window.pollEvent(event))
        {
                        switch(event.type)
                        {
                        case sf::Event::Closed:
                                window.close();
                                break;
                        default:
                                break;
                        }
                }

          window.clear();
          map1.draw(window);
          window.display();
          }
}

return EXIT_SUCCESS;
}
 

map.cpp:
see above

EDIT:
You should fix the code-tag, everytime it ruins my indentation :P
« Last Edit: October 22, 2012, 02:37:48 pm by Kaev »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Cant draw Tilemap with Class
« Reply #7 on: October 22, 2012, 02:45:29 pm »
Quote
You should fix the code-tag, everytime it ruins my indentation
The code tag is not broken, it shows exactly what you type.
Laurent Gomila - SFML developer

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10823
    • View Profile
    • development blog
    • Email
Re: Cant draw Tilemap with Class
« Reply #8 on: October 22, 2012, 03:41:26 pm »
The whole problem was that you never created the render texture, thus it had a size of (0,0) and obviously nothing gets displayed...

Here's a fully working code. I cleaned up your strange indentation (now uses tabs) and removed the useless vector thingy. I mean there's no sense in reading it into one vector if you're going to draw it once to a render texture and then use that texture. You don't need the sprites objects later. I also fixed the possibility that the program crashes if the map file doesn't exists and a few other minor things...
You should really stop just trying to 'solve' things by programming and rather sit down and think about what you're doing. ;)

Edit: Hmm the indentation doesn't look that nice now either...
@Laurent: Is it really necessary that one tab gets translated to 8 spaces? :O

#include <iostream>
#include <fstream>
#include <SFML/Graphics.hpp>

class Map
{
public:
        int map_x, map_y;       // width, height
        int map[100][100];      // Maparray
        sf::Texture textur;     // Texture from Image Tilemap
        sf::RenderTexture rMap; // Texture sMap
        sf::Sprite sMap;        // Mapsprite

public:

        Map() :
                map_x(0),
                map_y(0)
        {
                // Loading Texture
                if(!textur.loadFromFile("boden.png"))
                {
                        std::cout << "boden.png konnte nicht geladen werden!\n";
                }
        };

        // Just tilesize
        static int getTile()
        {
                return 32; // 1 Tile = 32 Pixel
        }

        void loadMap(const char *filename)
        {
                // Load map from filename, first line width and height, other lines: id of tile
                int loadCounterX = 0, loadCounterY = 0;
                std::ifstream file(filename);

                // Exit if file doesn't exist
                if(!file.is_open())
                {
                        std::cout << "Couldn't open '" << filename << "'. Aborting." << std::endl;
                        return;
                }

                file >> map_x >> map_y;
                while(!file.eof())
                {
                        file >> map[loadCounterX][loadCounterY];
                        loadCounterX++;
                        if(loadCounterX >= map_x)
                        {
                                loadCounterX = 0;
                                loadCounterY++;
                        }
                }

                // Create the off screen texture
                rMap.create(map_x*32, map_y*32);
                rMap.clear();

                // Create tiles
                for(unsigned int y = 0; y < map_y; ++y)
                        for(unsigned int x = 0; x < map_x; ++x)
                        {
                                sf::IntRect ir(map[y][x]*32, 0, 32, 32);
                                sf::Sprite sprite(textur, sf::IntRect(map[y][x]*32, 0, 32, 32));
                                sprite.setPosition(x*32, y*32);
                                rMap.draw(sprite);
                        }

                rMap.display();

                rMap.getTexture().copyToImage().saveToFile("test.png");
                sMap.setTexture(rMap.getTexture(), true);
        }

        // get Mapsprite
        const sf::Sprite& getSprite() const
        {
                return sMap;
        }

        //draw Mapsprite on target
        void draw(sf::RenderTarget& target) const
        {
                target.draw(sMap);
        }
};

int main()
{
        // Create window
        sf::RenderWindow window(sf::VideoMode(800, 600), "SFML");
        // Limit framerate
        window.setFramerateLimit(60);

        Map mm;
        mm.loadMap("map1.txt");

        while(window.isOpen())
        {
                // Event handling
                sf::Event event;
                while(window.pollEvent(event))
                {
                        if(event.type == sf::Event::Closed)
                                window.close();
                }

                // Render
                window.clear();
                mm.draw(window);
                window.display();
        }
}
 
« Last Edit: October 22, 2012, 03:45:53 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Cant draw Tilemap with Class
« Reply #9 on: October 22, 2012, 03:59:50 pm »
Quote
@Laurent: Is it really necessary that one tab gets translated to 8 spaces? :O
The mod doesn't allow to change the tab width through the admin panel. I have to add a line of code to the mod sources.

And if I change the mod settings so that tabs are not translated to spaces, I lose line breaks :(
Laurent Gomila - SFML developer

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10823
    • View Profile
    • development blog
    • Email
Re: Cant draw Tilemap with Class
« Reply #10 on: October 22, 2012, 04:05:51 pm »
The mod doesn't allow to change the tab width through the admin panel. I have to add a line of code to the mod sources.
I guess/hope shouldn't be that hard...
I'd suggest a 1 tab = 4 spaces translation, which is what you mostly get as default setting in many editors.

And if I change the mod settings so that tabs are not translated to spaces, I lose line breaks :(
Bad mod! :P
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Cant draw Tilemap with Class
« Reply #11 on: October 22, 2012, 04:23:50 pm »
Quote
I guess/hope shouldn't be that hard...
Yep, I'll try that as soon as I can.
Laurent Gomila - SFML developer

Kaev

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Cant draw Tilemap with Class
« Reply #12 on: October 22, 2012, 04:30:32 pm »
Thanks eXpl0it3r, everything works fine now.

@Laurent:
My indentation in VC++ is made with tabs, not spaces. After copy it into the codefunction, everything was messy so i had to clean it with spaces. That's why it looks so bad here.

Problem is fixed and thread can be closed now.
Thank you!

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Cant draw Tilemap with Class
« Reply #13 on: October 22, 2012, 04:33:54 pm »
Quote
My indentation in VC++ is made with tabs, not spaces. After copy it into the codefunction, everything was messy so i had to clean it with spaces. That's why it looks so bad here.
I was not talking about the indentation length, but about things that were not properly aligned although they belong to the same level of indentation (the texture loading in your first post, the event loop in your last post, etc.).
Laurent Gomila - SFML developer

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Cant draw Tilemap with Class
« Reply #14 on: October 22, 2012, 08:51:37 pm »
Quote
I'd suggest a 1 tab = 4 spaces translation
Done :)
Laurent Gomila - SFML developer

 

anything