I need some help with my SFML/C++ code in Visual C++ 2010 Express Edition. I am trying to get my text (livesLeft) to "You Win!" Before the program sleeps. This is making the player know that he won. But instead, the program goes right to sleep and changes the text right as it is closing, so you only see it change for a few milliseconds. I can't even read it.
bool play = true;
bool win = false;
bool touchFinish = false;
int lives = 3;
sf::Font arial;
if(arial.loadFromFile("Fonts/arial.ttf") == 0)
{
return 1;
}
sf::Text livesLeft;
livesLeft.setFont(arial);
livesLeft.setCharacterSize(30);
livesLeft.setString("Lives: ");
livesLeft.setPosition(0, 0);
livesLeft.setColor(sf::Color::White);
sf::RectangleShape finish;
finish.setSize(sf::Vector2f(200, 600));
finish.setPosition(700, 0);
finish.setFillColor(sf::Color::Green);
Those are my variables in use and this is my code where I'm trying to change the text:
if(player.getGlobalBounds().intersects(finish.getGlobalBounds()))
{
livesLeft.setString("You Win!");
touchFinish = true;
}
if(touchFinish)
{
win = true;
}
if(win)
{
Sleep(5000);
play = false;
}
I also forgot to add in that I do have the rendering at the end:
window.clear();
window.draw(livesLeft);
window.draw(finish);
window.draw(player);
window.draw(obs1);
window.draw(obs2);
window.draw(obs3);
window.draw(obs4);
window.draw(obs5);
window.draw(obs6);
window.draw(obs7);
window.draw(obs8);
window.draw(obs9);
window.draw(obs10);
window.draw(obs11);
window.draw(obs12);
window.draw(obs13);
window.display();
This is most likely due to the fact that you aren't calling the display method for you window. Telling the text to change simply prepares the next framebuffer to display the new text, but because you never tell the window to update its display before sleeping, it never displays the new framebuffer.
Here is a quick example of a simple program using SFML. Notice the window.display() method at the end of the main game loop.
You effectively want to be doing this:
if(win)
{
window.display();
Sleep(5000);
play = false;
}
The reason why you need to update the display before hand again is because Sleep(5000); blocks the thread, essentially meaning that it sits at that call for 5000ms. Also, if you want to keep the previous items on the screen, you'll want to redraw those before window.display(); as well, since these won't be in the next framebuffer.
Related
this is my first post here.
I am trying to solve a problem I am having with my SFML project where I am using multiple clients, that communicate through texts that can be typed in the rendered window and then sent to the other sockets using a selector.
My problem is that everytime i press one button of the keyboard, the window detects like 3 or 4, and if I try it on another machine, the behaviour changes.
I tried almost every solution, including the setKeyRepeatEnabled(false);
This is the update function
void Client::Update(Input* input,sf::Event& Ev, sf::Font& font, sf::RenderWindow& window)
{
if (input->isKeyDown(sf::Keyboard::Return))
{
sf::Packet packet;
packet << id + ": " + text;
socket.send(packet);
sf::Text displayText(text, font, 20);
displayText.setFillColor(sf::Color::Red);
chat.push_back(displayText);
text = "";
input->setKeyUp(sf::Keyboard::Return);
}
else if (input->isKeyDown(sf::Keyboard::Backspace))
{
if (text.size() > 0)
text.pop_back();
}
else if (input->isKeyDown(sf::Keyboard::Space))
{
text += ' ';
}
else if (Ev.type == sf::Event::TextEntered)
{
text += Ev.text.unicode;
return;
}
//sf::Event::TextEntered
//text += Ev.text.unicode;
}
This is the render one.
void Client::Render(sf::Font& font, sf::RenderWindow& window)
{
sf::Packet packet;
socket.receive(packet);
std::string temptext;
if (packet >> temptext)
{
sf::Text displayText(temptext, font, 20);
displayText.setFillColor(sf::Color::Blue);
chat.push_back(displayText);
}
int i = 0;
for (i; i < chat.size(); i++)
{
chat[i].setPosition(0, i * 20);
window.draw(chat[i]);
}
sf::Text drawText(text, font, 20);
drawText.setFillColor(sf::Color::Red);
drawText.setPosition(0, i * 20);
window.draw(drawText);
}
I don't recognize the isKeyDown function as part of SFML, so I assume you either is something you implemented or is part of a previous version of SFML (being the current 2.5.1).
There are three ways to detect input from keyboard in SFML.
sf::Keyboard::isKeyPressed: looks like this is the one you are using. It will be true every cycle that the key is pressed. You definetly don't want this. The window.setKeyRepeatEnabled(false) will obviously not work because you don't get the input through the window, but directly from the keyboard.
sf::Event::KeyPressed and sf::Event::KeyReleased events: for this, window.setKeyRepeatEnabled(false) will work, but still it's not the recommended way to deal with text input, as it would require a lot of juggling by your side to handle key combinations (accents, uppa.
sf::Event::TextEntered event: now, this is the best and recommended way to handle typing. Check the tutorial to see how to use it.
The code I've written displays the sf::Drawable objects only for the top state of the state stack. Rendering works fine for everything, except the sf::Text type, that does not change the color of the text when button.getText().setFillColor(sf::Color:Red) is called. However, when I construct a button with a red text, whenever I try to set another color to that button, I only get a white text, no matter what color I request.
Here's where I change the color of a button:
void GameState_MainMenu::handleRealTimeInput()
{
for each (TextButton button in mButtons)
{
if (button.isSpriteClicked())
{
button.getText().setFillColor(sf::Color::Red);
button.triggerAction();
sf::Clock wait;
sf::Time timer = sf::Time::Zero;
timer = sf::seconds(0.15f);
while (wait.getElapsedTime() < timer)
{
}
wait.restart();
}
}
}
and this is my Game::render() method:
void Game::render()
{
GameState *currentState = getActiveState();
if (currentState != nullptr)
{
mWindow.clear();
currentState->draw();
}
mWindow.display();
}
Lastly, this is the draw method of the MainMenu state:
void GameState_MainMenu::draw()
{
game->mWindow.draw(game->mBackground);
game->mWindow.draw(mSelector.mSprite);
for each (TextButton button in mButtons)
{
game->mWindow.draw(button.getText());
}
}
It's probably because you have a while loop in the GameState_MainMenu::handleRealTimeInput that the program is getting stuck in.
You can try to use threads, though that way could get pretty messy. I suggest revising your code.
Okay, so I figured out this had something to do with c++'s for each instruction. As soon as I switched to the classic array-like traversal, my buttons started changing colors. I'm not saying this is THE solution, just that it worked for me. If anyone has the same problem, you might want to check that.
I am not too familiar with the performance of QGraphicsScene and QGraphicsView.. I know that there is a 10 000 chips example which works well and that the QGraphicsScene is optimized for having a large amount of items in it. However, the game I made lags.( I need to note that this is my first game which actually could be called as such )
My mainloop processing looks like this:
timer.setInterval(0);
timer.start();
connect(&timer, SIGNAL(timeout()), this, SLOT(mainloop()));
inside this mainloop I update all my game logic. Everything seems to be ok, but once I go to fullscreen and I have about 100+ Items in the scene..it starts to lag and the completion of the mainloop takes (sometimes) more than 33ms. Besides the Player, I have only Objects of GameCollectable, you can see the update routine in the code below. Is this because I have my mainloop on the GUI Thread? Because every GameCollectable is rendered by an image? Should I try to make the mainloop in its own thread?
It would be really gentle of you, if someone could take a look at the update routine of my GameCollectable class and tell me why my code produces so much lag. I have a I5 2500K processor btw.
void GameCollectable::update(int t)
{
//animationstuff
if(t>lastframeupdate)
{
if(m_spawner!=NULL)
{
if(animindex>=m_spawner->animation_collectable_normal.get()->animationimgs.size()-1)
animindex=0;
m_graphicsitem->setImage( m_spawner->animation_collectable_normal.get()->getFrameImage(animindex));
lastframeupdate=t;
//animindex++;
}
}
if(started==false)starttime=t;
started=true;
move(t);
}
bool GameCollectable::move(int t)
{
float t_inc=(t-starttime)/animtime;
//reached our destination?
if(m_graphicsitem->pos().x()<destPos.x())
{
onDestination=true;
emit signal_reached(this);
return false;
}
//collided with player?
else if(m_graphicsitem->collidesWithItem(Game::GameManager::instance()->getPlayer()->getGraphicsItem()))
{
Game::SoundManager::instance()->playCoinPickup(t);
bumpedPlayer=true;
emit signal_bumped(this);
return false;
}
else
{
m_graphicsitem->setPos(lerp(startPos.x(),destPos.x(),t_inc),m_graphicsitem->pos().y());
return true;
}
return false;
}
I have an OpenGL project which loads an object file, after the object is loaded i want to be able to move it with keyboard smoothly, so i wrote this block of code to do the job:
while (remains) {
if (x_remains) {
refPosition[0] += speed.x;
if (refPosition[0] > nextPos[0]) {
x_remains = false;
}
}
if (y_remains) {
refPosition[1] += speed.y;
if (refPosition[1] > nextPos[1]) {
y_remains = false;
}
}
if (z_remains) {
refPosition[2] += speed.z;
if (refPosition[2] >= nextPos[2]) {
z_remains = false;
}
}
remains = x_remains || y_remains || z_remains;
glutPostRedisplay();
}
as you see I want to redisplay the scene in the while but when this is executed glutpostredisplay() just sets a flag and the scene is redrawn in the next iteration of the mainloop. my question is how can I redraw the scene before next loop of the while and before the function returns
You won't lose performance or see jerky rendering by going through glutPostRedisplay instead of drawing directly. (Or, if every microsecond really is that precious, why the heck are you using GLUT to begin with?)
On some systems you CAN'T draw outside the display function anyway, because the GL context won't be valid.
This is not unique to GLUT either. All the modern graphics/GUI toolkits I'm familiar with also require you to have a designated display function that gets invoked by an event handler, whether it's WM_PAINT messages, NSView drawRect:, or whatever.
If your program is not updating smoothly, it will be for some other reason.
I have made a game in OpenGL, and also have added a menu item. when I right click on the OpenGL Screen, the menu item is displayed and I have added an option "Reset Game" in it. How Can I clear all the variables involved in the game by clicking on this (Any clear or flush function?).
Here is my code
glutCreateMenu(menu);
glutAddMenuEntry("Reset Game", 1);
void menu(int item)
{
switch (item)
{
case 1:
{
//Adding a function here to clear all the variables
}
break;
}
}
You just need to code up the routine to reset all your variables to their default values.
void Reset()
{
score = 0;
lives = 3;
// etc.
}
OpenGL doesn't know what these are so you have to do it yourself.