Sign in to follow this  
Protomin

How can I have SDL show a variable on the screen?

Recommended Posts

I just started learning SDL a while ago, so I don't know much about it, but how could I have it show a number on a screen that is going to keep on changing. To be more specific, I'm trying to make Pong right now. I have everything done except for it showing the score at the top. How would I do that? I'm following LazyFoo's tutorials right now, and to show text on the screen he says to do this:
message = TTF_RenderText_Solid( font, "The quick brown fox jumps over the lazy hound", textColor );
Then use your apply_surface message and apply 'message' to the screen. I tried doing that but instead of putting text for the second argument, I just put the variable where I have the score at. But that didn't work. So what is an easy way to do this? I would just have it blit a new surface on the screen each having a different number where the text goes, but that is big, long and complicated. Plus later on if I tried to make another game with a more complicated scoring system, that way wouldn't really work... So I'd rather learn how to do it the good way now. >___>

Share this post


Link to post
Share on other sites
I'm assuming C++ since you didn't specify. There are ways of achieving this in C too.

You are familiar with std::cout and std::cin? The Standard C++ Library comes with a number of other useful iostream classes that can be used in the same way. You might know fstreams, which allow us to read and write to files.

The important one in this situation is stringstream. It does exactly what it says, it treats a memory string as something we can read and write from.


#include <sstream>

// turn an int into a string
std::string example_toString( int x )
{
std::stringstream stream;
stream << x;
std::string retval;
stream >> retval;
return retval;
}



We can improve on this, as std::stringstream has a member function str() which returns a string object:

#include <sstream>

// turn an int into a string
std::string example_toString( int x )
{
std::stringstream stream;
stream << x;
return stream.str();
}



A generic to string using C++ templates can be written. This can turn any object which has overloaded the stream insertion operators to be turned into a string easily.

#include <sstream>

template< class Type >
std::string generic_toString( const Type &instance )
{
std::stringstream stream;
stream << instance;
return stream.str();
}



However, what if we want the reverse? A string to an int perhaps. Or even a user defined type such as Foo? We can improve once more:

#include <sstream>

template< class In, class Out >
Out generic_to( const In &in )
{
std::stringstream stream;
stream << instance;
Out retval;
stream >> retval;
return retval;
}



We would write generic_to<Foo>("Hello") to use this.

I have purposely not included error checking. We should really be using boost::lexical_cast, which is similar in spirit to the above but will throw an exception to handle errors.

Enough of the rambling you say.

We can use std::stringstream to create a string suitable for use with SDL_TTF. Lets assume you want the Frames per second and the frame time.

std::stringstream stream;
stream << "FPS: " << fps << " Frame Draw Time: " << frameTime;
// stream.str() returns a std::string, we need to call c_str() to get the
// const char * that SDL_TTF expects
message = TTF_RenderText_Solid( font, stream.str().c_str(), textColor );
// blit!

Share this post


Link to post
Share on other sites
All right thanks, and yeah I'm programming with C++. I guess I forgot about that.

Edit: I got SDL_ttf to work but I'm probably not understanding how to do the scoring thing I want.

So at the top of my code I put:

SDL_Surface* score = NULL;
TTF_Font *font = NULL;
SDL_Color textColor = { 255, 255, 255 };
std::stringstream ScoreS;

int sX = 50, sY = 0; //x,y values of where i'm going to put the score
int p1s = 0, p2s = 0; //vars where the score goes



then in the main loop of the main function I have:

stream<< p1s << "  " << p2s;
score = TTF_RenderText_Solid( font, ScoreS.str().c_str(), textColor );
if ( score == NULL ) {
return 1;
}
apply_surface( sX, sY, score, screen );
if ( SDL_Flip(screen) == -1 ) {
return 1;
}



When I run the program, It puts "0 0" at 50,0 but then it repeats it over and over so the top of the screen looks like "0 00 00 00 00 00" and so on. Also, when the ball hits the edge of the screen I have p1s += 1;
But when it actually hits the edge, nothing happens to the score at the top, it just stays 0 all over the place. After a while it will close and return a value of 1.

I found out that it quits because of the first if statement I post in this post. But when I run it, I get the score to appear on the screen, so how does it become NULL later on?

[Edited by - Protomin on October 12, 2007 9:05:51 PM]

Share this post


Link to post
Share on other sites
It looks like you're just appending to the end of the string each time. Wouldn't you need to "reset" the score string so that it holds on the new value?

Share this post


Link to post
Share on other sites
Quote:
Original post by Maxamor
It looks like you're just appending to the end of the string each time. Wouldn't you need to "reset" the score string so that it holds on the new value?


Exactly. But instead of "resetting", it would be better to declare a new stringstream only where it will be used.

SDL_Surface* score = NULL;
TTF_Font *font = NULL;
SDL_Color textColor = { 255, 255, 255 };
// remove the stream declaration here
//std::stringstream ScoreS;

int sX = 50, sY = 0; //x,y values of where i'm going to put the score
int p1s = 0, p2s = 0; //vars where the score goes

while(running)
{
// stuff here

std::stringstream scores;
scores << p1s << " " << p2s;
score = TTF_RenderText_Solid( font, scores.str().c_str(), textColor );
if ( score == NULL ) {
return 1;
}
apply_surface( sX, sY, score, screen );

// we should free the "score" surface here
// to prevent memory leaks
SDL_FreeSurface(score);


if ( SDL_Flip(screen) == -1 ) {
return 1;
}

}



However, allocating a new surface every frame is expensive and unnecessary if the scores aren't changing. We could change the logic such that we only re-create the surface when the score changes.

Here is a simple example (simple in that I assume there is only 1 place in the code a player's score is updated:



// outside main() or any other function
SDL_Color textColor = { 255, 255, 255 };

SDL_Surface *createScoreSurface( Font *font, int player1Score, int player2Score )
{
std::stringstream scores;
scores << player1Score << " " << player2Score;
SDL_Surface *score = TTF_RenderText_Solid( font, scores.str().c_str(), textColor );
if ( score == NULL ) {
std::cerr << "Couldn't create score surface: " << TTF_GetError() << '\n';
// handle error someway?
throw std::runtime_error("TTF_RenderText_Solid() failed");
}
return score;
}


int main(int, char**)
{
// initialise SDL etc


TTF_Font *font = NULL;


int sX = 50, sY = 0; //x,y values of where i'm going to put the score
int p1s = 0, p2s = 0; //vars where the score goes

SDL_Surface* score = createScoreSurface( font, p1s, p2s );

while(running)
{
// update game here

if( player1.wins() )
{
p1s++;
SDL_FreeSurface(score);
score = createScoreSurface( font, p1s, p2s );
}

if( player2.wins() )
{
p2s++;
SDL_FreeSurface(score);
score = createScoreSurface( font, p1s, p2s );
}


apply_surface( sX, sY, score, screen );


if ( SDL_Flip(screen) == -1 ) {
return 1;
}
}
// we should free the "score" surface here
// to prevent memory leaks
SDL_FreeSurface(score);

// free everything else
}



[Edited by - rip-off on October 13, 2007 6:58:56 AM]

Share this post


Link to post
Share on other sites
Ah all right thanks. I'm just used to putting declarations outside of functions so I can use them anywhere. But now it looks like I realized that isn't always a good idea.

Anyways thanks again, I got Pong finished! It's a little buggy when the ball hits a paddle, but thats just because I'm too lazy to make the detection and all that perfect. And the computer is pretty stupid, but again thats just because I'm lazy and it works the way it is. >____>

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this