Problem displaying tiles using tiled map loader with SFML

Posted by user1905192 on Game Development See other posts from Game Development or by user1905192
Published on 2012-12-14T21:49:57Z Indexed on 2012/12/14 23:23 UTC
Read the original article Hit count: 357

Filed under:
|
|

I've been searching fruitlessly for what I did wrong for the past couple of days and I was wondering if anyone here could help me. My program loads my tile map, but then crashes with an assertion error. The program breaks at this line: spacing = atoi(tilesetElement->Attribute("spacing"));

Here's my main game.cpp file.

#include "stdafx.h"
#include "Game.h"
#include "Ball.h"

#include "level.h"
using namespace std;

    Game::Game()
    {
        gameState=NotStarted;
        ball.setPosition(500,500);
        level.LoadFromFile("meow.tmx");
    }

   void Game::Start()
    {
    if (gameState==NotStarted)
    {
    window.create(sf::VideoMode(1024,768,320),"game");

    view.reset(sf::FloatRect(0,0,1000,1000));//ball drawn at 500,500
   level.SetDrawingBounds(sf::FloatRect(view.getCenter().x-view.getSize().x/2,view.getCenter().y-view.getSize().y/2,view.getSize().x, view.getSize().y)); 
    window.setView(view);

    gameState=Playing;
}
while(gameState!=Exiting)
{
    GameLoop();
}

window.close();
   }

  void Game::GameLoop()
  {
      sf::Event CurrentEvent;
      window.pollEvent(CurrentEvent);
     switch(gameState)
     {
      case Playing:
    {
        window.clear(sf::Color::White);
        window.setView(view);
        if (CurrentEvent.type==sf::Event::Closed)
        {
            gameState=Exiting;
        }
        if ( !ball.IsFalling() &&!ball.IsJumping() &&sf::Keyboard::isKeyPressed(sf::Keyboard::Space))
        {
            ball.setJState();
        }
        ball.Update(view);
        level.Draw(window);
        ball.Draw(window);
        window.display();
        break;
    }

}
}

And here's the file where the error happens:

    /*********************************************************************
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 "level.h"

      #include <iostream>
      #include "tinyxml.h"
      #include <fstream>

      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 = strtod(properties[name].c_str(), NULL);

    return f;
}

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

Level::Level()
{
    //ctor
}

Level::~Level()
{
    //dtor
}
using namespace std;
bool Level::LoadFromFile(std::string filename)
{
    TiXmlDocument levelFile(filename.c_str());

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

    //Map element. This is the root element for the whole file.
    TiXmlElement *map;
    map = levelFile.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"));

    //Tileset stuff
    TiXmlElement *tilesetElement;
    tilesetElement = map->FirstChildElement("tileset");
   firstTileID = atoi(tilesetElement->Attribute("firstgid"));
    spacing = atoi(tilesetElement->Attribute("spacing"));
    margin = atoi(tilesetElement->Attribute("margin"));

    //Tileset image
    TiXmlElement *image;
    image = tilesetElement->FirstChildElement("image");
    std::string imagepath = image->Attribute("source");

    if (!tilesetImage.loadFromFile(imagepath))//Load the tileset image
    {
        std::cout << "Failed to load tile sheet." << std::endl;
        return false;
    }

    tilesetImage.createMaskFromColor(sf::Color(255, 0, 255));

    tilesetTexture.loadFromImage(tilesetImage);
    tilesetTexture.setSmooth(false);

    //Columns and rows (of tileset image)
    int columns = tilesetTexture.getSize().x / tileWidth;
    int rows = tilesetTexture.getSize().y / tileHeight;

    std::vector <sf::Rect<int> > subRects;//container of subrects (to divide the tilesheet image up)

    //tiles/subrects are counted from 0, left to right, top to bottom
    for (int y = 0; y < rows; y++)
    {
        for (int x = 0; x < columns; x++)
        {
            sf::Rect <int> rect;
            rect.top = y * tileHeight;
            rect.height = y * tileHeight + tileHeight;
            rect.left = x * tileWidth;
            rect.width = x * tileWidth + tileWidth;
            subRects.push_back(rect);
        }
    }

    //Layers
    TiXmlElement *layerElement;
    layerElement = map->FirstChildElement("layer");
    while (layerElement)
    {
        Layer layer;
        if (layerElement->Attribute("opacity") != NULL)//check if opacity attribute exists
        {
            float opacity = 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
        }

        //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;

        while (tileElement)
        {
            int tileGID = atoi(tileElement->Attribute("gid"));
            int subRectToUse = tileGID - firstTileID;//Work out the subrect ID to 'chop up' the tilesheet image.
            if (subRectToUse >= 0)//we only need to (and only can) create a sprite/tile if there is one to display
            {
                sf::Sprite sprite;//sprite for the tile
                sprite.setTexture(tilesetTexture);
                sprite.setTextureRect(subRects[subRectToUse]);
                sprite.setPosition(x * tileWidth, y * tileHeight);

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

                //add tile to layer
                layer.tiles.push_back(sprite);
            }

            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;
                }
            }
        }

        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;
                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"));
                int width = atoi(objectElement->Attribute("width"));
                int height = atoi(objectElement->Attribute("height"));

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

                sf::Rect <int> objectRect;
                objectRect.top = y;
                objectRect.left = x;
                objectRect.height = y + height;
                objectRect.width = x + width;

                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);

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

    return true;
}

Object Level::GetObject(std::string name)
{
    for (int i = 0; i < objects.size(); i++)
    {
        if (objects[i].name == name)
        {
            return objects[i];
        }
    }
}

void Level::SetDrawingBounds(sf::Rect<float> bounds)
{
    drawingBounds = bounds;
    cout<<tileHeight;
    //Adjust the rect so that tiles are drawn just off screen, so you don't see them disappearing.
    drawingBounds.top -= tileHeight;
    drawingBounds.left -= tileWidth;
    drawingBounds.width += tileWidth;
    drawingBounds.height += tileHeight;
}

void Level::Draw(sf::RenderWindow &window)
{
    for (int layer = 0; layer < layers.size(); layer++)
          {
              for (int tile = 0; tile < layers[layer].tiles.size(); tile++)
              {
                   if (drawingBounds.contains(layers[layer].tiles[tile].getPosition().x, layers[layer].tiles[tile].getPosition().y))
                  {
                      window.draw(layers[layer].tiles[tile]);
                  }
              }
          } 
      }

I really hope that one of you can help me and I'm sorry if I've made any formatting issues. Thanks!

© Game Development or respective owner

Related posts about c++

Related posts about tilemap