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ć ? class DialogBox { sf::RectangleShape background; sf::Font font; sf::Text text; float padding; }; |
|
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. |
|
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ł. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-05-07 20:00:46 Napisałem prosty DialogBox. Kod zamieszczam poniżej. #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
|
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-05-27 20:57:47 Ostateczna wersja prototypowa Dialog Boxa#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
|
|
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ł. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-05-28 17:23:41 czyli delete'ować wszystkie zmienne po użyciu ? |
|
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. |
|
« 1 » 2 |