SFML community forums

Help => Graphics => Topic started by: packetpirate on November 25, 2013, 04:41:12 pm

Title: Unknown problem with drawing.
Post by: packetpirate on November 25, 2013, 04:41:12 pm
I'm having some trouble with drawing tiles from a tile engine I'm working on. I'm honestly not sure if it's just a fluke, or if there's something causing it, but I wrote a quick and dirty level generator that isn't meant to actually generate anything special... it's just meant to show random tiles so I can play around with the tiles themselves. The problem, however, is that sometimes, I'll get tiles that half-appear, or appear to push other tiles over a random number of pixels.

This only seems to happen after I re-generate the level 5+ times, but hey... it's random, so who knows, right?

So is there something I'm doing wrong here?

SFMLApp.h: http://pastebin.com/67LNpf9V
SFMLApp.cpp: http://pastebin.com/NrjQKSKz
Level.h: http://pastebin.com/Ve4FET96
Level.cpp: http://pastebin.com/60WXYBfA
Tile.h: http://pastebin.com/DSU6C5xM
Tile.cpp: http://pastebin.com/C5eG5q6J

Seems like a lot of code to ask you to review, but really all you should need to look at is the GenerateLevel() method of the SFMLApp class and the Tile class' constructor and Draw() method. I just included the rest in case you need to see how I'm handling something specific.

I've attached some screenshots of the problem itself. All tiles should be the same distance from each other... 48 px, and if you'll notice, some of the tiles are pushed over slightly, or the tile's image itself will even be cut off.

Can anyone take a guess as to what's causing this?
Title: Re: Unknown problem with drawing.
Post by: Nexus on November 25, 2013, 05:25:26 pm
bool turn = (((rand() % 20) + 1) > 9);
xDir = ((((cX + xDir) >= 0) && ((cX + xDir) < this->level->GetWidth()))?xDir:-xDir);
 
When you write code like that, I'm not surprised you don't understand it...

If you just want a random amount of tiles to be filled, this can be done much simpler. What random pattern do you want to use exactly? Let's rewrite it from scratch, that's faster.

Also, there are a lot of other questionable things in your code that are certain to create problems in the long term. I really suggest to fix those things, as they will turn maintenance into hell as soon as the project grows. For example:
Title: Re: Unknown problem with drawing.
Post by: packetpirate on November 25, 2013, 05:48:57 pm
bool turn = (((rand() % 20) + 1) > 9);
xDir = ((((cX + xDir) >= 0) && ((cX + xDir) < this->level->GetWidth()))?xDir:-xDir);
 
When you write code like that, I'm not surprised you don't understand it...

If you just want a random amount of tiles to be filled, this can be done much simpler. What random pattern do you want to use exactly? Let's rewrite it from scratch, that's faster.

Also, there are a lot of other questionable things in your code that are certain to create problems in the long term. I really suggest to fix those things, as they will turn maintenance into hell as soon as the project grows. For example:
  • Global variables
  • Manual memory management. In modern C++, you don't need new and delete! RAII (http://en.sfml-dev.org/forums/index.php?topic=9359.msg63566) is the keyword here.
  • Init/Cleanup functions instead of constructors and destructors
  • Arrays -> use std::array
  • Unnecessary include files (#include <SFML/Graphics.hpp> increases compile time unnecessarily)
  • Undefined behavior (this->tiles[r][c].~Tile(); -- you may not call destructors explicitly), there's probably more UB
  • No const-correctness (getters such as GetWidth() should be const-qualified)
  • Useless virtual destructors although you don't have polymorphism
  • Disregarded rule of three/five

First of all, I understand everything in that snippet you posted. Second, it has been a while since I've used C++. I've been focusing on Java for a couple years, so I'm get re acclimated to pointers. Third,  what global variables?

As for the "unnecessary" include files... what's unnecessary about them? I can't very well use an SFML class without including the appropriate header... and yes, the Init() method, rather than a constructor was necessary... how else do you expect me to return a boolean value to tell the Execute() method whether or not the window was properly initialized?

And finally, as for the random level generation, I don't have anything specific in mind. The only algorithm I've looked at so far is BSP generation, but I don't really understand that yet. One thing at a time.
Title: Re: Unknown problem with drawing.
Post by: Sqasher on November 25, 2013, 08:03:17 pm
Third,  what global variables?

Line 7 in SFMLApp.cpp:
TextureManager* SFMLApp::textureManager = new TextureManager();

As for the "unnecessary" include files... what's unnecessary about them? I can't very well use an SFML class without including the appropriate header...

Just include what you need. If you need the RenderWindow, you include <SFML/Graphics/RenderWindow.hpp>. If you need a Sprite, you include <SFML/Graphics/Sprite.hpp> and so on.

It makes the include part look longer and it takes time getting used to, but it speeds up the building process.

and yes, the Init() method, rather than a constructor was necessary... how else do you expect me to return a boolean value to tell the Execute() method whether or not the window was properly initialized?

Exceptions (http://www.cplusplus.com/doc/tutorial/exceptions/)

But back to the topic:
Try to print out the scale, position and size of the tile your mouse is hovering over or even put the whole tilemap into a text file. Then investigate which variable is wrong. I could even imagine that there are tiles with no texture over the actual tiles.

P.S.: Nexus is right, your map generation algorithm is short, but complex and error-prone. Look here (http://pcg.wikidot.com/pcg-algorithm:dungeon-generation) or here (http://www.futuredatalab.com/proceduraldungeon/) for some ideas.
Title: Re: Unknown problem with drawing.
Post by: packetpirate on November 26, 2013, 12:38:56 am
Third,  what global variables?

Line 7 in SFMLApp.cpp:
TextureManager* SFMLApp::textureManager = new TextureManager();

As for the "unnecessary" include files... what's unnecessary about them? I can't very well use an SFML class without including the appropriate header...

Just include what you need. If you need the RenderWindow, you include <SFML/Graphics/RenderWindow.hpp>. If you need a Sprite, you include <SFML/Graphics/Sprite.hpp> and so on.

It makes the include part look longer and it takes time getting used to, but it speeds up the building process.

and yes, the Init() method, rather than a constructor was necessary... how else do you expect me to return a boolean value to tell the Execute() method whether or not the window was properly initialized?

Exceptions (http://www.cplusplus.com/doc/tutorial/exceptions/)

But back to the topic:
Try to print out the scale, position and size of the tile your mouse is hovering over or even put the whole tilemap into a text file. Then investigate which variable is wrong. I could even imagine that there are tiles with no texture over the actual tiles.

P.S.: Nexus is right, your map generation algorithm is short, but complex and error-prone. Look here (http://pcg.wikidot.com/pcg-algorithm:dungeon-generation) or here (http://www.futuredatalab.com/proceduraldungeon/) for some ideas.

That's not a global variable... that's a static member of the SFMLApp class.
As for the includes, I'll do that. I didn't realize you could include sub-classes from those packages.
Title: Re: Unknown problem with drawing.
Post by: eXpl0it3r on November 26, 2013, 01:00:03 am
That's not a global variable... that's a static member of the SFMLApp class.
Which in turn IS a global variable, since any object that knows the class can do SFMLApp::textureManager. ;)