Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[SFML] Dialog box

Ostatnio zmodyfikowano 2024-05-29 19:36
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
[SFML] Dialog box
» 2024-05-06 21:35:31
Potrzebuje zrobić w mojej grze dialog box. To znaczy chodzi o to że potrzebuje funkcji która jako argument pobiera tekst i wyświetla ten tekst na prostokątnym tle. Tekst jest dzielony na kilka tekstów, tak by każdy tekst nie wychodził poza obszar boxa. Jak to zrobić ?


C/C++
class DialogBox {
   
sf::RectangleShape background;
   
sf::Font font;
   
sf::Text text;
   
float padding;
};
P-181029
pekfos
» 2024-05-07 18:50:37
Samo sf::Text nie załamuje tekstu, więc napis będziesz musiał przetworzyć by wstawić znaki nowej linii, używając zwrotki z getGlobalBounds() jako feedback czy mieścisz się w ustalonym obszarze. Jak dodanie kolejnego słowa wykracza poza szerokość, wstaw po nowej linii. Jak wykracza na wysokość, to musisz resztę zostawić na kolejny ekran. Trzeba by pewnie dodać pole std::string na ten nadmiarowy tekst.

potrzebuje funkcji która jako argument pobiera tekst i wyświetla ten tekst na prostokątnym tle.
Jako że tekst może wymagać wielu ekranów i aktualnie jest wyświetlany jeden z nich, ta funkcja by co najwyżej inicjowała pokazywanie dialogu przez np utworzenie obiektu DialogBox i przypisanie parametrów. Gdzieś w stanie gry możesz mieć wskaźnik DialogBox*, który gdy jest niepusty, sprawia że dialog jest wyświetlany wg jego aktualnego stanu (trzymanego w obiekcie DialogBox) i sterowanie gracza wpływa na ten stan.
P-181030
DejaVu
» 2024-05-07 19:37:40
Nadal nie rozumiem czemu nie zadajesz tych pytań do ChatGPT 4. ChatGPT wygeneruje rozwiązanie, a Ty zadajesz pytania na forum, aby czekać na odpowiedź cały dzień i często nie dostaniesz gotowej implementacji, tylko opis jak rozwiązać można problem.

Stworzenie dialog boxa w SFML z możliwością wyświetlania dłuższego tekstu można osiągnąć poprzez podzielenie go na mniejsze fragmenty, tak aby nie wychodziły poza obszar okna. Trzeba zająć się kilkoma rzeczami:

1. **Podzielenie Tekstu:** Rozdzielenie tekstu na linie o odpowiedniej długości tak, aby każda linia mieściła się w obrębie boxa.
2. **Renderowanie Tekstu:** Upewnij się, że tekst jest poprawnie wyświetlany linia po linii.
3. **Box:** Stworzenie prostokątnego boxa i wyświetlenie w nim tekstu.

Poniżej znajdziesz przykładowy kod w C++, używający SFML, który ilustruje takie podejście:

```cpp
#include <SFML/Graphics.hpp>
#include <string>
#include <vector>
#include <sstream>

// Funkcja dzieląca tekst na linie o odpowiedniej szerokości
std::vector<std::string> wrapText(const std::string& text, sf::Font& font, unsigned int fontSize, float maxWidth) {
    std::vector<std::string> wrappedText;
    std::istringstream wordsStream(text);
    std::string word;
    std::string currentLine;

    while (wordsStream >> word) {
        std::string testLine = currentLine.empty() ? word : currentLine + " " + word;
        sf::Text testText(testLine, font, fontSize);
        if (testText.getGlobalBounds().width > maxWidth) {
            wrappedText.push_back(currentLine);
            currentLine = word;
        } else {
            currentLine = testLine;
        }
    }

    if (!currentLine.empty()) {
        wrappedText.push_back(currentLine);
    }

    return wrappedText;
}

int main() {
    sf::RenderWindow window(sf::VideoMode(800, 600), "Dialog Box Example");

    sf::Font font;
    if (!font.loadFromFile("arial.ttf")) {
        return -1; // Upewnij się, że masz odpowiednią czcionkę
    }

    std::string text = "This is an example of a dialog box that wraps text automatically "
                       "based on the width of the dialog box.";

    unsigned int fontSize = 24;
    float boxWidth = 600;

    // Dzielimy tekst na linie
    std::vector<std::string> wrappedText = wrapText(text, font, fontSize, boxWidth);

    // Tworzymy tekst do wyświetlenia linia po linii
    std::vector<sf::Text> textLines;
    float yPosition = 50;
    for (const auto& line : wrappedText) {
        sf::Text textLine(line, font, fontSize);
        textLine.setPosition(100, yPosition);
        textLine.setFillColor(sf::Color::White);
        textLines.push_back(textLine);
        yPosition += fontSize + 5;
    }

    // Tworzymy prostokątny box
    sf::RectangleShape dialogBox(sf::Vector2f(boxWidth, yPosition - 50 + 20));
    dialogBox.setPosition(90, 40);
    dialogBox.setFillColor(sf::Color(0, 0, 0, 150));
    dialogBox.setOutlineColor(sf::Color::White);
    dialogBox.setOutlineThickness(2);

    // Pętla główna aplikacji
    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }
        }

        window.clear();
        window.draw(dialogBox);
        for (const auto& textLine : textLines) {
            window.draw(textLine);
        }
        window.display();
    }

    return 0;
}
```

### Wyjaśnienie kodu
1. **Podział Tekstu:** Funkcja `wrapText` dzieli długi tekst na linie, które mieszczą się w określonej szerokości, korzystając z czcionki i rozmiaru tekstu.
2. **Wyświetlanie Tekstu:** Dzielone linie są umieszczane w obszarze okna poprzez ustawienie odpowiednich pozycji.
3. **Dialog Box:** Tworzony jest prostokątny box na podstawie wielkości zawartości.

W kodzie upewnij się, że ścieżka do czcionki jest poprawna, aby załadować ją do programu.

Sprawdziłem i ta implementacja działa. Co prawda nie jest idealna, bo spacje powinno wliczać w długość tekstu, ale jest wystarczająco dobra na start i taką drobną poprawkę możesz mu zasugerować, aby ją doimplementował.
P-181032
tBane
Temat założony przez niniejszego użytkownika
» 2024-05-07 20:00:46
Napisałem prosty DialogBox. Kod zamieszczam poniżej.


C/C++
#ifndef DialogBox_hpp
#define DialogBox_hpp

float characterSize = 32.0f;
float lineHeight = 40.0f;
float padding = 10.0f;
sf::Vector2f dialogSize = sf::Vector2f( screenWidth / 3.0f * 2.0f, 4.0f * lineHeight + 2.0f * padding );
sf::Vector2f textPosition;
int countOfLines = 0;
int page = 0;
sf::RectangleShape * background;
std::vector < string > lines;

std::vector < string > wrapText( const std::string text, float maxWidth ) {
   
std::vector < std::string > wrappedText;
   
std::istringstream wordsStream( text );
   
std::string word;
   
std::string currentLine;
   
   
while( wordsStream >> word ) {
       
std::string testLine = currentLine.empty() ? word
            : currentLine + " " + word;
       
sf::Text testText( testLine, * basicFont, characterSize );
       
if( testText.getLocalBounds().width + 2.0f * padding > maxWidth ) {
           
wrappedText.push_back( currentLine );
           
currentLine = word;
       
}
       
else {
           
currentLine = testLine;
       
}
    }
   
   
if( !currentLine.empty() ) {
       
wrappedText.push_back( currentLine );
   
}
   
   
return wrappedText;
}

void setTextToDialogBox( string s ) {
   
lines = wrapText( s, dialogSize.x );
   
countOfLines = lines.size();
}

void renderDialogBox( sf::RenderWindow * window, int currentPage = 0 ) {
   
   
page = currentPage;
   
background = new sf::RectangleShape( dialogSize );
   
background->setFillColor( sf::Color( 64, 64, 64 ) );
   
background->setOrigin( background->getLocalBounds().width / 2.0f, background->getLocalBounds().height / 2.0f );
   
background->setPosition( view.getCenter().x, view.getCenter().y + screenHeight / 2.0f - dialogSize.y / 2.0f );
   
   
std::vector < sf::Text * > texts;
   
texts.clear();
   
sf::Text * text;
   
sf::Vector2f textPosition;
   
   
for( int i = 0; i < lines.size(); i++ ) {
       
if( i + 4 * page < lines.size() )
           
 text = new sf::Text( lines[ i + 4 * page ], * basicFont, characterSize );
       
else
           
 text = new sf::Text( "", * basicFont, characterSize );
       
       
text->setFillColor( sf::Color::White );
       
textPosition.x = background->getPosition().x - dialogSize.x / 2.f + padding;
       
textPosition.y = background->getPosition().y - dialogSize.y / 2.f + float( i ) * lineHeight + padding;
       
text->setPosition( textPosition );
       
texts.push_back( text );
   
}
   
   
window->draw( * background );
   
for( auto & text: texts )
       
 window->draw( * text );
   
   
}
#endif
P-181033
tBane
Temat założony przez niniejszego użytkownika
» 2024-05-27 20:57:47
Ostateczna wersja prototypowa Dialog Boxa


C/C++
#ifndef DialogBox_hpp
#define DialogBox_hpp

float characterSize = 32.0f;
float lineHeight = 32.0f;
float padding = 10.0f;
sf::Vector2f dialogSize = sf::Vector2f( 600, 160 );
sf::Vector2f textPosition;
int countOfLines = 0;
int page = 0;
sf::Sprite * background;
std::vector < string > lines;
std::vector < std::string > wrappedText;

void wrapText( const std::string text ) {
   
   
std::istringstream wordsStream( text );
   
std::string word;
   
std::string currentLine;
   
   
wrappedText.clear();
   
float maxWidth = dialogSize.x - 2.0f * padding;
   
   
while( wordsStream >> word ) {
       
std::string testLine = currentLine.empty() ? word
            : currentLine + " " + word;
       
sf::Text testText( testLine, * basicFont, characterSize );
       
if( testText.getLocalBounds().width > maxWidth ) {
           
wrappedText.push_back( currentLine );
           
currentLine = word;
       
}
       
else {
           
currentLine = testLine;
       
}
    }
   
   
if( !currentLine.empty() ) {
       
wrappedText.push_back( currentLine );
   
}
   
}

void setTextToDialogBox( string s ) {
   
wrapText( s );
   
countOfLines = wrappedText.size();
}

void renderDialogBox( sf::RenderWindow * window, int currentPage = 0 ) {
   
   
page = currentPage;
   
   
sf::Texture * dialogBoxTexture = new sf::Texture();
   
dialogBoxTexture->loadFromFile( "assets/GUI/DialogBoxTexture.png" );
   
   
background = new sf::Sprite();
   
background->setTexture( * dialogBoxTexture );
   
background->setOrigin( dialogSize.x / 2.0f, dialogSize.y / 2.0f );
   
background->setPosition( view.getCenter().x, view.getCenter().y + screenHeight / 2.0f - dialogSize.y / 2.0f );
   
   
std::vector < sf::Text * > texts;
   
texts.clear();
   
sf::Text * text;
   
sf::Vector2f textPosition;
   
   
for( int i = 0; i < 4; i++ ) {
       
if( i + 4 * page < wrappedText.size() )
           
 text = new sf::Text( wrappedText[ i + 4 * page ], * basicFont, characterSize );
       
else
           
 text = new sf::Text( "", * basicFont, characterSize );
       
       
text->setFillColor( sf::Color::White );
       
textPosition.x = background->getPosition().x - dialogSize.x / 2.f + padding;
       
textPosition.y = background->getPosition().y - dialogSize.y / 2.f + float( i ) * lineHeight + padding;
       
text->setPosition( textPosition );
       
texts.push_back( text );
   
}
   
   
window->draw( * background );
   
for( auto & text: texts )
       
 window->draw( * text );
   
   
}

#endif
P-181132
pekfos
» 2024-05-28 16:40:29
Poobserwuj sobie użycie pamięci przez Twoją grę w menadżerze zadań. Masz całą masę nieuzasadnionej ręcznej alokacji pamięci i jeszcze nie widziałem żebyś tą pamięć zwalniał.
P-181133
tBane
Temat założony przez niniejszego użytkownika
» 2024-05-28 17:23:41
czyli delete'ować wszystkie zmienne po użyciu ?
P-181135
pekfos
» 2024-05-28 18:05:53
Wypadałoby. Ale prościej tej pamięci w ogóle nie alokować dynamicznie. Jeśli masz w kodzie new to na 99% robisz coś źle.
P-181136
« 1 » 2
  Strona 1 z 2 Następna strona