1

I try to create a tiled base map by using Qt GUI: I have two classes: one to set my tile images that inherits from QGraphicPixmapItem, one to load my map from a text file that is a 2D array composed of the numbers 1, 0 and 2, and add it to a scene: But my program quits unexpectedly and I do not know where is the break:

my tile class:

class mapTile: public QGraphicsPixmapItem
{
public:
    enum Tile {DOOR, GRASS, FIRE};

    mapTile(): QGraphicsPixmapItem(),currentTile(GRASS){
        syncBitmap();
    }

    Tile getTile() const {return currentTile;}

    void setTile(Tile newTile){
        if(currentTile!= newTile){
            currentTile=newTile;
            syncBitmap();
        }
    }

private:
    void syncBitmap() {//Set my image to my tile
        switch(currentTile) {
        case DOOR:
            image->setPixmap(QPixmap(":/mpa/castledoors.png"));
        case GRASS:
            image->setPixmap(QPixmap(":/map/grass3_blur.jpg"));
        case FIRE:
            image->setPixmap(QPixmap(":/map/feu1/png"));
        }
    }

    Tile currentTile;
    QGraphicsPixmapItem *image;

};

my class map:

Map.h:

class Map
{

public:
    static const int TILE_SIZE=20; //value of the tile in pixels!!!->20X20=a tile
    void paintMap(QGraphicsScene *scene);
    Map();

 private:

    static const int WIDTH= 13;// width of the grid cell
    static const int HEIGHT= 9;//height  of the grid cell

    //my grid cell map !!!!
    int array[WIDTH][HEIGHT];
    mapTile *tile; //my tile

};

And Map.cpp

/*Create a default Map*/
Map::Map()
{
    QFile myfile("path to my file");
    if (!myfile.open(QIODevice::ReadOnly | QIODevice::Text))
    {
         QMessageBox::information(0, "error", myfile.errorString());
    }

    QTextStream in(&myfile);
    QString line ;
    QStringList fields;
    int i=0;
    int j=0;

    while (!in.atEnd()) {
        //Fill my array with my list--> convert Qtring into Int
        for (i=0; i<HEIGHT; i++ ) {

           line = in.readLine();
           fields = line.split(" ");

           for(j=0;j<WIDTH;j++)
           {
               //cout<<fields[j].toInt();
                array[i][j] = fields[j].toInt();
           }
        }
    }
}



//Paint my map with my tile
void Map::paintMap(QGraphicsScene *scene){

    int i=0, j=0;
    tile= new mapTile();

    for (i=0; i<HEIGHT; i++){
        for(j=0; j<WIDTH; j++){

            switch(array[i][j]){

            case 0:

                tile->setTile(mapTile::GRASS);
                tile->setPos(i,j);
                scene->addItem(tile);
                j+=TILE_SIZE;

            case 1:

                tile->setTile(mapTile::FIRE);
                tile->setPos(i,j);
                scene->addItem(tile);
                j+=TILE_SIZE;
            case 2:

                tile->setTile(mapTile::DOOR);
                tile->setPos(i,j);
                scene->addItem(tile);
                j+=TILE_SIZE;
            }

            i+=TILE_SIZE;//
        }
    }

}

and finally my mainwindow (I directly give the file.cpp):

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    myMap= new Map;
    scene= new QGraphicsScene(this);

    myMap->paintMap(scene);
    ui->graphicsView->setScene(scene);

}

MainWindow::~MainWindow()
{
    delete ui;
}

Sorry guys for the long post but I am stuck! Any ideas on what I missed?

Ary
  • 128
  • 1
  • 1
  • 11

2 Answers2

1

Well, there are at least five problems in your code:

  • You can't share the same myTile instance when adding them to the scene. You need to create a new one each time you're adding a tile to the scene. At the moment you're creating only one instance at the start of Map::paintMap.

  • Your myTile class inherits from QGraphicsPixmapItem, however it also has a QGraphicsPixmapItem *image; member which it leaves uninitialized (so it's a roaming pointer), but then it uses it in image->setPixmap(QPixmap(":/mpa/castledoors.png")); which will crash. Instead, you'll want to just call setPixmap(QPixmap(":/mpa/castledoors.png")) (calling the function of your superclass).

  • In the above item you may have noticed that you misspelled "map" as "mpa", though this will not be the reason of your crash.

  • In mapTile::syncPixmap as well as in Map::paintMap, you forgot the break; statements in the switch. Without those, all tiles would appear like fire tiles.

  • You're adding your tile size to the i and j iterators, as if they were the pixel coordinates, but at the same time you're using them as array indexes. You need to either use separate variables for the pixel coordinates or multiply i and j by the TILE_SIZE when calling setPos instead.

Good luck!

Thorbjørn Lindeijer
  • 2,022
  • 1
  • 17
  • 22
  • Hey! Thank you for you response! I put all the breaks that missed, I created 3 different mapTile objects in my map class, initialized my QGraphicPixmapItem and I decided to multiply my i and my j by TILE_SIZE in setPos() as you said, and finally it doesn't crash anymore :) I have a window but with nothing! Indeed I used a scene when I call, in my main, the function paintMap() that expects a scene as argument, but how I can add my map that is not a scene itself to my view then?? – Ary Oct 14 '14 at 20:13
  • And yes it is "map" and not "mpa" ;) – Ary Oct 14 '14 at 20:14
  • You shouldn't need to add your map to the scene since your `paintMap` function is already adding the tiles to it which should be showing up. I don't know why your tiles would not be showing up. Try adding some debug prints to your code (include `QDebug` and use `qDebug() << ...`) to try finding out what is going on. – Thorbjørn Lindeijer Oct 15 '14 at 21:15
0

I have finally found solutions to my problems: I added a scene to my function paintMap for adding each item to my scene and created a QGraphicScene* getScene() that returns the scene then I just call it my mainWindow by just writing

ui->graphicsView->setScene(myMap->getScene())

Moreover in my mapTile class I don't use anymore the function setTile(). I removed it, then changed my QGraphicPixmapItem *image by a QPixmap image and in my function syncbitmap() I did this->setPixmap(image.scaled(TILE_SIZE,TILE_SIZE));at the end of my switch! Why? Because my tile is already a QGraphicsPixmapItem (inheritance) so I just have to set a pixmap to it! And I put it at the end of the switch because if I set the image before, the image will never change because it will be already set! And finally in the constructor I removed currentTile(GRASS), added a Tile variable in my constructor as an argument and just put currentTile= name of your variable in the constructor and then called the syncBitmap function. So in paintMap() you just have to do:

tile= new mapTile(mapTile::GRASS);
tile->setPos(j*TILE_SIZE,i*TILE_SIZE);
scene->addItem(tile);

in each case! Voilà! I hope that will help a newbie like me, at least to understand the logic behind! I am not sure that is the best way to do but this way works for me! :)

Ary
  • 128
  • 1
  • 1
  • 11