C++ e SFML - Aula02
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.