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

Author Topic: Problem displaying tiles, only showing up as dots.  (Read 3179 times)

0 Members and 1 Guest are viewing this topic.

Stormblessed

  • Newbie
  • *
  • Posts: 6
    • View Profile
Problem displaying tiles, only showing up as dots.
« on: February 25, 2012, 06:07:27 am »
So I've been working on setting up a tile system for a block-pushing puzzle game, and I got it to work awhile back, but it was extremely inefficient and ran at like 5 frames a second.  

So I think I did a fair amount to amend that: creating a TextureManager class and having my tiles sprites simply point to tiles in that object.  However somewhere in all of my changes something got screwed up and it's now just displaying tiny white dots in the upper left corner of each tile.  

I think it's an issue with pointers but I'm really not sure.  Because when I close down the program it shows a bunch of OpenGL errors really fast in console before closing.  It was impossible to read before closing so I grabbed a snapshot: http://imgbox.com/aayX2yHW


The textures do show up in the TextureManager object when I look at it in debug mode, but something is screwing up in between, as the Tile's sprite doesn't have any characteristics: http://imgbox.com/aavNp9fw


The important part(s) of TextureManager.cpp
-----------------------------------------------------------
Code: [Select]
void TextureManager::loadTextureMap(string fileName)
{
sf::Image imageLoad;

if(!imageLoad.LoadFromFile(fileName))
{
cout << "Error loading image, TextureManager addImageByFile function\n";
}

for(int i = 1; i <= 6; i++)
{
for(int k = 1; k <= 6; k++)
{
sf::Texture tempTexture;

tempTexture.LoadFromImage(imageLoad, sf::IntRect(((k-1)*48),((i-1)*48),48,48));
addTextureFromData(tempTexture);

//Empty up the memory for safety reasons(not sure if it actually does anything)
tempTexture.~Texture();
}
}
}



The Tile.h code
---------------------------------------------
Code: [Select]
class Tile
{
public:
Tile(int);
Tile(sf::Texture &);
Tile(void);
~Tile(void);

void setSprite(sf::Texture &);
void drawTile(int, int, sf::RenderWindow*);

sf::Sprite getSprite();
int getId();

private:
int id;
sf::Sprite tileSprite;
};



The important part(s) of the Tile.cpp code
-------------------------------------------------------------------
Code: [Select]
Tile::Tile(sf::Texture & textureSet)
{
tileSprite.SetTexture(textureSet);
}
void Tile::setSprite(sf::Texture & textureSet)
{
tileSprite.SetTexture(textureSet);
}

void Tile::drawTile(int xPos, int yPos, sf::RenderWindow *Window)
{
tileSprite.SetPosition(xPos, yPos);

Window -> Draw(tileSprite);
}

sf::Sprite Tile::getSprite()
{
return tileSprite;
}



Room.h code
------------------------------------------
Code: [Select]
class Room
{
public:
Room(vector<vector<Tile>>, vector<vector<Block>>);
Room(void);
~Room(void);

void initializeRoom(string, string, TextureManager &);
void setFloor(vector<vector<Tile>>);
void setBlocks(vector<vector<Block>>);
void addTile(int, Tile);
void addBlock(int, Block);
void assignTileSprites(TextureManager &);
void loadFromImages(sf::Image, sf::Image);
void saveToImages();
void displayRoomConsole();
void drawRoom(sf::RenderWindow *, TextureManager &);

Tile getTile(int, int);
Block getBlock(int, int);
vector<vector<Tile>> getFloor();
vector<vector<Block>> getBlocks();
int getRowNum();
int getCollumnNum();

private:
vector<vector<Tile>> floor;
vector<vector<Block>> blocks;
int rows;
int collumns;
};



The important parts of Room.cpp
----------------------------------------
Code: [Select]
void Room::initializeRoom(string floorFileLoc, string blocksFileLoc, TextureManager & textures)
{
sf::Image floorImage, blocksImage;

if(!floorImage.LoadFromFile(floorFileLoc))
{
cout << "Error loading Image, Floor file\n";
}
if(!blocksImage.LoadFromFile(blocksFileLoc))
{
cout << "Error loading Image, Blocks file\n";
}

collumns = floorImage.GetWidth();
rows = floorImage.GetHeight();

loadFromImages(floorImage, blocksImage);
assignTileSprites(textures);
}
void Room::assignTileSprites(TextureManager & textures)
{
for(int i = 0; i < getRowNum(); i++)
{
for(int k = 0; k < getCollumnNum(); k++)
{
switch(getTile(i, k).getId())
{
case plain:
getTile(i, k).setSprite(textures.getTexture(0));
break;
case iceFloor:
getTile(i, k).setSprite(textures.getTexture(1));
break;
case magmaFloor:
getTile(i, k).setSprite(textures.getTexture(2));
break;
case spikeFloor:
getTile(i, k).setSprite(textures.getTexture(3));
break;
case stickyFloor:
getTile(i, k).setSprite(textures.getTexture(4));
break;
case raisedPlain:
getTile(i, k).setSprite(textures.getTexture(5));
break;
case ditch:
getTile(i, k).setSprite(textures.getTexture(6));
break;
case water:
getTile(i, k).setSprite(textures.getTexture(7));
break;
case deathPit:
getTile(i, k).setSprite(textures.getTexture(8));
break;
case button:
getTile(i, k).setSprite(textures.getTexture(9));
break;
default:
cout << "Problem rendering tile, invalid tile id\n";
break;
}
}
}

}
void Room::drawRoom(sf::RenderWindow *window, TextureManager & textures)
{
for(int i = 0; i < getRowNum(); i++)
{
for(int k = 0; k < getCollumnNum(); k++)
{
getTile(i, k).drawTile(i*48, k*48, window);
}
}
}


..and finally main.cpp
-------------------------------------
Code: [Select]
int main()
{
int speed = 16;
Room testRoom;
Character testPlayer;
TextureManager textures;
bool rightPress = false;
bool leftPress = false;
bool upPress = false;
bool downPress = false;
int xMove = 0;
int yMove = 0;

testPlayer.setSpriteTexture("Resources/Sprites/chain.bmp");

//Loads a 36x36 texture map and splits it into individual textures
textures.loadTextureMap("Resources/TexturePacks/defaultTexturePack.bmp");

//loads the room data from the map bitmap files
testRoom.initializeRoom("Resources/Maps/emptyroomfloor.bmp", "Resources/Maps/emptyroomblocks.bmp", textures);


    sf::RenderWindow Window(sf::VideoMode(640, 480, 32), "SFML Basic Build");

Window.SetFramerateLimit(60);

    while (Window.IsOpened())
    {
sf::Event Event;

while (Window.PollEvent(Event))
        {
//This part was removed for conciseness :)
}
testPlayer.moveChar(xMove,yMove);
testPlayer.updatePos();
yMove = 0;
xMove = 0;
Window.Clear(sf::Color(50, 50, 50));
testRoom.drawRoom(& Window, textures);
Window.Draw(testPlayer.getSprite());
        Window.Display();
    }
 
system("pause");
    return 0;



I know that's a ton of stuff to look through, but I thought that I might as well get a couple more sets of eyes(more experienced ones :)) to help me figure out where I was going wrong, because my brain is tied into knots right now...  
EDIT:If someone replies, I'll read it in about 8 hours, because I'm going to bed at the moment.  Hopefully it's an easy error to fix, and not a design flaw!!!
Embrace success, don't condemn it.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Problem displaying tiles, only showing up as dots.
« Reply #1 on: February 25, 2012, 09:42:51 am »
I didn't read everything but I already see several mistakes.

1. Why do you create several smaller textures from your big one, instead of playing with the TextureRect property of sprites?

2. Never call a destructor explicitely.

3. That's a lot of code but the bug is probably in the texture manager parts that are not shown here... The problem is (probably) that the textures that you assign to your sprites are destroyed; they must live as long as the sprites use them.
Laurent Gomila - SFML developer

Stormblessed

  • Newbie
  • *
  • Posts: 6
    • View Profile
Problem displaying tiles, only showing up as dots.
« Reply #2 on: February 25, 2012, 04:48:37 pm »
Quote from: "Laurent"

1. Why do you create several smaller textures from your big one, instead of playing with the TextureRect property of sprites?

Oh cool, I didn't know about that.  I'll implement that once I figure out why it's not drawing.

Quote from: "Laurent"

2. Never call a destructor explicitely.

Sounds good, I'll be removing that...

Quote from: "Laurent"

3. That's a lot of code but the bug is probably in the texture manager parts that are not shown here... The problem is (probably) that the textures that you assign to your sprites are destroyed; they must live as long as the sprites use them.


There isn't much else in TextureManager but I'll post the remaining bits because you sounded exasperated:
Code: [Select]
#include "GlobalHeaderFile.h"

using namespace std;

TextureManager::TextureManager(void)
{
}

TextureManager::~TextureManager(void)
{
}

void TextureManager::addTextureByFile(string fileName)
{
sf::Texture textureAdd;

if(!textureAdd.LoadFromFile(fileName))
{
cout << "Error loading image, TextureManager addImageByFile function\n";
}

textureList.push_back(textureAdd);
}

void TextureManager::addTextureFromData(sf::Texture textureAdd)
{
textureList.push_back(textureAdd);
}

void TextureManager::loadTextureMap(string fileName)
{
sf::Image imageLoad;

if(!imageLoad.LoadFromFile(fileName))
{
cout << "Error loading image, TextureManager addImageByFile function\n";
}

for(int i = 1; i <= 6; i++)
{
for(int k = 1; k <= 6; k++)
{
sf::Texture tempTexture;

tempTexture.LoadFromImage(imageLoad, sf::IntRect(((k-1)*48),((i-1)*48),48,48));
addTextureFromData(tempTexture);

}
}
}

void TextureManager::removeTexture(int index)
{
textureList.erase(textureList.begin() + (index - 1));
}

sf::Texture& TextureManager::getTexture(int index)
{
return textureList[index];
}


I feel like the error is most likely in the Room.cpp, in the assignTileSprites function, because according to the debugger the sprites aren't retaining their textures, so they must have gotten deleted somewhere like you said.  I'm guessing that's somehow because they're getting removed at the end of that functions scope?  Or that the TextureManager I'm passing to the function isn't giving the Tiles the right Sprites or something...

Thanks for the help, I'm eternally grateful!

EDIT: Removing the destructor seems to have fixed the OpenGL error spam at closing, so that's good  :D
Embrace success, don't condemn it.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Problem displaying tiles, only showing up as dots.
« Reply #3 on: February 25, 2012, 05:18:33 pm »
Quote
you sounded exasperated

Uh? Where?

Quote
Code: [Select]
textureList.push_back(textureAdd);

When you add elements to a std::vector, elements already in it may move in memory because the vector needs more space. Therefore, any pointer to a texture stored in the vector is invalid after that.
Workarounds: use std::list (never moves elements in memory), or store pointers (so that pointers will move, but not the objects themselves), or assign the textures to the sprites after all the textures have been loaded.
Laurent Gomila - SFML developer

Stormblessed

  • Newbie
  • *
  • Posts: 6
    • View Profile
Problem displaying tiles, only showing up as dots.
« Reply #4 on: February 25, 2012, 05:33:13 pm »
Quote from: "Laurent"

Uh? Where?

Quote
but the bug is probably in the texture manager parts that are not shown here...


I probably misinterpreted you but I read that as exasperated, probably because of the "..."


Quote

Quote
Code: [Select]
textureList.push_back(textureAdd);

When you add elements to a std::vector, elements already in it may move in memory because the vector needs more space. Therefore, any pointer to a texture stored in the vector is invalid after that.
Workarounds: use std::list (never moves elements in memory), or store pointers (so that pointers will move, but not the objects themselves), or assign the textures to the sprites after all the textures have been loaded.


I believe I am assigning the textures to the sprites after all the textures have loaded.  Here's my order of operations:  
I run the TextureManager loadTextureMap function, which should add all of the necessary textures the vector.

After that is completely done I run the initializeRoom function for my Room which loads the tiles and blocks, and then runs the assignTileSprites function.

So the memory addresses of the Textures moving in TextureManager before I assign them to the Tiles shouldn't be the issue, right?


Sorry this is taking so long, I spent at least 4 hours trying different ways to fix it yesterday and I think I got the problem fairly isolated.  But I still have no idea what to do to fix it in the end.
Embrace success, don't condemn it.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Problem displaying tiles, only showing up as dots.
« Reply #5 on: February 25, 2012, 06:28:39 pm »
Quote
I probably misinterpreted you but I read that as exasperated, probably because of the "..."

I use "..." a lot, maybe too much. But it often means nothing special ;)

Quote
Code: [Select]
Tile getTile(int, int);
...
getTile(i, k).setSprite(textures.getTexture(0));

GetTile returns a copy, not the original tile. So you never modify any of the tiles that you actually draw. You should return a reference (Tile&).
Laurent Gomila - SFML developer

Stormblessed

  • Newbie
  • *
  • Posts: 6
    • View Profile
Problem displaying tiles, only showing up as dots.
« Reply #6 on: February 25, 2012, 07:28:40 pm »
http://imgbox.com/aafH3X7f

IT WORKS!!!  Thanks Laurent, that last thing you posted worked perfectly!  I'll focus on optimizing it now, would moving the part where I set the position of the tile out of the drawTile function speed things up?  I saw some people mention that in other threads when I was searching the forums for an answer.
Embrace success, don't condemn it.