Problem displaying tiles using tiled map loader with SFML
- by user1905192
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!