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

Author Topic: Text Strangeness  (Read 2353 times)

0 Members and 1 Guest are viewing this topic.

gamecreator

  • Newbie
  • *
  • Posts: 17
    • View Profile
Text Strangeness
« on: April 23, 2018, 01:35:37 am »
I think I'm not understanding how text is supposed to be properly displayed.  This is my current code, trying to show 3 lines of information.

Quote
   
   std::stringstream buff3, buff4, buff5;
   buff3.clear(); buff4.clear(); buff5.clear();

   text.setFillColor(sf::Color::White);
   buff3<<"Lives: "<<lives;
   text.setString(buff3.str());
   text.setPosition(1000,0);
   window.draw(text);

   text.setFillColor(sf::Color::White);
   buff4<<"Level: "<<levelnumber;
   text.setString(buff4.str());
   text.setPosition(1000,50);
   window.draw(text);

   text.setFillColor(sf::Color::White);
   buff5<<"Flips: "<<flipsremaining;
   text.setString(buff5.str());
   text.setPosition(1000,100);
   window.draw(text);

The strange thing is that when I change a position, compile and run, it doesn't change the position on the screen.  If I change a color, it always changes and I think always then fixes the position.  Pretty sure I also don't need multiple stringstreams but using only 1 and clearing it didn't work either.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10823
    • View Profile
    • development blog
    • Email
Re: Text Strangeness
« Reply #1 on: April 23, 2018, 07:57:17 am »
stringstream::clear() doesn't do what you expect, check a C++ reference.
With C++11 we have a better tool for that job anyways: std::to_string()

Changing the position should work fine.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

gamecreator

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Text Strangeness
« Reply #2 on: April 23, 2018, 08:58:19 pm »
Thank you.  I made changes thanks to your suggestion which simplified the code (I don't know how to use to_string yet so I skipped that for now).

I also made a video demonstrating the strangeness I mentioned earlier:

Maybe I'm doing something wrong but if so, I don't understand what.  Why would positions not update until you change a color?  I also tried changing just the position multiple times, compiling after each one, but that didn't do anything.  I wonder if maybe Visual Studio thinks that the code didn't change for some reason and so it doesn't update it.

I can provide the entire project but I don't need anyone to look at this.  I'm finished with the project (and I have that workaround anyway).
« Last Edit: April 23, 2018, 09:00:42 pm by gamecreator »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10823
    • View Profile
    • development blog
    • Email
Re: Text Strangeness
« Reply #3 on: April 23, 2018, 09:12:25 pm »
So what's the full code?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

gamecreator

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Text Strangeness
« Reply #4 on: April 23, 2018, 10:13:54 pm »
main.cpp
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include "world.h"

int main()
{
        initializegame();
        generatecurrentlevel(levelnumber);

        while(window.isOpen() && !sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
        {
                while(window.pollEvent(event))
                        if(event.type == sf::Event::Closed) window.close();

                think();
                drawlevel();
                window.display();
        }

        return 0;
}
 

world.h
#ifndef WORLD_H
#define WORLD_H

#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>

#define CARDDOWN        0
#define CARDUP          1
#define FLAG            2
#define BOMB            3

extern sf::RenderWindow window;
extern sf::Event event;
extern sf::Font font;

extern sf::Texture itemstexture;

extern sf::Sprite itemssprite[10];

extern sf::SoundBuffer soundbuffer_cardflip, soundbuffer_explosion, soundbuffer_win;
extern sf::Sound sound_cardflip, sound_explosion, sound_win;

struct cardsshowing
{
        bool showing;
        int x, y;
};

extern cardsshowing cardshown[2];
extern int numberofcardsshowing;

extern sf::Clock myclock; //  Used for pausing for a second while two cards are shown

struct levelstruct
{
        bool bomb;

        //  Bomb has to be either flagged or otherwise revealed to count
        bool flag;
        bool bombrevealed;

        int surroundingbombsamount;

        int cardindex;
        bool cardfaceshowing;
        bool matched;
};

extern levelstruct level[100][100];

extern int lives;
extern int levelnumber;
extern int flipsremaining;
extern int setsof;
extern int numberofbombs;

extern int levelwidth, levelheight;
extern int xoffset;
extern int yoffset;
extern int xspacing;
extern int yspacing;

void think();
void initializegame();
void generatelevel(int width, int height, int numberofbombss, int setspertype, int nofflips);
void generatecurrentlevel(int which);
void drawlevel();
int countbombsat(int x, int y);
bool checkforwin();

#endif
 

world.cpp
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include "windows.h"
#include "world.h"

#include <iostream>             //  Used to convert float to string for draw(text)
#include <sstream>              //  Used to convert float to string for draw(text)

#include <vector>

sf::RenderWindow window;
sf::Event event;
sf::Font font;

sf::Texture itemstexture;

sf::Sprite itemssprite[10];

sf::Clock myclock;

sf::SoundBuffer soundbuffer_cardflip, soundbuffer_explosion, soundbuffer_win;
sf::Sound sound_cardflip, sound_explosion, sound_win;


int lives;
int levelnumber;
int flipsremaining;
int setsof;
int numberofbombs;

cardsshowing cardshown[2];
int numberofcardsshowing;

levelstruct level[100][100];

int levelwidth, levelheight;
int xoffset;
int yoffset;
int xspacing;
int yspacing;

bool leftmousedown, leftmousedownlastframe;
bool rightmousedown, rightmousedownlastframe;



void think()
{
        sf::Vector2i mousepos = sf::Mouse::getPosition(window);
        int cardx, cardy;

        if(sf::Mouse::isButtonPressed(sf::Mouse::Left)) leftmousedown=true;
        else leftmousedown=false;
        if(sf::Mouse::isButtonPressed(sf::Mouse::Right)) rightmousedown=true;
        else rightmousedown=false;

        bool overcard=false;
        if(mousepos.x>xoffset && mousepos.x<xspacing*(levelwidth-1)+64+xoffset)
                if(mousepos.y>yoffset && mousepos.y<yspacing*(levelheight-1)+94+yoffset)
                        if((mousepos.x-xoffset)%xspacing<64 && (mousepos.y-yoffset)%yspacing<94)
                        {
                                overcard=true;
                                cardx=(mousepos.x-xoffset)/xspacing;
                                cardy=(mousepos.y-yoffset)/yspacing;
                        }

        //  Set or clear flag
        if(!rightmousedown && rightmousedownlastframe && overcard)
        {
                level[cardy][cardx].flag=!level[cardy][cardx].flag;
        }

        //  Clicked on a bomb OR ran out of flips
        if(!leftmousedown && leftmousedownlastframe && overcard && level[cardy][cardx].bomb || flipsremaining<1)
        {
                lives--;
                if(lives<1)
                {
                        levelnumber=1;
                        lives=5;
                }
                generatecurrentlevel(levelnumber);
                sound_explosion.play();
        }
        //  Flip card
        //  MUST use "else if" here or above code will reset board and this code will cause a click
        else if(!leftmousedown && leftmousedownlastframe && overcard && numberofcardsshowing<2 && !level[cardy][cardx].matched && !level[cardy][cardx].bomb)
        {
                level[cardy][cardx].cardfaceshowing=!level[cardy][cardx].cardfaceshowing;

                if(level[cardy][cardx].cardfaceshowing)
                {
                        cardshown[numberofcardsshowing].x=cardx;
                        cardshown[numberofcardsshowing].y=cardy;
                        cardshown[numberofcardsshowing].showing=true;
                        numberofcardsshowing++;  //  We turned a card face up

                        if(numberofcardsshowing>1)  //  We have two cards up.  Start the clock for a second until they both flip back automatically
                        {
                                myclock.restart();
                        }

                        flipsremaining--;
                }
                else numberofcardsshowing--;  //  We turned a card back face down

                sound_cardflip.play();
        }

        if(checkforwin())
        {
                levelnumber++;
                generatecurrentlevel(levelnumber);
                sound_win.play();
        }

        //  Check for match
        if(numberofcardsshowing>1 && level[cardshown[0].y][cardshown[0].x].cardindex==level[cardshown[1].y][cardshown[1].x].cardindex)
        {
                //  MATCH!!
                //  Uncover all cards with the same number
                int matchnumber=level[cardshown[0].y][cardshown[0].x].cardindex;
                for(int j=0; j<levelheight; j++)
                {
                        for(int i=0; i<levelwidth; i++)
                        {
                                if(level[j][i].cardindex==matchnumber) level[j][i].matched=true;
                        }
                }
        }

        //  Flip cards back if enough time passed
        sf::Time elapsed = myclock.getElapsedTime();
        if(numberofcardsshowing>1 && elapsed.asMilliseconds()>400)
        {
                level[cardshown[0].y][cardshown[0].x].cardfaceshowing=false;
                level[cardshown[1].y][cardshown[1].x].cardfaceshowing=false;
                cardshown[0].showing=false;
                cardshown[1].showing=false;
                numberofcardsshowing=0;
        }

        leftmousedownlastframe=leftmousedown;
        rightmousedownlastframe=rightmousedown;
}

void drawlevel()
{
        std::stringstream buff;
        int i, j;

        window.clear();

        sf::Text text;
        text.setFont(font);
        text.setCharacterSize(36);


        for(j=0; j<levelheight; j++)
        {
                for(i=0; i<levelwidth; i++)
                {
                        if(level[j][i].cardfaceshowing && !level[j][i].matched)
                        {
                                itemssprite[CARDUP].setPosition(i*xspacing+xoffset, j*yspacing+yoffset);
                                window.draw(itemssprite[CARDUP]);
                        }
                        else if(!level[j][i].matched)
                        {
                                itemssprite[CARDDOWN].setPosition(i*xspacing+xoffset, j*yspacing+yoffset);
                                window.draw(itemssprite[CARDDOWN]);
                        }

                        if(level[j][i].bomb)
                        {
                                itemssprite[BOMB].setPosition(i*xspacing+xoffset, j*yspacing+yoffset);
//                              window.draw(itemssprite[BOMB]);
                        }

                        if(level[j][i].flag)
                        {
                                itemssprite[FLAG].setPosition(i*xspacing+xoffset, j*yspacing+yoffset);
                                window.draw(itemssprite[FLAG]);
                        }

                        //  All this just to show card number on screen
                        text.setFillColor(sf::Color::Black);
                        buff.str("");
                        buff<<level[j][i].cardindex;  //  Card matching number
                        text.setString(buff.str());

                        if(level[j][i].cardindex<10) text.setPosition(i*xspacing+xoffset+26,j*yspacing+yoffset+22);
                        else text.setPosition(i*xspacing+xoffset+18,j*yspacing+yoffset+22);

                        //  Show card number
                        if(level[j][i].cardfaceshowing && !level[j][i].matched) window.draw(text);

                        //  Show surrounding bomb count
                        if(level[j][i].matched && !level[j][i].bomb)
                        {
                                buff.str("");
                                buff<<level[j][i].surroundingbombsamount;  //  Number of bombs around
                                text.setString(buff.str());

                                text.setFillColor(sf::Color::White);
                                if(level[j][i].surroundingbombsamount<10) text.setPosition(i*xspacing+xoffset+26,j*yspacing+yoffset+22);
                                else text.setPosition(i*xspacing+xoffset+18,j*yspacing+yoffset+22);
                                window.draw(text);
                        }
                }
        }

        text.setFillColor(sf::Color::White);
        buff.str("");
        buff<<"Level: "<<levelnumber;
        text.setString(buff.str());
        text.setPosition(1000,0);
        window.draw(text);

        text.setFillColor(sf::Color::White);
        buff.str("");
        buff<<"Lives: "<<lives;
        text.setString(buff.str());
        text.setPosition(1000,50);
        window.draw(text);

        text.setFillColor(sf::Color::White);
        buff.str("");
        buff<<"Flips: "<<flipsremaining;
        text.setString(buff.str());
        text.setPosition(1000,100);
        window.draw(text);

        text.setFillColor(sf::Color::White);
        buff.str("");
        buff<<"Bombs: "<<numberofbombs;
        text.setString(buff.str());
        text.setPosition(1000,150);
        window.draw(text);

        text.setFillColor(sf::Color::White);
        buff.str("");
        buff<<"Sets of: "<<setsof;
        text.setString(buff.str());
        text.setPosition(1000,200);
        window.draw(text);
}

int countbombsat(int x, int y)
{
        int bombcount=0;

        if(x>0) bombcount+=level[y][x-1].bomb;
        if(x<levelwidth-1) bombcount+=level[y][x+1].bomb;
        if(y>0) bombcount+=level[y-1][x].bomb;
        if(y<levelheight-1) bombcount+=level[y+1][x].bomb;

        if(x>0 && y>0) bombcount+=level[y-1][x-1].bomb;
        if(x<levelwidth-1 && y>0) bombcount+=level[y-1][x+1].bomb;
        if(x<levelwidth-1 && y<levelheight-1) bombcount+=level[y+1][x+1].bomb;
        if(x>0 && y<levelheight-1) bombcount+=level[y+1][x-1].bomb;

        return bombcount;
}

void generatecurrentlevel(int which)
{
        if(which==1) generatelevel(4, 4, 1, 4, 30);
        else if(which==2) generatelevel(5, 5, 2, 4, 40);
        else if(which==3) generatelevel(7, 5, 3, 3, 50);
        else if(which==4) generatelevel(7, 6, 3, 3, 60);
        else if(which==5) generatelevel(7, 6, 4, 3, 70);
        else if(which==6) generatelevel(8, 6, 4, 3, 80);
        else if(which==7) generatelevel(6, 5, 5, 3, 70);
        else generatelevel(6, 6, 6, 3, 60);
}

void generatelevel(int width, int height, int numberofbombss, int setspertype, int nofflips)
{
        struct levelarrayindex { int x, y; };
        std::vector <levelarrayindex> lai(width*height);  //  A list of all array coordinates to help populate level array with bombs, cards, etc.

        //  Check to make sure we aren't requesting too many bombs
        if(numberofbombss>width*height/3)
        {
                MessageBoxA(NULL, "Too many bombs requested for level size", "ERROR", MB_ICONERROR | MB_OK);
                exit(1);
        }

        levelwidth=width;
        levelheight=height;
        setsof=setspertype;
        flipsremaining=nofflips;
        numberofbombs=numberofbombss;

        xoffset=10;
        yoffset=10;
        xspacing=100;
        yspacing=120;

        //  Reset everything
        for(int j=0; j<levelheight; j++)
                for(int i=0; i<levelwidth; i++)
                {
                        level[j][i].bomb=false;
                        level[j][i].bombrevealed=false;
                        level[j][i].cardfaceshowing=false;
                        level[j][i].cardindex=0;
                        level[j][i].flag=false;
                        level[j][i].matched=false;
                        level[j][i].surroundingbombsamount=0;
                }
        numberofcardsshowing=0;
        cardshown[0].showing=false;
        cardshown[1].showing=false;


        //  Set up vector coordinates
        for(int j=0; j<height; j++)
        {
                for(int i=0; i<width; i++)
                {
                        lai[j*width+i].x=i;
                        lai[j*width+i].y=j;
                }
        }

        //  Generate bombs
        int bombcount=0;
        while(bombcount<numberofbombss)
        {
                int bombindex = rand() % lai.size();
                level[lai[bombindex].y][lai[bombindex].x].bomb=true;
//              printf("%d, %d\n",lai[bombindex].x, lai[bombindex].y);
//              printf("%d\n",level[lai[bombindex].y][lai[bombindex].x].bomb);
//              printf("%d\n",lai.size());
                lai.erase(lai.begin() + bombindex);
                bombcount++;
        }

        int numbertouse=1;
        int numbersremaining=setspertype;  //  # of each number for cards

        while(lai.size()>0)
        {
                int numberindex = rand() % lai.size();
                level[lai[numberindex].y][lai[numberindex].x].cardindex=numbertouse;
                lai.erase(lai.begin() + numberindex);

                numbersremaining--;
                if(numbersremaining<1)
                {
                        numbertouse++;
                        numbersremaining=4;
                }

                //  If we only have 2 cards left, fill them up with the latest number
                if(lai.size()<3)
                {
                        while(lai.size()>0)
                        {
                                level[lai[0].y][lai[0].x].cardindex=numbertouse;
                                lai.erase(lai.begin());
                        }
                }
        }

        for(int j=0; j<levelheight; j++)
                for(int i=0; i<levelwidth; i++)
                        level[j][i].surroundingbombsamount=countbombsat(i, j);
}

bool checkforwin()
{
        //  Check here to make sure all bombs are either marked or revealed

        int flippedcardscount=0;

        for(int j=0; j<levelheight; j++)
                for(int i=0; i<levelwidth; i++)
                        if(!level[j][i].bomb) flippedcardscount+=level[j][i].matched;

//      printf("flipped cards: %d, number of bombs: %d, width*height: %d\n",flippedcardscount,numberofbombs,levelwidth*levelheight);
        if(flippedcardscount+numberofbombs==levelwidth*levelheight) return true;

        return false;
}

void initializegame()
{
        srand((unsigned int)time(NULL));
        window.create(sf::VideoMode(1240, 720), "MatchSweeper");

        if(!font.loadFromFile("forced square.ttf"))
        {
                MessageBoxA(NULL, "Error loading font", "ERROR", MB_ICONERROR | MB_OK);
                exit(1);
        }

        if(!itemstexture.loadFromFile("graphics/items.png"))
        {
                MessageBoxA(NULL, "Error loading items.png", "ERROR", MB_ICONERROR | MB_OK);
                exit(1);
        }

    if(!soundbuffer_cardflip.loadFromFile("sounds/flipcard.wav"))
        {
                MessageBoxA(NULL, "Error loading flipcard.wav", "ERROR", MB_ICONERROR | MB_OK);
                exit(1);
        }
        sound_cardflip.setBuffer(soundbuffer_cardflip);

    if(!soundbuffer_explosion.loadFromFile("sounds/explosion.wav"))
        {
                MessageBoxA(NULL, "Error loading explosion.wav", "ERROR", MB_ICONERROR | MB_OK);
                exit(1);
        }
        sound_explosion.setBuffer(soundbuffer_explosion);

    if(!soundbuffer_win.loadFromFile("sounds/win.wav"))
        {
                MessageBoxA(NULL, "Error loading win.wav", "ERROR", MB_ICONERROR | MB_OK);
                exit(1);
        }
        sound_win.setBuffer(soundbuffer_win);

        itemssprite[0].setTexture(itemstexture);
        itemssprite[0].setTextureRect(sf::IntRect(0, 0, 64, 128));
        itemssprite[1].setTexture(itemstexture);
        itemssprite[1].setTextureRect(sf::IntRect(64, 0, 64, 128));
        itemssprite[2].setTexture(itemstexture);
        itemssprite[2].setTextureRect(sf::IntRect(128, 0, 64, 128));
        itemssprite[3].setTexture(itemstexture);
        itemssprite[3].setTextureRect(sf::IntRect(196, 0, 64, 128));

        lives=5;
        levelnumber=1;
}
 
« Last Edit: April 23, 2018, 10:34:13 pm by gamecreator »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10823
    • View Profile
    • development blog
    • Email
Re: Text Strangeness
« Reply #5 on: April 23, 2018, 11:17:37 pm »
You shouldn't use global SFML resources (e.g. render window). You can easily wrap everything into a class and then you don't even have to worry about the extern keyword.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

gamecreator

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Text Strangeness
« Reply #6 on: April 24, 2018, 01:31:24 am »
Thanks for the tip.
« Last Edit: April 24, 2018, 01:51:38 am by gamecreator »