C++ e SFML - Aula02

De Aulas

Links Relacionados: Matemática e Física para Jogos

Recursos

Os arquivos de recursos utilizados pelos exemplos a seguir encontram-se em: https://saulo.arisa.com.br/aulas/mfj/mfj_a02_e01_res.zip.

Exemplo 01

O seguinte código apresenta a utilização de alguns recursos da biblioteca SFML, como imagens, sprites, texto, som, música, interação com teclado e mouse.

  1#include <SFML/Graphics.hpp>
  2#include <SFML/Audio.hpp>
  3#include <iostream>
  4#include <sstream>
  5
  6int main()
  7{
  8    // Inicializacao da biblioteca
  9    sf::RenderWindow* app = new sf::RenderWindow(sf::VideoMode(800, 600, 32), "MFJ - SFML e C++");
 10
 11    // Le uma imagem para deixar de fundo
 12    sf::Image* imageBackground = new sf::Image();
 13    if (!imageBackground->LoadFromFile("res/background.png"))
 14    {
 15        std::cout << "ERRO IMAGEM" << std::endl;
 16    }
 17    sf::Sprite* spriteBackground = new sf::Sprite(*imageBackground);
 18    spriteBackground->SetPosition(0, 0);
 19
 20    // Le outra imagem para ser movimentada na tela, o alvo.
 21    int x = 100;
 22    int y = 100;
 23    sf::Image* imageTarget = new sf::Image();
 24    if (!imageTarget->LoadFromFile("res/target.png"))
 25    {
 26        std::cout << "ERRO IMAGEM" << std::endl;
 27    }
 28    sf::Sprite* spriteTarget = new sf::Sprite(*imageTarget);
 29
 30    // Le a imagem do tiro
 31    sf::Image* imageShot = new sf::Image();
 32    if (!imageShot->LoadFromFile("res/shot.png"))
 33    {
 34        std::cout << "ERRO IMAGEM" << std::endl;
 35    }
 36
 37    // Le uma music e a coloca para tocar
 38    sf::Music* music = new sf::Music();
 39    if (!music->OpenFromFile("res/The_St_Louis_Blues.ogg"))
 40    {
 41        std::cout << "ERROR IN MUSIC" << std::endl;
 42    }
 43    music->Play();
 44
 45    // Le um arquivo de som
 46    int shotSize = 0;
 47    int shotTimer = 0;
 48    sf::SoundBuffer* bufferTiro = new sf::SoundBuffer();
 49    if (!bufferTiro->LoadFromFile("res/shot.wav"))
 50    {
 51        std::cout << "ERROR IN SOUND" << std::endl;
 52    }
 53    sf::Sound* soundShot = new sf::Sound(*bufferTiro);
 54
 55    // Escrevendo um text na tela
 56    int xText = 10;
 57    int yText = 10;
 58    sf::Font* fonteTimes = new sf::Font();
 59    if (!fonteTimes->LoadFromFile("res/times.ttf"))
 60    {
 61        std::cout << "ERRO FONTE" << std::endl;
 62    }
 63    sf::String* text = new sf::String("Blues is not dead!", *fonteTimes, 48);
 64    text->SetColor(sf::Color(255, 255, 255));
 65
 66    // Gameloop - Le os eventos
 67    while (app->IsOpened())
 68    {
 69        // Leitura dos eventos
 70        sf::Event event;
 71        while (app->GetEvent(event))
 72        {
 73            if (event.Type == sf::Event::Closed)
 74            {
 75                app->Close();
 76            }
 77        }
 78        // Verifica a localizacao do mouse para para posicionar a mira
 79        int mouseX = app->GetInput().GetMouseX();
 80        int mouseY = app->GetInput().GetMouseY();
 81        if ((mouseX > 0) && (mouseY > 0) && (mouseX < (int) app->GetWidth()) && (mouseY < (int) app->GetHeight()))
 82        {
 83            x = mouseX - (int) (spriteTarget->GetSize().x / 2);
 84            y = mouseY - (int) (spriteTarget->GetSize().y / 2);
 85        }
 86        spriteTarget->SetPosition(x, y);
 87        text->SetPosition(xText, yText);
 88
 89        // Repoiciona o text conforme a utilizacao das setas
 90        if (app->GetInput().IsKeyDown(sf::Key::Up)) yText--;
 91        if (app->GetInput().IsKeyDown(sf::Key::Down)) yText++;
 92        if (app->GetInput().IsKeyDown(sf::Key::Left)) xText--;
 93        if (app->GetInput().IsKeyDown(sf::Key::Right)) xText++;
 94        // Som de tiro
 95        if (app->GetInput().IsKeyDown(sf::Key::Space) || app->GetInput().IsMouseButtonDown(sf::Mouse::Left))
 96        {
 97            if (shotTimer == 0)
 98            {
 99                soundShot->Play();
100                int xaux = (int) x + (spriteTarget->GetSize().x / 2) - (imageShot->GetWidth() / 2);
101                int yaux = (int) y + (spriteTarget->GetSize().y / 2) - (imageShot->GetHeight() / 2);
102                imageBackground->Copy(*imageShot, xaux, yaux, sf::IntRect(0, 0, 50, 50), true);
103                shotTimer = 20;
104                shotSize++;
105            }
106        }
107        if (shotTimer > 0) shotTimer--;
108        // Se pressionada a tecla ESC, sai do programa
109        if (app->GetInput().IsKeyDown(sf::Key::Escape))
110        {
111            return EXIT_SUCCESS;
112        }
113
114        // Coloca a quantidade de tiros efetuados
115        std::stringstream stringShotSize;
116        stringShotSize << "Blues is not dead! " << shotSize << " times.";
117        text->SetText(stringShotSize.str());
118
119        // Desenha os elementos
120        app->Clear();
121        app->Draw(*spriteBackground);
122        app->Draw(*text);
123        app->Draw(*spriteTarget);
124        app->Display();
125    }
126    return EXIT_SUCCESS;
127}

Exemplo 02

Esta é a mesma versão do exemplo anterior. Contudo, formatado para a orientação a objetos e ao modelo de gameloop utilizado na disciplina de Jogos Digitais II (Jogos Digitais).

  1#include <SFML/Graphics.hpp>
  2#include <SFML/Audio.hpp>
  3#include <iostream>
  4#include <sstream>
  5
  6class Game
  7{
  8private:
  9    // Privated attirbutes
 10    sf::RenderWindow* app;
 11    sf::Event* event;
 12    sf::Image* imageBackground;
 13    sf::Sprite* spriteBackground;
 14    sf::Sprite* spriteTarget;
 15    sf::Image* imageShot;
 16    sf::Music* music;
 17    sf::Sound* soundShot;
 18    sf::String* text;
 19    bool exitGame;
 20    int shotSize;
 21    int shotTimer;
 22    int xText;
 23    int yText;
 24    int x;
 25    int y;
 26
 27    // Privated methods
 28    void render();
 29    void simulateGameWorld();
 30    void processInput();
 31    int gameLoop();
 32public:
 33    // public methods
 34    Game();
 35    ~Game();
 36};
 37
 38Game::Game()
 39{
 40    // Inicializacao da biblioteca SFML
 41    app = new sf::RenderWindow(sf::VideoMode(800, 600, 32), "MFJ - SFML e C++");
 42    exitGame = false;
 43
 44    // Le uma imagem para deixar de fundo
 45    imageBackground = new sf::Image();
 46    if (!imageBackground->LoadFromFile("res/background.png"))
 47    {
 48        std::cout << "ERRO IMAGEM" << std::endl;
 49    }
 50    spriteBackground = new sf::Sprite(*imageBackground);
 51
 52    // Le outra imagem para ser movimentada na tela, o alvo.
 53    x = 100;
 54    y = 100;
 55    sf::Image* imageTarget = new sf::Image();
 56    if (!imageTarget->LoadFromFile("res/target.png"))
 57    {
 58        std::cout << "ERRO IMAGEM" << std::endl;
 59    }
 60    spriteTarget = new sf::Sprite(*imageTarget);
 61
 62    // Le a imagem do tiro
 63    imageShot = new sf::Image();
 64    if (!imageShot->LoadFromFile("res/shot.png"))
 65    {
 66        std::cout << "ERRO IMAGEM" << std::endl;
 67    }
 68
 69    // Le uma musica e a coloca para tocar
 70    music = new sf::Music();
 71    if (!music->OpenFromFile("res/The_St_Louis_Blues.ogg"))
 72    {
 73        std::cout << "ERROR IN MUSIC" << std::endl;
 74    }
 75    music->Play();
 76
 77    // Le um arquivo de som
 78    shotSize = 0;
 79    shotTimer = 0;
 80    sf::SoundBuffer* bufferShot = new sf::SoundBuffer();
 81    if (!bufferShot->LoadFromFile("res/shot.wav"))
 82    {
 83        std::cout << "ERROR IN SOUND" << std::endl;
 84    }
 85    soundShot = new sf::Sound(*bufferShot);
 86
 87    // Configura um texto para escrever na tela
 88    xText = 10;
 89    yText = 10;
 90    sf::Font* fontTimes = new sf::Font();
 91    if (!fontTimes->LoadFromFile("res/times.ttf"))
 92    {
 93        std::cout << "ERRO FONTE" << std::endl;
 94    }
 95    text = new sf::String("Blues is not dead!", *fontTimes, 48);
 96    text->SetColor(sf::Color(255, 255, 255));
 97
 98    gameLoop();
 99}
100
101void Game::simulateGameWorld()
102{
103    // Verifica a localizacao do mouse para para posicionar a mira
104    int mouseX = app->GetInput().GetMouseX();
105    int mouseY = app->GetInput().GetMouseY();
106    if ((mouseX > 0) && (mouseY > 0) && (mouseX < (int) app->GetWidth()) && (mouseY < (int) app->GetHeight()))
107    {
108        x = mouseX - (int) (spriteTarget->GetSize().x / 2);
109        y = mouseY - (int) (spriteTarget->GetSize().y / 2);
110    }
111    spriteTarget->SetPosition(x, y);
112    text->SetPosition(xText, yText);
113
114    // Repoiciona o texto conforme a utilizacao das setas
115    if (app->GetInput().IsKeyDown(sf::Key::Up)) yText--;
116    if (app->GetInput().IsKeyDown(sf::Key::Down)) yText++;
117    if (app->GetInput().IsKeyDown(sf::Key::Left)) xText--;
118    if (app->GetInput().IsKeyDown(sf::Key::Right)) xText++;
119    // Som de tiro
120    if (app->GetInput().IsKeyDown(sf::Key::Space) || app->GetInput().IsMouseButtonDown(sf::Mouse::Left))
121    {
122        if (shotTimer == 0)
123        {
124            soundShot->Play();
125            int xaux = (int) x + (spriteTarget->GetSize().x / 2) - (imageShot->GetWidth() / 2);
126            int yaux = (int) y + (spriteTarget->GetSize().y / 2) - (imageShot->GetHeight() / 2);
127            imageBackground->Copy(*imageShot, xaux, yaux, sf::IntRect(0, 0, 50, 50), true);
128            shotTimer = 20;
129            shotSize++;
130        }
131    }
132    if (shotTimer > 0) shotTimer--;
133
134    // Coloca a quantidade de tiros efetuados
135    std::stringstream stringShotSize;
136    stringShotSize << "Blues is not dead! " << shotSize << " times.";
137    text->SetText(stringShotSize.str());
138
139    if (app->GetInput().IsKeyDown(sf::Key::Escape))
140    {
141        exitGame = true;
142    }
143}
144
145void Game::render()
146{
147    // Desenha os elementos
148    app->Clear();
149    app->Draw(*spriteBackground);
150    app->Draw(*text);
151    app->Draw(*spriteTarget);
152    app->Display();
153}
154
155void Game::processInput()
156{
157    event = new sf::Event();
158    while (app->GetEvent(*event))
159    {
160        if (event->Type == sf::Event::Closed)
161        {
162            app->Close();
163        }
164    }
165}
166
167int Game::gameLoop()
168{
169    while (!exitGame && app->IsOpened())
170    {
171        render();
172        processInput();
173        simulateGameWorld();
174    }
175    return EXIT_SUCCESS;
176}
177
178Game::~Game()
179{
180}
181
182int main()
183{
184    Game game;
185    return 0;
186}

Exercícios

Faça etapa por etapa, compile e rode cada uma delas observando os resultados.

1. Crie um projeto no Code::Blocks para cada exemplo apresentado acima.

2. Baixe os arquivos utilizados pelos exemplos e coloque-os dentro de uma pasta chamada res. Configure os projetos e faça-os executar.

3. Crie um novo projeto do zero e configure para a biblioteca SFML.

4. Coloque uma imagem de fundo, de tamanho 800x600 pixels.

4.1. Coloque uma música de fundo.

5. Insira uma imagem PNG (sprite) e faça esta se movimentar. Ela deve se movimentar da seguinte forma:

5.1. Inicialmente de forma diagonal, em direção para direita e para baixo (x++ e y++).
5.2. Quando a imagem colide com as laterais, ela inverte a movimentação lateral. Se estiver indo para a direita, então vai para a esquerda. Se estiver indo para a esquerda, então vai para a direita.
5.3. Se a imagem colide com algum canto superior ou inferior, então inverte o y.

6. Coloque outras duas imagens em outras partes da tela se movimentando, uma verticalmente e outra horizontalmente.

7. Gerencie as colisões das 3 imagens (sprites) se movimentando. Eles invertem seus vetores de direção caso colidam entre si.

7.1. Coloque sons de colisão. O som de colisão com as laterais da tela deve ser um tipo, e o som de colisão entre as imagens se movimentando deve ser outro.
7.2. Coloque um texto na parte inferior esquerda da tela, mostrando duas informações: a quantidade de colisões com as laterais e a quantidade de colisões entre os elementos.