Hello,
I'm developing a simple game that should works like a simpler pokemòn and obviously I'm using SFML.
The problem is that I've got the classic label of text that shows hp of the user and enemy but the updating of it (graphically talking) isn't updating every time, I mean the logic of the game works properly cause if i'm attacking with 60 and the enemy has got 240 hp it took 4 hit to be killed but the sf::Text I'm trying to draw does not update at every "run" of the program.
Here it is the code of the BattleLoop using it:(player and enemy are the pointer to the user and the enemy)
void BattleLoop(std::vector<Character*> *chrt, int ID){
Character *player = chrt->at(0);
Character *enemy = chrt->at(ID);
sf::Texture playerTexture, enemyTexture, battleTexture;
sf::Sprite playerSprite, enemySprite, battleSprite;
sf::Font font;
if (!font.loadFromFile("Lobster_1.3.otf"))
{
std::cout<< "failed to open font"<<std::endl;
}
sf::Text playerlife, enemylife; //<---this is the no updating thing!!
playerlife.setColor(sf::Color::Black);
enemylife.setColor(sf::Color::Black);
playerlife.setFont(font);
enemylife.setFont(font);
playerlife.setCharacterSize(20);
enemylife.setCharacterSize(20);
playerlife.setPosition(402, 200);
enemylife.setPosition(22, 10);
std::string playerpng = player->getType() + "battle.png";
if(!playerTexture.loadFromFile(playerpng))
std::cout<<"Error, could not load "<<playerpng<<std::endl;
playerSprite.setTexture(playerTexture);
playerSprite.setTextureRect(sf::IntRect(0,0,110,128));
playerSprite.setPosition(32,128);
std::string enemypng = std::to_string(enemy->getId()) + ".png";
if(!enemyTexture.loadFromFile(enemypng))
std::cout<<"Error, could not load "<<enemypng<<std::endl;
enemySprite.setTexture(enemyTexture);
enemySprite.setPosition(32*11,50);
bool enemyatk = false;
sf::RenderWindow window2(sf::VideoMode(32*16, 32*8), "Battle!!");
std::ostringstream playerlifeConv; //I use this to convert the int (life) to string and then in Text
playerlifeConv << "hp: " << player->getLife();
playerlife.setString(playerlifeConv.str());
std::ostringstream enemylifeConv;
enemylifeConv << "hp: " << enemy->getLife();
enemylife.setString(enemylifeConv.str());
sf::Event events;
while (window2.isOpen()){
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
//putting a lot of those method updateLife to prove that's not the problem
window2.clear();
window2.draw(playerSprite);
window2.draw(enemySprite);
window2.draw(playerlife);
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
window2.draw(enemylife);
window2.display();
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
while (window2.pollEvent(events)){
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
if(events.type == sf::Event::Closed){
window2.close();
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)){
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
window2.close();
}
if (events.type == sf::Event::KeyReleased) {//this is how I attack the enemy
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
if (events.key.code==sf::Keyboard::Space) {
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
enemy->reduceLife(player->getAttack()); //this is working!!
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
enemyatk=true;
if (enemy->getLife()<=0) {
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
chrt->erase(chrt->begin()+ID);
enemyatk=false;
window2.close();
}
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
if (enemyatk) {
player->reduceLife(enemy->getAttack());
enemyatk = false;
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
}
if (player->getLife()<=0) {
chrt->erase(chrt->begin());
window2.close();
}
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
}
}
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
window2.clear();
window2.draw(playerSprite);
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
window2.draw(enemySprite);
window2.draw(playerlife);
updateLife(playerlifeConv, enemylifeConv, player, enemy, &playerlife, &enemylife);
window2.draw(enemylife);
window2.display();
}//eventloop
}//gameloop
}
bool collision (sf::Vector2f vp1, sf::Vector2f vp2){ //metodo per collisioni con nemici, se ci troviamo in un raggio di 4px
float a=fabs(vp1.x-vp2.x); //fabs fa il valore assoluto
float b=fabs(vp1.y-vp2.y);
if (a<4 && b<4) {
return true;
}
return false;
}
void updateLife(std::ostringstream &pl,std::ostringstream &el, Character *p, Character *e, sf::Text *et, sf::Text *ee){
pl.clear();
pl.str("");
pl << "hp: " << p->getLife();
et->setString(pl.str());
el.clear();
el.str("");
el << "hp: " << e->getLife();
ee->setString(el.str());
}
I hope to be clear.
Thankyou(sorry for bad english)
replace std::ostringstream with std::sstringstream 'o' means output, so std::ostringstream doesn't work as excepted
Seriously?
The right (C++11) way of doing it, is std::to_string. If you still want to use std::ostringstream, then don't reuse instances.
void updateLife(Character *p, sf::Text *t){
t->setString("hp: " + std::to_string(p->getLife()));
}
// OU...
void updateLife(Character *p, sf::Text *t){
std::ostringstream oss;
oss << "hp: " << p->getLife();
t->setString(pl.str());
}
Then show a complete and minimal code that reproduces the problem. Your original code is so cluttered with these duplicated calls everywhere, that it's hard to know what really happens.
Then Laurent here it is a complete code, the problem is that it works in this very simple way. Hope you can understand it now.
#include <SFML/Audio.hpp>
#include <SFML/Graphics.hpp>
#include <unistd.h>
#include <iostream>
#include <stdio.h>
void updateLife(int *p, int *e, sf::Text *et, sf::Text *ee){
et->setString("hp: " + std::to_string(*p));
ee->setString("hp: " + std::to_string(*e));
}
void reduceLife( int attack, int &life){
life-=attack;
}
int main(int, char const**)
{
int playerhp = 60;
int playeratk = 60;
int enemyhp = 240;
int enemyatk = 10;
sf::Font font;
if (!font.loadFromFile("Lobster_1.3.otf"))
{
std::cout<< "failed to open font"<<std::endl;
}
sf::Text playerlife, enemylife;
playerlife.setColor(sf::Color::White);
enemylife.setColor(sf::Color::White);
playerlife.setFont(font);
enemylife.setFont(font);
playerlife.setCharacterSize(20);
enemylife.setCharacterSize(20);
playerlife.setPosition(402, 200);
enemylife.setPosition(22, 10);
bool attackable = false;
sf::RenderWindow window2(sf::VideoMode(32*16, 32*8), "Battle!!");
sf::Event events;
while (window2.isOpen()){
updateLife(&playerhp, &enemyhp, &playerlife, &enemylife);
window2.clear();
window2.draw(playerlife);
window2.draw(enemylife);
window2.display();
while (window2.pollEvent(events)){
if(events.type == sf::Event::Closed){
window2.close();
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)){
window2.close();
}
if (events.type == sf::Event::KeyReleased) {
if (events.key.code==sf::Keyboard::Space) {
reduceLife(playeratk, enemyhp);
updateLife(&playerhp, &enemyhp, &playerlife, &enemylife);
enemyatk=true;
if (enemyhp<=0) {
enemyatk=false;
window2.close();
}
if (enemyatk) {
reduceLife(enemyatk, playerhp);
updateLife(&playerhp, &enemyhp, &playerlife, &enemylife);
enemyatk = false;
}
if (playerhp <= 0) {
window2.close();
}
}
}
window2.clear();
window2.draw(playerlife);
window2.draw(enemylife);
window2.display();
}//eventloop
}//gameloop
return EXIT_SUCCESS;
}
So I want this logic, and sometimes it works in my original code, but not every time how is supposed to happen..