0

I made a program that was supposed to recreate that game, "MonkeyType" in which you have to write a specific text, if you make a mistake, the letter turns to red, and if it's good, the letter is white.

I made a sf::Text object using sfml, which is colored in white, i takes the letter if it is the good one, and a space if it is the wrong one, I did same with a red text that makes the opposite.

and I draw them with same coordinates.

I am using a monospace font, so that letters size should not be a problem, but as the text becomes bigger, the red text seems to shift on the left. so the letters end up being superimposed.

I have a Class Mot that has a string field and a Method ajouterLettre to add a letter to that string. And a Method that returns the string getMot().

class Mot
{
    string orthographe_;
public:
    ...
    void ajouterLettre(char lettre) { orthographe_.push_back(lettre); }
    string getMot() { return orthographe_; }
};
class Phrase
{
    vector<Mot> tabMots_;
public:
        ...
    void ajouterLettre(char lettre);
};

The method adds a letter to the last word of the list.

void Phrase::ajouterMot(const Mot& mot) {
    tabMots_.push_back(mot);
}

I'm using Monospace font. In the main function, I create two texts, a red one and a white one. and two objects phrase that makes the text of these sf::Text objects. the (1, false) parameters means the phrase has only one empty word (Mot).

sf::Text textecrit1(phraseecrite.Text(), font, 24);
    textecrit1.setFillColor(sf::Color::White);
    textecrit1.setPosition(10, 10);

Phrase phraseecrite(1,false);

sf::Text texterreur1("", font, 24);
    texterreur1.setFillColor(sf::Color(255, 0, 0));
    texterreur1.setPosition(10, 10);

Phrase phraserreur(1, false);

phrase objects has a Text Method that returns a string corresponding to the list of words separated by a space.

string Phrase::Text() {
    string texte;

    if (tabMots_.size() == 1) {
        texte = tabMots_[0].getMot();
    }

    else{
        int i;
        texte = tabMots_[0].getMot();

        for (i = 1; i < tabMots_.size(); i++) {
            texte = texte + " " + tabMots_[i].getMot();
        }
    }   
    return texte;
}

I have an isCorrect function that works and tells if the last letter of two sentences (Phrase) is the same.

when the user types a letter on the keyboard, the phrase "phraseecrite" takes the letter, and a phraseerreur that takes a space if it is the right and the letter if it is not. I also update the rendering sf::Text

I draw them one on top of the other so that the red one covers the white one. phraseaecrire is the sentence the player has to match with.

if (event.text.unicode >= 'a' && event.text.unicode <= 'z') {
    phraseecrite.ajouterLettre( event.text.unicode );

    textecrit1.setString(phraseecrite.Text());

    if (phraseecrite.isCorrect(phraseaecrire1)) {
        phraserreur.ajouterLettre(' ');
    }
    else
    {
        phraserreur.ajouterLettre(event.text.unicode);
    }

even if I add a space to phraseerreur to make them be a the same position when the letter is incorrect. it shifts gradually when the text gets bigger, just a little at the beginning, but it becomes bigger when the text is really long.

1
  • Please post code that so that the problem can be recreated please. You explained bits of your code but how they are linked together are lacking. I'm unable to recreate your problem. Commented Apr 28, 2023 at 11:24

1 Answer 1

1

Due to the lack of for recreating the problem i was unable to help with the immediate spacing. But after fiddling with it myself i think i found what you lacked. All further information about your code will be my assumptions. I Assume in your code you have a vector or list of any type of letters that you iterate through and change their color and things if they're correct or not. What you may not have is a correct formulat for positioning of the letters. I'll assume the most probable scenario in which you put a static value for your letters (as in their width). lets say 100 pixels. Not all letters have an equal width thus your positioning of letters, the more of them the further their spacing would become as lets say the letter 'l' would take 20 pixels. Having 3 'l's next to each other would make it far apart and unnatural maybe even giving you the problem you have now. Below is the formula i implemented which is relative to the width of the previous letter. I also added an offset as different fonts have different letter widths. The below code is a basic implementation of your game as well as a nice solve to your problem. Hope it helped.

#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
#include <vector>
using namespace std;

class GameClass
{
public:
    vector<sf::Text> text;
    string correctTextString;
    int textStringIndex = 0;
    sf::Font font;

    GameClass()
    {
        font.loadFromFile("arial.ttf");
        setString("string");
    }

    void setString(string str)
    {
        correctTextString = str;
        textStringIndex = 0;
        text.clear();
        for(int i = 0; i < (int)str.length(); i++)
        {
            int offsetX = 5;
            sf::Text tmp;
            tmp.setCharacterSize(60);
            tmp.setFont(font);
            tmp.setString(str[i]);
            if (text.size() == 0) tmp.setPosition(0,0);
            else tmp.setPosition(text[i-1].getPosition().x + text[i-1].getGlobalBounds().width + offsetX, 0);
            text.emplace_back(tmp);
        }
    }

    bool checkLetter(char letter)
    {
        if (textStringIndex >= correctTextString.length()) return false;
        if (correctTextString[textStringIndex] == letter)
        {
            text[textStringIndex].setFillColor(sf::Color::Green);
            textStringIndex++;
            return true;
        }
        else
        {
            text[textStringIndex].setFillColor(sf::Color::Red);
            textStringIndex++;
            return false;
        }
    }
};

int main()
{
    // create the window
    sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
    window.setFramerateLimit(60);
    GameClass gameclass;
    // run the program as long as the window is open
    while (window.isOpen())
    {
        // check all the window's events that were triggered since the last iteration of the loop
        sf::Event event;
        while (window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed) window.close();
            if(event.type == sf::Event::KeyPressed)
            {
                gameclass.checkLetter(event.key.code+'a');
            }
        }

        // clear the window with black color
        window.clear(sf::Color::Black);

        // draw everything here...
        // window.draw(...);
        for(int i = 0; i < (int)gameclass.text.size(); i++)
            window.draw(gameclass.text[i]);

        // end the current frame
        window.display();
    }

    return 0;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.