Pular para o conteúdo
Baixar

C++ para a Brasa

C++ tem fama de difícil, mas para fazer jogos na Brasa você usa uma parte pequena dele. Esta página explica essa parte, com exemplos tirados do tutorial.

Quando você aperta Play, a Brasa compila o seu código: transforma o texto dos arquivos .cpp num programa. Se algo estiver escrito errado, o compilador avisa na Saída antes de o jogo abrir.

Uma variável guarda um valor. Em C++, você diz o tipo dela:

int lives = 3; // número inteiro
float speed = 2.0f; // número com vírgula (o f no fim marca um float)
bool canShoot = true; // verdadeiro ou falso
auto dx = 0.0f; // auto: o compilador descobre o tipo (aqui, float)
  • Use float para posições e velocidades, e int para contagens, como vidas e pontos.
  • const marca algo que não muda depois de criado: const float margin = 16.0f;.

As instâncias já vêm com várias variáveis prontas, como x, y, hspeed e vspeed. Veja Objetos e eventos.

x = x + 2; // soma 2 ao x
x += 2; // o mesmo, mais curto
--invincible; // tira 1
++spawned; // soma 1
if (held(Key::Space) && canShoot_) {
// espaço apertado E pode atirar
}
if (state().lives <= 0) {
goTo("GameOver");
} else {
invincible_ = 90;
}
  • && é e, || é ou, ! é não.
  • Para comparar: == (igual), != (diferente), <, >, <=, >=.

Uma função é um bloco de código com nome. Ela pode receber valores e devolver um resultado:

float centeredX(std::string_view text, float screenWidth) {
return (screenWidth - text.size() * 8.0f) / 2.0f;
}

A maior parte do tempo, você chama funções da Brasa: spawn<Bullet>(x, y, "Instancias"), random(0.8f, 1.6f), Audio::play("tiro").

Cada objeto do jogo é uma classe que herda de brasa::Entity:

class Player : public brasa::Entity {
public:
void onSpawn() override;
void onUpdate() override;
private:
bool canShoot_ = true;
};
  • : public brasa::Entity quer dizer que o Player é uma Entity: ele ganha posição, sprite, velocidade e todas as funções da Brasa.
  • onSpawn e onUpdate são eventos. A Entity já tem esses eventos, vazios. O override diz que você está trocando o comportamento deles.
  • O que fica em private: só a própria classe usa. É comum terminar esses nomes com _, como em canShoot_.

O código de cada função fica no .cpp, com o nome da classe na frente:

void Player::onUpdate() {
// roda a cada passo
}

O Player:: diz “esta é a função onUpdate do Player”.

Algumas funções da Brasa recebem um pedaço de código para executar mais tarde. Esse pedaço é uma lambda:

after(10, [this] { canShoot_ = true; });
onCollide<Enemy>([this](Enemy& enemy) {
if (hurt()) enemy.destroy();
});
  • [this] deixa a lambda usar as coisas da instância, como canShoot_ e hurt().
  • (Enemy& enemy) é o que a lambda recebe: no onCollide, o inimigo que encostou.
  • O & quer dizer que você recebe o próprio inimigo, não uma cópia, então enemy.destroy() destrói o inimigo de verdade.

Em spawn<Bullet>(x, y, "Instancias"), count<Enemy>() e onCollide<Enemy>(...), o que vai entre < > é qual objeto. É assim que a Brasa sabe o que criar, contar ou detectar.

#include "Player.hpp" // traz a classe deste objeto
#include "src/game.hpp" // traz o que é do jogo todo (pontos e vidas)
#include <algorithm> // traz std::clamp e std::max da biblioteca padrão
using namespace brasa; // deixa escrever Audio::play em vez de brasa::Audio::play
  • #include copia o conteúdo de outro arquivo para este. Use aspas para arquivos seus e < > para bibliotecas.
  • Um namespace é uma “pasta” de nomes. A Brasa usa brasa. As classes dos seus objetos ficam fora de namespace.
  • std:: é o namespace da biblioteca padrão do C++: std::clamp, std::max, std::format.

Quando o Play falha, a Saída mostra o erro com o arquivo e a linha, por exemplo:

Player.cpp(23,5): error C2143: erro de sintaxe: ';' ausente antes de 'if'

Isso quer dizer: no Player.cpp, linha 23, coluna 5, faltou um ;. Clique no erro e o seu editor de código abre nessa linha. Os erros mais comuns:

Mensagem (parecida com) O que costuma ser
';' ausente Faltou o ; no fim da linha anterior.
identificador não declarado Nome escrito errado, ou faltou um #include (por exemplo o src/game.hpp).
não é possível converter Tipos diferentes, como int e float. Um static_cast<float>(...) resolve.
'}' esperado Uma chave { ficou sem fechar.

Veja também Play e erros.