Capítulo 04 — Build, Run e Executable não são a mesma coisa
Série: Do zero ao jogo comercial com C++ e SFML
Do main.cpp ao programa em execução: entendendo o que realmente acontece quando salvamos, construímos e executamos nosso projeto C++
Nos capítulos anteriores começamos nossa jornada com algo extremamente simples:
#include <iostream>
int main()
{
std::cout << "Game Engineering com C++ começou!" << std::endl;
return 0;
}
Primeiro, fizemos esse código funcionar.
Depois, entendemos sua estrutura.
Em seguida, começamos a quebrá-lo de propósito para aprender a ler erros, formular hipóteses, corrigir problemas e validar o resultado.
Agora existe uma nova pergunta importante.
Quando pressionamos:
Ctrl + S
alguma coisa acontece.
Quando pressionamos:
Ctrl + Shift + B
acontece outra coisa.
E quando usamos:
Ctrl + F5
acontece outra coisa novamente.
Essas ações podem parecer semelhantes quando estamos começando, porque todas fazem parte do mesmo fluxo de desenvolvimento.
Mas elas representam etapas diferentes.
Hoje vamos separar três conceitos fundamentais:
Save
Build
Run
e entender também um quarto:
Executable
A ideia central deste capítulo é simples:
salvar não é compilar, compilar não é executar e o executável não é a mesma coisa que o programa em execução.
Essa distinção será essencial quando chegarmos a compilação, linking, DLLs, Debug, Release, automação, testes, CI/CD e distribuição.
1. Nosso projeto continua pequeno
Continuamos com algo conceitualmente próximo de:
07_Game_Engineering_na_Pratica_CPP_SFML/
│
├── CppGameEngine/
│ └── main.cpp
│
├── README.md
├── CHANGELOG.md
├── CONTRIBUTING.md
└── ROADMAP.md
E nosso código:
#include <iostream>
int main()
{
std::cout << "Game Engineering com C++ começou!" << std::endl;
return 0;
}
Ainda não temos SFML.
Ainda não temos Engine.
Ainda não temos classes próprias.
Isso é proposital.
Nosso objetivo agora é entender melhor o ciclo de desenvolvimento de um programa C++.
2. Começando pelo Save
Abra main.cpp.
Altere a mensagem:
std::cout << "Game Engineering com C++ começou!" << std::endl;
para:
std::cout << "Estamos estudando Build, Run e Executable." << std::endl;
Agora pressione:
Ctrl + S
O que aconteceu?
O arquivo foi salvo.
Só isso.
Conceitualmente:
Código no editor
↓
Ctrl + S
↓
Arquivo atualizado no disco
Nenhum novo executável precisa ter sido produzido por causa disso.
Nenhum processo precisa ter sido iniciado.
Salvar significa persistir as alterações feitas no arquivo.
3. O código mudou, mas o executável necessariamente mudou?
Não.
Esse ponto é extremamente importante.
Imagine:
main.cpp antigo
↓
Build
↓
CppGameEngine.exe
Depois alteramos main.cpp:
main.cpp novo
e apenas salvamos.
Agora podemos ter:
main.cpp novo
e, ao mesmo tempo:
CppGameEngine.exe antigo
Ou seja:
o código-fonte atual e o executável existente podem representar momentos diferentes do projeto.
Isso explica situações que confundem muitos iniciantes.
4. “Eu alterei o código, mas continua aparecendo a mensagem antiga”
Imagine que antes tínhamos:
std::cout << "Mensagem antiga" << std::endl;
Fizemos Build.
Depois alteramos para:
std::cout << "Mensagem nova" << std::endl;
Salvamos o arquivo, mas executamos diretamente um .exe antigo que ainda não foi reconstruído.
O que poderá aparecer?
Mensagem antiga
Então pensamos:
“O Visual Studio ignorou meu código.”
Não necessariamente.
O problema pode ser muito mais simples:
Source atual
≠
Executable atual
Precisamos fazer um novo Build para produzir um artefato correspondente ao código atual.
5. Save não é Build
Vamos formalizar:
Save
Ctrl + S
significa, de maneira simplificada:
pegar alterações do editor
↓
gravar no arquivo
Build
Ctrl + Shift + B
significa solicitar que o sistema de build processe o projeto e gere os artefatos necessários.
Conceitualmente:
Source Code
↓
Build
↓
Artifacts
Entre esses artefatos poderá existir:
CppGameEngine.exe
6. O que exatamente é Build?
Até agora tratamos Build como uma caixa-preta.
Fazemos:
Ctrl + Shift + B
e recebemos:
Build succeeded.
Mas a palavra Build não significa apenas “compilar uma linha”.
Ela representa um processo maior de construção do software.
Em nosso projeto atual, uma visão bastante simplificada seria:
main.cpp
↓
compilação
↓
linking
↓
CppGameEngine.exe
Ainda não vamos aprofundar cada estágio.
Isso acontecerá mais adiante.
Por enquanto, queremos apenas entender:
Build é o processo que transforma nosso projeto fonte em artefatos construídos.
7. Artefato?
Em Engenharia de Software, a palavra artifact aparece bastante.
Um artefato é um resultado produzido por algum processo.
No nosso caso, o Build pode produzir coisas como:
Object Files
Debug Information
Intermediate Files
Executable
Não precisamos conhecer todos ainda.
O mais importante neste capítulo é:
CppGameEngine.exe
porque ele é algo que conseguimos executar.
8. Faça um Build agora
Com o código atualizado:
#include <iostream>
int main()
{
std::cout << "Estamos estudando Build, Run e Executable." << std::endl;
return 0;
}
pressione:
Ctrl + Shift + B
Observe a janela Output.
Se tudo estiver correto:
Build succeeded.
Agora temos um novo estado.
Conceitualmente:
main.cpp atualizado
↓
Build
↓
CppGameEngine.exe atualizado
9. Mas Build não significa Run
Fizemos Build.
O código foi processado.
O executável foi produzido.
Mas nosso programa necessariamente foi executado?
Não.
Essa distinção é fundamental.
Podemos construir um programa sem iniciá-lo.
Então:
Build
≠
Run
Build produz.
Run executa.
10. Executando o programa
Agora pressione:
Ctrl + F5
No Visual Studio, isso normalmente corresponde a iniciar a aplicação sem entrar em uma sessão interativa de debugging.
O resultado deverá ser:
Estamos estudando Build, Run e Executable.
Agora executamos algo diferente.
Temos:
Executable
↓
Run
↓
Processo em execução
Chegamos ao quarto conceito deste capítulo.
11. O que é um executable?
Nosso executável é um arquivo.
No Windows, normalmente possui extensão:
.exe
No nosso caso:
CppGameEngine.exe
Ele existe no sistema de arquivos.
Podemos pensar:
CppGameEngine.exe
│
└── arquivo armazenado no disco
Ele não precisa estar sendo executado para existir.
Podemos ter:
CppGameEngine.exe
na pasta do projeto durante horas, dias ou meses sem iniciar o programa.
12. O arquivo executável e o programa rodando não são a mesma coisa
Este é um dos conceitos mais importantes do capítulo.
Temos:
CppGameEngine.exe
como um arquivo.
Quando o sistema operacional inicia esse executável, surge um processo.
Conceitualmente:
CppGameEngine.exe
↓
Sistema operacional inicia
↓
Processo
↓
Código sendo executado
Portanto:
Executable
≠
Process
O executável é um arquivo.
O processo representa uma instância em execução daquele programa.
13. Um executável pode gerar mais de um processo
Imagine que futuramente nosso jogo esteja pronto.
Podemos iniciar:
CppGameEngine.exe
duas vezes.
Dependendo do comportamento permitido pela aplicação, poderíamos ter:
CppGameEngine.exe
↓
Processo A
e novamente:
CppGameEngine.exe
↓
Processo B
O arquivo é o mesmo.
Os processos são instâncias distintas.
Essa diferença será importante quando estudarmos:
memória;
sistema operacional;
debugging;
múltiplas instâncias;
recursos;
IPC;
concorrência.
Ainda não precisamos de tudo isso.
Mas a base começa aqui.
14. Onde está nosso .exe?
Agora vamos procurá-lo.
No Visual Studio, estamos utilizando inicialmente:
Debug
x64
Dependendo de como a solução e o projeto foram criados, o caminho exato pode variar.
Mas você provavelmente encontrará alguma estrutura semelhante a:
x64/
└── Debug/
└── CppGameEngine.exe
ou alguma variação equivalente dentro da estrutura da solução/projeto.
Não memorize um caminho sem verificar sua própria configuração.
Procure fisicamente pelo arquivo.
15. Por que eu quero que você procure o executável?
Porque precisamos eliminar uma ideia perigosa:
“O Visual Studio executa meu código C++ diretamente.”
Não é assim que queremos pensar.
Nosso modelo mental deve começar a evoluir:
main.cpp
↓
Build
↓
CppGameEngine.exe
↓
Sistema operacional
↓
Processo
O Visual Studio está ajudando a coordenar essas etapas.
Mas cada conceito existe separadamente.
16. Executando fora do Visual Studio
Depois de encontrar:
CppGameEngine.exe
feche a execução atual.
Agora tente abrir o executável diretamente pelo Windows Explorer.
Clique duas vezes.
O programa deverá ser iniciado sem que você precise pressionar:
Ctrl + F5
no Visual Studio.
Esse experimento é extremamente importante.
Ele demonstra que:
o executável existe independentemente da IDE.
O Visual Studio é nossa ferramenta de desenvolvimento.
O programa gerado não “mora dentro” do Visual Studio.
17. O console pode fechar rápido
Ao executar diretamente um pequeno programa de console, você pode perceber que a janela abre e fecha rapidamente.
Nosso programa:
int main()
{
std::cout << "Estamos estudando Build, Run e Executable." << std::endl;
return 0;
}
faz basicamente:
inicia
↓
escreve mensagem
↓
return 0
↓
termina
Isso acontece muito rápido.
No Visual Studio, determinadas formas de execução podem manter o console visível para facilitar o desenvolvimento.
Não vamos adicionar artifícios desnecessários apenas para manter a janela aberta.
O comportamento de lifetime do processo será estudado no momento apropriado.
18. O programa termina quando main termina?
Em nosso exemplo simples, podemos pensar assim:
Processo inicia
↓
main()
↓
std::cout
↓
return 0
↓
término normal
Mais adiante essa história ficará mais complexa.
Teremos objetos.
Construtores.
Destrutores.
Recursos.
Threads talvez.
Sistemas.
Mas hoje nosso programa praticamente vive durante a execução de main.
19. Vamos observar o processo acontecendo
Existe uma experiência interessante que podemos fazer.
Nosso programa termina rápido demais para ser fácil observá-lo.
Ainda não estudamos input adequadamente, então não vamos complicar o código apenas para isso.
Mas conceitualmente, quando executamos:
CppGameEngine.exe
o Windows cria um processo.
Podemos observar processos no sistema através do Task Manager / Gerenciador de Tarefas.
Futuramente faremos experimentos mais interessantes com aplicações que permanecem abertas.
Quando tivermos nossa primeira janela SFML, isso ficará visualmente muito mais claro:
CppGameEngine.exe
↓
Processo ativo
↓
Janela aberta
20. Código-fonte não precisa existir para o executável rodar
Aqui vem um experimento conceitual importante.
Imagine que construímos:
CppGameEngine.exe
Depois copiamos apenas esse arquivo para outra pasta.
O executável não precisa abrir main.cpp para executar aquelas instruções.
O código-fonte foi utilizado durante a construção.
Depois temos um artefato executável.
Isso nos leva a:
Source Code
≠
Executable
Nosso .cpp é entrada do processo de desenvolvimento/build.
O .exe é um resultado construído.
21. “Então posso apagar o código-fonte?”
Tecnicamente, possuir o executável não exige que o código-fonte permaneça ao lado dele para iniciar aquela build.
Mas apagar o código-fonte seria uma péssima ideia porque perderíamos nossa capacidade normal de:
entender;
alterar;
corrigir;
reconstruir;
versionar;
evoluir.
Esse experimento serve apenas para compreender a separação conceitual.
É exatamente por isso que temos:
source repository
e:
build artifacts
como responsabilidades distintas.
22. Source Code versus Build Artifact
Podemos classificar:
Source Code
main.cpp
Código que desenvolvedores escrevem e mantêm.
Build Artifact
CppGameEngine.exe
Resultado produzido pelo processo de Build.
Futuramente também poderemos ter artefatos como:
.dll
.lib
.pdb
.zip
installer
test reports
dependendo da evolução do projeto.
Essa terminologia será especialmente importante em CI/CD.
23. O que acontece se alterarmos o source depois do Build?
Vamos experimentar.
Primeiro deixe:
std::cout << "Build 1" << std::endl;
Faça Build.
Execute.
Resultado:
Build 1
Agora altere apenas o código para:
std::cout << "Build 2" << std::endl;
Salve:
Ctrl + S
Mas não faça Build.
Se você executar manualmente o executável antigo existente no disco, qual mensagem esperamos?
Provavelmente:
Build 1
porque o executável ainda corresponde ao Build anterior.
Agora faça:
Ctrl + Shift + B
e execute o artefato novamente.
Esperamos:
Build 2
Esse experimento prova visualmente a diferença entre:
source saved
e:
artifact rebuilt
24. Um pequeno detalhe: a IDE pode construir antes de executar
Aqui precisamos ser cuidadosos.
Ao iniciar o projeto através do Visual Studio, dependendo das configurações e do estado dos arquivos, a IDE pode detectar que o projeto está desatualizado e oferecer ou realizar um Build antes da execução.
Por isso nosso experimento mais claro envolve executar diretamente o .exe antigo.
A ideia não é decorar comportamento específico da IDE.
É entender o princípio:
o executável só muda quando algum processo de Build produz uma nova versão dele.
25. O que significa “out-of-date”?
Durante o desenvolvimento você poderá encontrar mensagens indicando que um projeto está:
out of date
ou desatualizado.
Conceitualmente:
Source mudou
↓
Artifacts existentes foram gerados antes
↓
Projeto precisa ser reconstruído
Ferramentas de build precisam determinar quais partes precisam ser processadas novamente.
Esse assunto ficará muito interessante quando estudarmos incremental builds.
Ainda não precisamos entrar nisso.
26. O Build sempre reconstrói tudo?
Não necessariamente.
Sistemas de build modernos tentam evitar trabalho desnecessário.
Se nada mudou, algumas etapas podem ser consideradas atualizadas.
Você poderá ver mensagens relacionadas a:
up-to-date
Isso significa, de maneira simplificada, que o sistema concluiu que determinado alvo não precisava ser reconstruído.
Mais tarde estudaremos:
incremental build;
dependencies;
timestamps;
build graph;
clean;
rebuild.
Hoje basta perceber que:
Build
não significa obrigatoriamente “refazer absolutamente tudo do zero”.
27. Build Solution
Quando usamos:
Build Solution
estamos solicitando a construção da solution de acordo com suas dependências e configurações.
Hoje nossa solution provavelmente possui apenas:
1 Project
Então parece simples.
No futuro poderemos ter, por exemplo:
Solution
├── Engine
├── Game
├── Tools
└── Tests
ou alguma estrutura que surgirá naturalmente.
Nesse cenário, “Build Solution” terá implicações mais interessantes.
Não criaremos esses projetos agora.
28. Configuration também faz parte do Build
Observe a barra superior:
Debug
x64
Esses dois valores fazem parte do contexto da construção.
Portanto, não existe apenas:
"o executable"
de maneira abstrata.
Podemos possuir artefatos diferentes para:
Debug | x64
e:
Release | x64
Por exemplo:
x64/Debug/CppGameEngine.exe
e:
x64/Release/CppGameEngine.exe
Esses dois executáveis podem ser construídos com configurações diferentes.
29. Debug e Release podem gerar executáveis diferentes
Ainda não estudaremos todas as diferenças.
Mas precisamos começar a entender:
Debug Build
≠
Release Build
Mesmo que ambos produzam:
CppGameEngine.exe
eles podem ter características diferentes.
Mais adiante veremos diferenças envolvendo:
otimização;
símbolos de debug;
macros;
runtime;
comportamento;
performance;
tamanho;
diagnósticos.
Isso será extremamente importante quando integrarmos SFML.
30. E x64?
Da mesma forma:
x64
faz parte da configuração da build.
Uma aplicação construída para:
x64
não é simplesmente “o mesmo arquivo” que uma build:
x86
Arquitetura importa.
Mais adiante teremos situações como:
Application x64
+
Library x64
funcionando corretamente.
Enquanto:
Application x64
+
Library x86
poderá produzir problemas.
Essa é uma das razões pelas quais estamos aprendendo a olhar configurações desde cedo.
31. Run
Agora vamos isolar o segundo grande conceito.
Run significa iniciar o programa.
Temos:
Executable
↓
Operating System
↓
Process
No Visual Studio, usamos:
Ctrl + F5
para executar sem debugger.
Também existe:
F5
que normalmente inicia com debugging.
Essas duas ações não são exatamente iguais.
Mas ambas estão relacionadas à execução.
32. Run sem Debugging versus Start Debugging
Vamos estabelecer apenas a distinção inicial.
Ctrl + F5
Conceitualmente:
Start Without Debugging
Executa a aplicação sem iniciar a sessão normal do debugger.
F5
Conceitualmente:
Start Debugging
Inicia a aplicação integrada ao debugger.
Ainda não precisamos usar breakpoints.
Mas é importante entender por que existem dois comandos diferentes.
Mais adiante aprenderemos a utilizar:
breakpoints
step over
step into
watch
call stack
locals
memory
quando realmente tivermos algo interessante para investigar em runtime.
33. Build não exige execução
Imagine uma pipeline no GitHub no futuro.
Ela poderá fazer:
Checkout
↓
Configure
↓
Build
↓
Tests
Talvez nem exista interface gráfica.
Talvez o objetivo seja apenas verificar:
"o projeto compila?"
Isso demonstra que Build possui valor independentemente da execução manual do jogo.
34. Run também não significa desenvolvimento
Imagine o jogador final.
Ele receberá algo como:
Game.exe
Assets/
Dependencies/
Config/
O jogador não precisa:
Visual Studio
main.cpp
Ctrl + Shift + B
para jogar.
Ele apenas executa o produto distribuído.
Desenvolvimento e execução do produto final são experiências diferentes.
35. Isso nos aproxima da ideia de distribuição
Ainda estamos muito longe de publicar nosso jogo.
Mas já podemos enxergar a sequência:
Source Code
↓
Build
↓
Executable + Dependencies + Assets
↓
Packaging
↓
Distribution
↓
User Executes
No fim da série trabalharemos muito mais profundamente com isso.
Hoje estamos aprendendo o primeiro elo.
36. Build directory não é source directory
À medida que o projeto crescer, veremos uma separação entre:
Source Files
e:
Generated Files
Essa diferença será importante para Git.
Não queremos versionar indiscriminadamente:
.exe
.obj
.pdb
build cache
temporary files
IDE files
se eles são reproduzíveis através do Build.
O repositório deve conter principalmente aquilo necessário para reconstruir o projeto.
37. Por que não colocar o .exe no Git?
Para nosso fluxo de desenvolvimento, normalmente não queremos versionar binários gerados em cada Build.
Por quê?
Porque eles:
podem ser recriados;
mudam frequentemente;
são binários;
aumentam o repositório;
podem depender de configuração;
podem ser específicos de plataforma;
não mostram diff útil como código-fonte.
Mais tarde poderemos disponibilizar executáveis como:
Release Artifacts
por meio das Releases do GitHub ou outro canal.
Isso é diferente de versionar cada build no histórico do código.
38. Nosso .gitignore começa a fazer mais sentido
No Capítulo 01 mencionamos que arquivos gerados não devem entrar indiscriminadamente no Git.
Agora temos uma razão mais concreta.
Queremos algo conceitualmente assim:
Git Repository
├── source code
├── project files
├── documentation
└── configuration necessária
e não necessariamente:
Git Repository
├── source
├── every .exe
├── every .obj
├── caches
├── local IDE state
└── every generated file
Quando aprofundarmos Git, refinaremos isso.
39. Clean
No Visual Studio existe também a ideia de:
Clean
O objetivo é remover artefatos produzidos por builds anteriores.
Conceitualmente:
Source
+
Generated Build Artifacts
depois de Clean:
Source
+
menos artefatos gerados
Não significa apagar nosso main.cpp.
Esse é um ponto importante.
Clean atua sobre resultados da construção, não sobre nosso código-fonte.
40. Rebuild
Também encontraremos:
Rebuild
Conceitualmente:
Clean
+
Build novamente
Em vez de tentar reaproveitar artefatos considerados atualizados, o processo força uma reconstrução mais completa.
Ainda não precisamos usar Rebuild constantemente.
Na realidade, fazer Rebuild para todo problema pode esconder nossa falta de compreensão.
Primeiro queremos entender o que estamos investigando.
41. Build versus Rebuild
Podemos pensar inicialmente:
Build
│
└── constrói o necessário
Rebuild
│
├── remove artefatos anteriores
└── constrói novamente
Quando nosso projeto crescer, Rebuild será mais caro.
Imagine:
Build incremental: 4 segundos
Rebuild completo: 4 minutos
ou mais em projetos grandes.
Então entender a diferença deixa de ser apenas curiosidade.
Afeta produtividade.
42. Clean, Build e Run são independentes
Podemos ter:
Clean
sem Run.
Podemos ter:
Build
sem Run.
Podemos ter um executável já existente e fazer:
Run
sem novo Build.
Portanto:
Clean
Build
Run
são operações distintas.
Ferramentas podem encadeá-las automaticamente em alguns contextos, mas isso não apaga suas responsabilidades.
43. Uma analogia simples
Pense em um livro.
Source
O arquivo editável:
manuscrito
Save
Você grava as mudanças do manuscrito.
Build
Você produz uma versão final diagramada e exportada.
Executable
No nosso caso não é PDF, claro, mas podemos pensar como o artefato final produzido.
Run
Seria “usar” aquele artefato.
A analogia não é perfeita.
Mas ajuda a separar:
conteúdo fonte
de:
artefato produzido
44. Outra analogia: receita e bolo
Imagine:
Receita
↓
Preparação
↓
Bolo
Nosso source é mais próximo da receita.
Build é o processo de transformação.
Executable é o resultado construído.
Run é consumir/iniciar aquele resultado.
Novamente, analogia limitada.
Mas ela ajuda a evitar:
“main.cppé o programa executável."
Não é.
45. O sistema operacional não executa nosso main.cpp
Quando damos dois cliques em:
CppGameEngine.exe
o Windows trabalha com o executável.
Ele não abre:
main.cpp
para interpretar nossas instruções diretamente.
Isso diferencia nosso fluxo C++ de modelos utilizados por algumas outras tecnologias.
Não vamos comparar linguagens profundamente agora.
Mas essa característica é central para compreender C++.
46. “Mas o Visual Studio sabe abrir main.cpp"
Sim.
Porque o Visual Studio é nossa ferramenta de desenvolvimento.
Ele trabalha com:
source files
project metadata
build configuration
debug configuration
O sistema operacional, ao iniciar nosso produto construído, trabalha com o executável e suas dependências.
Esses papéis são diferentes.
47. Estamos começando a separar Development Time e Runtime
Vamos introduzir duas expressões que serão úteis futuramente.
Development Time
Enquanto estamos construindo o software:
editar
salvar
compilar
linkar
testar
depurar
Runtime
Enquanto o programa está efetivamente em execução.
Muitos problemas pertencem a momentos diferentes.
Exemplo:
missing semicolon
é detectado antes de runtime.
Enquanto algo como:
divisão por zero em determinada condição
pode aparecer durante execução.
Essa distinção continuará crescendo.
48. O executable está parado no disco
Quando nosso jogo não está aberto:
CppGameEngine.exe
continua sendo apenas um arquivo.
Quando executamos:
disk
↓
loader / operating system
↓
memory
↓
process
Uma instância do programa passa a existir em memória.
Essa relação nos prepara para um assunto enorme que veremos futuramente:
memória.
49. Arquivo no disco versus dados em memória
Hoje basta pensar:
Disk
│
└── CppGameEngine.exe
Memory
│
└── processo em execução
Isso não significa que o executável inteiro simplesmente seja copiado de maneira trivial para RAM.
O sistema operacional faz muito mais que isso.
Mas ainda não precisamos aprofundar loaders, virtual memory, pages ou sections.
Queremos apenas construir a separação conceitual correta.
50. O processo possui estado
Nosso executável armazenado no disco não possui:
playerHealth atual
playerCoins atual
posição atual
tempo atual da sessão
Esses valores farão sentido quando o programa estiver rodando e possuir estado em memória.
Imagine futuramente:
CppGameEngine.exe
↓
Processo
↓
playerHealth = 100
playerCoins = 25
currentDay = 4
Fechamos o processo.
Esses valores em memória desaparecem, a menos que os persistamos em algum lugar.
Isso nos levará, muito mais tarde, a Save/Load.
Percebe como conceitos pequenos se conectam?
51. Executable não contém automaticamente nosso save atual
Nosso .exe representa código e dados necessários ao programa construído.
Run significa iniciar o programa.
Temos:
Executable
↓
Operating System
↓
Process
No Visual Studio, usamos:
Ctrl + F5
para executar sem debugger.
Também existe:
F5
que normalmente inicia com debugging.
Essas duas ações não são exatamente iguais.
Mas ambas estão relacionadas à execução.
32. Run sem Debugging versus Start Debugging
Vamos estabelecer apenas a distinção inicial.
Ctrl + F5
Conceitualmente:
Start Without Debugging
Executa a aplicação sem iniciar a sessão normal do debugger.
F5
Conceitualmente:
Start Debugging
Inicia a aplicação integrada ao debugger.
Ainda não precisamos usar breakpoints.
Mas é importante entender por que existem dois comandos diferentes.
Mais adiante aprenderemos a utilizar:
breakpoints
step over
step into
watch
call stack
locals
memory
quando realmente tivermos algo interessante para investigar em runtime.
33. Build não exige execução
Imagine uma pipeline no GitHub no futuro.
Ela poderá fazer:
Checkout
↓
Configure
↓
Build
↓
Tests
Talvez nem exista interface gráfica.
Talvez o objetivo seja apenas verificar:
"o projeto compila?"
Isso demonstra que Build possui valor independentemente da execução manual do jogo.
34. Run também não significa desenvolvimento
Imagine o jogador final.
Ele receberá algo como:
Game.exe
Assets/
Dependencies/
Config/
O jogador não precisa:
Visual Studio
main.cpp
Ctrl + Shift + B
para jogar.
Ele apenas executa o produto distribuído.
Desenvolvimento e execução do produto final são experiências diferentes.
35. Isso nos aproxima da ideia de distribuição
Ainda estamos muito longe de publicar nosso jogo.
Mas já podemos enxergar a sequência:
Source Code
↓
Build
↓
Executable + Dependencies + Assets
↓
Packaging
↓
Distribution
↓
User Executes
No fim da série trabalharemos muito mais profundamente com isso.
Hoje estamos aprendendo o primeiro elo.
36. Build directory não é source directory
À medida que o projeto crescer, veremos uma separação entre:
Source Files
e:
Generated Files
Essa diferença será importante para Git.
Não queremos versionar indiscriminadamente:
.exe
.obj
.pdb
build cache
temporary files
IDE files
se eles são reproduzíveis através do Build.
O repositório deve conter principalmente aquilo necessário para reconstruir o projeto.
37. Por que não colocar o .exe no Git?
Para nosso fluxo de desenvolvimento, normalmente não queremos versionar binários gerados em cada Build.
Por quê?
Porque eles:
podem ser recriados;
mudam frequentemente;
são binários;
aumentam o repositório;
podem depender de configuração;
podem ser específicos de plataforma;
não mostram diff útil como código-fonte.
Mais tarde poderemos disponibilizar executáveis como:
Release Artifacts
por meio das Releases do GitHub ou outro canal.
Isso é diferente de versionar cada build no histórico do código.
38. Nosso .gitignore começa a fazer mais sentido
No Capítulo 01 mencionamos que arquivos gerados não devem entrar indiscriminadamente no Git.
Agora temos uma razão mais concreta.
Queremos algo conceitualmente assim:
Git Repository
├── source code
├── project files
├── documentation
└── configuration necessária
e não necessariamente:
Git Repository
├── source
├── every .exe
├── every .obj
├── caches
├── local IDE state
└── every generated file
Quando aprofundarmos Git, refinaremos isso.
39. Clean
No Visual Studio existe também a ideia de:
Clean
O objetivo é remover artefatos produzidos por builds anteriores.
Conceitualmente:
Source
+
Generated Build Artifacts
depois de Clean:
Source
+
menos artefatos gerados
Não significa apagar nosso main.cpp.
Esse é um ponto importante.
Clean atua sobre resultados da construção, não sobre nosso código-fonte.
40. Rebuild
Também encontraremos:
Rebuild
Conceitualmente:
Clean
+
Build novamente
Em vez de tentar reaproveitar artefatos considerados atualizados, o processo força uma reconstrução mais completa.
Ainda não precisamos usar Rebuild constantemente.
Na realidade, fazer Rebuild para todo problema pode esconder nossa falta de compreensão.
Primeiro queremos entender o que estamos investigando.
41. Build versus Rebuild
Podemos pensar inicialmente:
Build
│
└── constrói o necessário
Rebuild
│
├── remove artefatos anteriores
└── constrói novamente
Quando nosso projeto crescer, Rebuild será mais caro.
Imagine:
Build incremental: 4 segundos
Rebuild completo: 4 minutos
ou mais em projetos grandes.
Então entender a diferença deixa de ser apenas curiosidade.
Afeta produtividade.
42. Clean, Build e Run são independentes
Podemos ter:
Clean
sem Run.
Podemos ter:
Build
sem Run.
Podemos ter um executável já existente e fazer:
Run
sem novo Build.
Portanto:
Clean
Build
Run
são operações distintas.
Ferramentas podem encadeá-las automaticamente em alguns contextos, mas isso não apaga suas responsabilidades.
43. Uma analogia simples
Pense em um livro.
Source
O arquivo editável:
manuscrito
Save
Você grava as mudanças do manuscrito.
Build
Você produz uma versão final diagramada e exportada.
Executable
No nosso caso não é PDF, claro, mas podemos pensar como o artefato final produzido.
Run
Seria “usar” aquele artefato.
A analogia não é perfeita.
Mas ajuda a separar:
conteúdo fonte
de:
artefato produzido
44. Outra analogia: receita e bolo
Imagine:
Receita
↓
Preparação
↓
Bolo
Nosso source é mais próximo da receita.
Build é o processo de transformação.
Executable é o resultado construído.
Run é consumir/iniciar aquele resultado.
Novamente, analogia limitada.
Mas ela ajuda a evitar:
“main.cppé o programa executável."
Não é.
45. O sistema operacional não executa nosso main.cpp
Quando damos dois cliques em:
CppGameEngine.exe
o Windows trabalha com o executável.
Ele não abre:
main.cpp
para interpretar nossas instruções diretamente.
Isso diferencia nosso fluxo C++ de modelos utilizados por algumas outras tecnologias.
Não vamos comparar linguagens profundamente agora.
Mas essa característica é central para compreender C++.
46. “Mas o Visual Studio sabe abrir main.cpp"
Sim.
Porque o Visual Studio é nossa ferramenta de desenvolvimento.
Ele trabalha com:
source files
project metadata
build configuration
debug configuration
O sistema operacional, ao iniciar nosso produto construído, trabalha com o executável e suas dependências.
Esses papéis são diferentes.
47. Estamos começando a separar Development Time e Runtime
Vamos introduzir duas expressões que serão úteis futuramente.
Development Time
Enquanto estamos construindo o software:
editar
salvar
compilar
linkar
testar
depurar
Runtime
Enquanto o programa está efetivamente em execução.
Muitos problemas pertencem a momentos diferentes.
Exemplo:
missing semicolon
é detectado antes de runtime.
Enquanto algo como:
divisão por zero em determinada condição
pode aparecer durante execução.
Essa distinção continuará crescendo.
48. O executable está parado no disco
Quando nosso jogo não está aberto:
CppGameEngine.exe
continua sendo apenas um arquivo.
Quando executamos:
disk
↓
loader / operating system
↓
memory
↓
process
Uma instância do programa passa a existir em memória.
Essa relação nos prepara para um assunto enorme que veremos futuramente:
memória.
49. Arquivo no disco versus dados em memória
Hoje basta pensar:
Disk
│
└── CppGameEngine.exe
Memory
│
└── processo em execução
Isso não significa que o executável inteiro simplesmente seja copiado de maneira trivial para RAM.
O sistema operacional faz muito mais que isso.
Mas ainda não precisamos aprofundar loaders, virtual memory, pages ou sections.
Queremos apenas construir a separação conceitual correta.
50. O processo possui estado
Nosso executável armazenado no disco não possui:
playerHealth atual
playerCoins atual
posição atual
tempo atual da sessão
Esses valores farão sentido quando o programa estiver rodando e possuir estado em memória.
Imagine futuramente:
CppGameEngine.exe
↓
Processo
↓
playerHealth = 100
playerCoins = 25
currentDay = 4
Fechamos o processo.
Esses valores em memória desaparecem, a menos que os persistamos em algum lugar.
Isso nos levará, muito mais tarde, a Save/Load.
Percebe como conceitos pequenos se conectam?
51. Executable não contém automaticamente nosso save atual
Nosso .exe representa código e dados necessários ao programa construído.
O progresso do jogador será outro tipo de informação.
Futuramente teremos algo como:
Game Executable
+
Assets
+
Configuration
+
Save Data
Cada elemento possui responsabilidade diferente.
Mas precisamos primeiro aprender a separar source, executable e runtime.
52. Um primeiro mapa técnico
Agora podemos representar nossa jornada atual:
main.cpp
│
│ Save
▼
arquivo fonte atualizado
│
│ Build
▼
CppGameEngine.exe
│
│ Run
▼
Processo em execução
│
▼
std::cout
│
▼
Console
Esse modelo ainda é incompleto.
Mas já é muito melhor que:
"apertei Play e C++ rodou"
53. Vamos fazer um experimento controlado completo
Vamos usar o que aprendemos.
Comece com:
#include <iostream>
int main()
{
std::cout << "Version A" << std::endl;
return 0;
}
Passo 1 — Save
Ctrl + S
Passo 2 — Build
Ctrl + Shift + B
Passo 3 — Run
Ctrl + F5
Resultado:
Version A
Agora altere:
std::cout << "Version B" << std::endl;
Salve.
Localize e execute manualmente o .exe antigo sem reconstruir.
Observe o resultado.
Depois faça novo Build.
Execute novamente.
Compare.
Esse experimento deve consolidar a diferença entre as etapas.
54. Verifique o timestamp do arquivo
Outra observação interessante:
localize:
CppGameEngine.exe
e veja sua data/hora de modificação.
Faça uma alteração real.
Salve apenas.
Observe o executável novamente.
Depois faça Build.
Confira o timestamp.
Essa é mais uma evidência física de que:
Save
e:
Build
produzem efeitos diferentes.
55. E se o Build falhar?
Considere:
std::cout << "Version C" << std::endl
sem:
;
Faça Save.
Depois Build.
O Build falha.
O que acontece com nosso executável anterior?
Dependendo do estado da pasta, o executável da última build bem-sucedida pode continuar existindo.
Isso pode produzir uma armadilha.
56. Executable antigo após Build failed
Imagine:
Build 1
↓
CppGameEngine.exe válido
Código alterado com erro
↓
Build 2
↓
FAILED
Talvez ainda exista:
CppGameEngine.exe
da Build 1.
Então alguém pode executá-lo e pensar:
“Mas meu programa está funcionando!”
Na realidade, está executando uma versão anterior.
Isso acontece bastante.
57. Build succeeded importa
Quando fazemos alterações, não basta pressionar o botão e presumir que tudo aconteceu corretamente.
Observe:
Build succeeded
ou:
Build failed
A saída do Build faz parte da validação.
Se o Build falhou, você não deve assumir que o executável existente representa o código atual.
58. Essa diferença ajuda no debugging
Imagine:
“Eu corrigi a mensagem, mas continua aparecendo a antiga.”
Perguntas úteis:
Salvei o arquivo?
↓
O Build realmente foi executado?
↓
O Build terminou com sucesso?
↓
Estou executando o .exe correto?
↓
Estou na configuração correta?
↓
Estou executando Debug ou Release?
↓
Existe outro executável em outra pasta?
Observe como conhecer o processo muda nossa investigação.
59. “Estou executando o executable correto?”
Essa pergunta será extremamente importante quando tivermos:
Debug/
└── Game.exe
Release/
└── Game.exe
Talvez você atualize Debug e execute manualmente Release.
Ou o contrário.
Ambos podem possuir o mesmo nome:
Game.exe
mas representar builds diferentes.
Por isso path e configuração importam.
60. O mesmo nome não significa o mesmo arquivo
Considere:
x64/Debug/CppGameEngine.exe
e:
x64/Release/CppGameEngine.exe
Os dois nomes finais são:
CppGameEngine.exe
Mas os caminhos são diferentes.
Portanto, são arquivos diferentes.
Esse princípio vale para muitos recursos no desenvolvimento.
Contexto importa.
61. Build Configuration é parte do diagnóstico
Quando futuramente pedirmos ajuda para um problema, não basta dizer:
“Estou rodando o jogo.”
Precisamos talvez informar:
Visual Studio 2022
C++20
Debug
x64
MSVC
Por quê?
Porque o comportamento pode variar por configuração.
Em alguns bugs teremos:
Debug works
Release fails
Essa diferença será um sinal extremamente importante.
62. Build e Run também são separados em CI/CD
No futuro, uma pipeline poderá fazer:
Checkout
↓
Build Debug
↓
Run Tests
↓
Build Release
↓
Package
Observe:
Build
e:
Run Tests
são etapas separadas.
Automação deixa essas diferenças ainda mais explícitas.
63. Um jogo comercial precisa de builds reproduzíveis
Imagine que publiquemos a versão:
1.0.0
Se um bug grave aparecer, precisamos saber:
qual código produziu aquela build;
quais dependências foram utilizadas;
qual configuração;
qual compilador;
quais assets;
qual versão;
qual artefato foi distribuído.
Por isso Build Engineering é uma disciplina séria.
Estamos apenas dando o primeiro passo.
64. O .exe não é necessariamente suficiente
Hoje nosso pequeno programa provavelmente executa com poucas preocupações extras.
Mas quando adicionarmos SFML teremos dependências adicionais.
Podemos chegar a algo como:
CppGameEngine.exe
+
sfml-graphics-3.dll
+
sfml-window-3.dll
+
sfml-system-3.dll
+
assets
dependendo da forma de integração.
Então descobriríamos rapidamente que:
possuir apenas o
.exenem sempre significa possuir tudo necessário para executar o programa.
Isso será estudado quando integrarmos a biblioteca.
65. Essa é a origem de muitos erros de DLL
Futuramente poderemos encontrar mensagens relacionadas a:
DLL not found
ou erros de inicialização.
Quando isso acontecer, já saberemos distinguir:
Source
Build
Executable
Runtime Dependencies
Process
Isso torna o troubleshooting muito mais claro.
66. O que significa “programa”?
A palavra “programa” pode ser utilizada informalmente para várias coisas.
Às vezes alguém diz:
“Meu programa está nesta pasta.”
e aponta para:
CppGameEngine.exe
Em outro contexto:
“Meu programa travou.”
e está falando do processo em execução.
Ou:
“Estou escrevendo meu programa.”
e está falando do source.
Não precisamos proibir o uso informal.
Mas tecnicamente queremos saber diferenciar:
source code
build artifacts
executable
process
quando a precisão for necessária.
67. Build não é Compiler
Outra distinção que prepararemos agora:
Build
≠
Compiler
O compilador é uma ferramenta envolvida no processo.
Build é um processo mais amplo.
Conceitualmente:
Build
├── preprocessing
├── compilation
├── linking
└── artifact generation
Essa representação ainda é simplificada.
Nos próximos capítulos técnicos aprofundaremos cada etapa.
68. Compiler também não é Linker
Você já viu no Roadmap que estudaremos erros como:
LNK2019
unresolved external symbol
Esses erros não são simplesmente erros de sintaxe.
Eles surgem em outra etapa.
Por isso precisamos aprender:
Compiler
≠
Linker
Mas ainda não vamos abrir essa caixa totalmente hoje.
Primeiro precisamos dominar a visão macro.
69. Nossa visão macro agora é esta
SOURCE
main.cpp
↓
BUILD
processo de construção
↓
ARTIFACT
CppGameEngine.exe
↓
RUN
solicitação de execução
↓
PROCESS
programa ativo
Essa sequência é o centro deste capítulo.
70. E onde entra Ctrl + S?
Antes de Build:
Editor
↓
Ctrl + S
↓
main.cpp salvo
Então nosso fluxo completo fica:
Editar
↓
Save
↓
Source atualizado
↓
Build
↓
Executable atualizado
↓
Run
↓
Processo
↓
Resultado
Agora começamos a possuir um ciclo de desenvolvimento mais consciente.
71. O ciclo de desenvolvimento atual
Nosso fluxo de trabalho pode ser descrito como:
EDIT
↓
SAVE
↓
BUILD
↓
RUN
↓
OBSERVE
↓
MODIFY
↓
REPEAT
Em breve adicionaremos:
DEBUG
TEST
Depois:
PROFILE
PACKAGE
RELEASE
O ciclo crescerá junto do software.
72. Um erro em cada etapa produz sintomas diferentes
Imagine:
Save
Problema no sistema de arquivos ou permissões.
Build
Erro de compilação ou linking.
Run
Executable inexistente ou problema de inicialização.
Runtime
Crash ou comportamento incorreto.
Portanto, perguntar:
“Em que etapa o problema aconteceu?”
já reduz bastante nosso espaço de investigação.
73. O primeiro passo do troubleshooting agora pode ser
Antes:
deu erro
Agora:
O erro aconteceu:
- ao salvar?
- durante Build?
- ao iniciar?
- durante execução?
Essa classificação simples já é extremamente poderosa.
74. Vamos provocar um cenário completo
Use:
#include <iostream>
int main()
{
std::cout << "Stable build" << std::endl;
return 0;
}
Faça:
Save
Build
Run
Tudo funciona.
Agora altere para:
#include <iostream>
int main()
{
std::cout << "Broken build" << std::endl
return 0;
}
Faça Save.
O arquivo foi salvo com sucesso.
Faça Build.
Falha.
Observe:
Save succeeded
Build failed
São resultados diferentes.
75. O código inválido pode ser salvo normalmente
Esse detalhe é importante.
O editor pode salvar:
std::cout << "Broken build" << std::endl
mesmo que o código seja inválido para compilação.
O sistema de arquivos não entende C++ nesse nível.
Para ele, main.cpp é um arquivo contendo bytes/texto.
Quem verifica as regras da linguagem durante construção é a toolchain.
Isso demonstra novamente:
Save
≠
Compile
76. “Salvar” não valida nosso C++
Exatamente.
Ter:
main.cpp
gravado corretamente no disco não significa:
C++ válido
nem:
Build bem-sucedido
nem:
Programa correto
São níveis diferentes de validação.
77. E Build succeeded não significa software correto
Também precisamos lembrar do capítulo anterior.
Temos:
Build succeeded
mas talvez:
Game Logic incorrect
Portanto:
Save succeeded
≠
Build succeeded
e:
Build succeeded
≠
Behavior correct
e:
Behavior correct em um teste
≠
Software completo e correto
É por isso que teremos testes e QA.
78. Um exemplo de game logic
#include <iostream>
int main()
{
std::cout << "Player Coins: 999999" << std::endl;
return 0;
}
Pode compilar.
Pode executar.
Mas talvez o jogador devesse iniciar com:
25
O pipeline técnico funcionou.
A regra funcional está errada.
Diferentes camadas de qualidade exigem diferentes formas de validação.
79. Build engineering não substitui testing
Build responde perguntas como:
conseguimos construir este software?
Testes respondem perguntas diferentes:
determinados comportamentos estão corretos?
QA vai ainda mais longe:
o produto atende expectativas de qualidade no contexto real?
Tudo isso aparecerá ao longo da série.
Mas a primeira base é saber o que estamos construindo e executando.
80. Nosso primeiro diagrama completo
Vamos consolidar:
DEVELOPMENT
main.cpp
│
│ Edit
▼
main.cpp
│
│ Save
▼
Source persisted
│
│ Build
▼
Build system / tools
│
▼
CppGameEngine.exe
│
│ Run
▼
Operating System
│
▼
Process
│
▼
Program behavior
Ainda não representa detalhes de compilação.
Mas já nos dá um mapa.
81. Microdesafio 1 — classifique cada ação
Classifique:
Situação A
Você altera:
std::cout << "Hello";
e pressiona Ctrl + S.
Resposta esperada:
Save
Situação B
Você pressiona Ctrl + Shift + B.
Resposta:
Build
Situação C
Você abre CppGameEngine.exe.
Resposta:
Run
Situação D
O Windows mostra CppGameEngine.exe no disco.
Resposta:
Executable / Build Artifact
Situação E
O jogo aparece no Gerenciador de Tarefas.
Resposta:
Process
82. Microdesafio 2 — encontre a inconsistência
Imagine:
main.cpp:
"Version 2"
Executable:
construído ontemÚltimo Build:
failedPrograma executado:
"Version 1"
Existe necessariamente um mistério?
Não.
Uma explicação muito provável:
o executável disponível ainda corresponde à última build bem-sucedida.
Isso é exatamente o tipo de raciocínio que queremos desenvolver.
83. Microdesafio 3 — faça o experimento das versões
Crie:
#include <iostream>
int main()
{
std::cout << "Executable Version 1" << std::endl;
return 0;
}
Faça:
Save
Build
Depois altere apenas o source para:
std::cout << "Executable Version 2" << std::endl;
Faça apenas:
Save
Execute manualmente o executável anterior.
Depois:
Build
Run
Observe a diferença.
Não apenas leia este experimento.
Faça.
84. Microdesafio 4 — encontre o executable
Sem usar pesquisa na internet, encontre no seu próprio projeto:
CppGameEngine.exe
Depois responda:
Qual configuração gerou este arquivo?
Qual plataforma?
Qual pasta?
Qual horário de modificação?
Esse pequeno exercício começa a treinar familiaridade com nossa build.
85. Microdesafio 5 — explique com suas palavras
Tente explicar sem voltar ao artigo:
Qual a diferença entre Save, Build, Executable, Run e Process?
Uma resposta possível:
Save grava o código-fonte. Build transforma o projeto em artefatos. O executable é um desses artefatos. Run solicita ao sistema operacional que inicie esse executável. O processo é a instância do programa em execução.
Se você consegue explicar isso, o objetivo central do capítulo foi atingido.
86. Precisamos alterar nosso main.cpp permanentemente?
Não necessariamente.
Os textos:
Version A
Version B
Stable build
Broken build
foram apenas experimentos.
Podemos voltar ao estado simples:
#include <iostream>
int main()
{
std::cout << "Game Engineering com C++ começou!" << std::endl;
return 0;
}
O aprendizado deste capítulo foi principalmente conceitual e operacional.
87. O projeto ainda não precisa crescer
Nossa arquitetura continua:
CppGameEngine/
└── main.cpp
Não precisamos criar:
BuildManager
ExecutableManager
ProcessManager
Isso seria um exemplo perfeito de abstração sem necessidade.
Estamos aprendendo conceitos da toolchain.
Não construindo classes para representar cada substantivo encontrado no artigo.
88. Nem todo conceito precisa virar classe
Essa regra merece ser registrada cedo.
Aprendemos:
Build
Process
Executable
Isso não significa:
class Build
{
};
ou:
class Process
{
};
Arquitetura não é transformar todo termo técnico em objeto.
Classes aparecerão quando houver responsabilidade real que nosso software precise representar.
89. Precisamos de commit?
Se o estado final do código for exatamente o mesmo do capítulo anterior, não precisamos criar commit apenas porque aprendemos novos conceitos.
Mas existe uma possibilidade interessante.
Se neste momento você adicionar ou ajustar um .gitignore para impedir que artefatos de build e arquivos locais sejam versionados, isso representa uma mudança real.
Nesse caso, um commit poderia ser:
git add .gitignore
git commit -m "build: ignore generated Visual Studio files"
Mas somente se o .gitignore realmente foi criado ou alterado.
Não criaremos commits fictícios.
90. E o CHANGELOG?
Também não precisa mudar apenas porque localizamos um .exe.
O CHANGELOG deve refletir alterações reais e relevantes do software.
Aprendizado editorial pertence ao artigo.
Mudanças do código pertencem ao Git.
Essa separação continua válida.
91. O ROADMAP mudou?
O Capítulo 04 é parte da jornada educacional.
Nosso ROADMAP técnico possui itens relacionados à fundação e, mais adiante, ao processo de compilação/linking.
Só devemos marcar itens como concluídos quando realmente atingirmos o objetivo técnico descrito.
Por exemplo, entender conceitualmente Build não significa necessariamente concluir toda a fase de compilação e linking.
Ainda existe bastante coisa pela frente.
92. Onde estamos no Roadmap educacional?
Até aqui:
Capítulo 00
↓
Visão da jornada
Capítulo 01
↓
Primeiro programa C++Capítulo 02
↓
Anatomia do códigoCapítulo 03
↓
Erros e troubleshootingCapítulo 04
↓
Save, Build, Executable e Run
Agora temos base suficiente para avançar à programação propriamente dita com dados.
E esse próximo passo é muito importante.
93. Nosso programa ainda não consegue lembrar nada
Observe:
std::cout << "Player Health: 100" << std::endl;
O número:
100
está preso dentro de uma string.
Nosso programa não possui uma informação chamada:
playerHealth
Ele possui apenas texto.
Se quisermos:
Player toma dano
↓
Health diminui
↓
Nova Health aparece
precisamos de algo que represente aquele dado.
Agora surge um problema concreto.
94. Precisamos armazenar estado
Imagine nosso futuro jogo:
Player
├── Health
├── Energy
├── Coins
└── Experience
Se essas informações mudarem durante a execução, precisamos armazená-las.
Por exemplo:
Health
100
↓
leva dano
↓
80
Essa transformação exige algo que ainda não estudamos formalmente.
Variáveis.
95. Agora variáveis têm uma razão para existir
Poderíamos ter começado esta série com:
int x = 10;
e dito:
“Isso é uma variável.”
Mas agora existe um problema real.
Nosso futuro jogador precisa possuir informações mutáveis.
Então algo como:
int playerHealth = 100;
começa a fazer sentido.
Observe também nossa convenção:
playerHealth
utiliza:
camelCase
porque é uma variável.
E está em inglês.
Estamos começando a usar nossas decisões de nomenclatura em código real.
Conclusão
Neste capítulo separamos conceitos que parecem semelhantes quando começamos a programar.
Aprendemos que:
Save
grava alterações no arquivo.
Que:
Build
executa o processo de construção do projeto.
Que:
CppGameEngine.exe
é um artefato produzido pelo Build.
Que:
Run
inicia o executável.
E que:
Process
é uma instância do programa em execução.
Nossa visão evoluiu de:
"Eu aperto Play e o C++ roda."
para:
Source
↓
Save
↓
Build
↓
Executable
↓
Run
↓
Process
↓
Behavior
Também aprendemos que:
Source atualizado
≠
Executable atualizado
se ainda não houve novo Build.
Que um Build falho pode deixar um executável anterior no disco.
Que:
Debug
e:
Release
podem produzir builds distintas.
Que:
x64
faz parte da configuração.
E que o executável armazenado no disco não é a mesma coisa que o processo vivo em memória.
Esses conceitos parecem simples.
Mas eles serão fundamentais quando chegarmos a:
compilação;
linker;
bibliotecas;
SFML;
DLLs;
testes;
Debug/Release;
CI/CD;
packaging;
distribuição.
Agora nosso ciclo está mais claro:
EDIT
↓
SAVE
↓
BUILD
↓
RUN
↓
OBSERVE
↓
UNDERSTAND
↓
EVOLVE
E finalmente podemos começar a fazer nosso programa guardar alguma coisa.
Próximo capítulo
Capítulo 05 — Variáveis: nosso futuro jogo precisa lembrar informações
No próximo artigo deixaremos de imprimir apenas valores fixos como:
std::cout << "Player Health: 100" << std::endl;
e começaremos a representar dados reais em memória.
Vamos criar algo como:
int playerHealth = 100;
e entender, passo a passo:
o que é uma variável;
por que programas precisam armazenar estado;
o que significa declarar;
o que significa inicializar;
o papel do nome;
o papel do valor;
como ler uma variável;
como alterar uma variável;
como imprimir seu conteúdo;
por que nomes importam;
por que utilizaremos
camelCaseem variáveis;como variáveis começam a representar o estado do nosso futuro jogo.
E finalmente nosso programa poderá sair de:
"Health: 100"
para algo conceitualmente mais poderoso:
playerHealth
↓
valor atual
↓
pode mudar durante a execução
Será o primeiro passo para nosso software começar a possuir estado de verdade.
Comentários
Ainda não há comentários. Sê o primeiro a comentar!