Aeca

Capítulo 05 — Variáveis: nosso futuro jogo precisa lembrar informações

Série: Do zero ao jogo comercial com C++ e SFML

Capítulo 05 — Variáveis: nosso futuro jogo precisa lembrar informações
aeca

Nosso primeiro passo para transformar mensagens fixas em um programa que possui estado

Até agora, nosso projeto sabe fazer algo muito simples:

  #include <iostream>

int main()
{
    std::cout << "Game Engineering com C++ começou!" << std::endl;
    return 0;
}

Nos capítulos anteriores aprendemos a:

  • criar nosso primeiro programa;

  • compreender sua estrutura básica;

  • quebrá-lo propositalmente;

  • interpretar os primeiros erros;

  • diferenciar código-fonte, Build, executável e execução.

Mas existe uma limitação importante.

Nosso programa ainda não lembra informações.

Se escrevermos:

  std::cout << "Player Health: 100" << std::endl;

vemos:

  Player Health: 100

Mas esse 100 faz parte do texto.

Nosso programa não possui realmente algo chamado:

  playerHealth

Ele simplesmente imprimiu caracteres no console.

Para começarmos a construir um jogo, isso não será suficiente.

Um jogo precisa conhecer informações como:

  Health
Energy
Coins
Level
Experience
Score

E, mais importante:

essas informações precisam poder mudar enquanto o jogo está sendo executado.

É aqui que entram as variáveis.


1. Começando pelo problema

Imagine nosso futuro jogo.

O jogador começa com:

  Health: 100
Coins: 25
Level: 1

Durante a partida ele recebe dano:

  Health: 100
   ↓
Health: 80

Depois vende algum recurso:

  Coins: 25
   ↓
Coins: 35

Mais tarde sobe de nível:

  Level: 1
   ↓
Level: 2

Nosso programa precisa representar esses valores.

Não podemos simplesmente escrever:

  std::cout << "Health: 100" << std::endl;

e esperar que o 100 magicamente se transforme quando o jogador receber dano.

Precisamos armazenar essa informação.


2. Nossa primeira variável

Vamos começar com:

  int playerHealth = 100;

Essa pequena instrução apresenta vários conceitos novos.

Podemos inicialmente separá-la assim:

  int playerHealth = 100;
│       │       │  │
│       │       │  └── valor inicial
│       │       │
│       │       └── atribuição/inicialização
│       │
│       └── nome
│
└── tipo

Ainda estudaremos tipos profundamente no próximo capítulo.

Por enquanto, precisamos apenas saber que:

  int

representa um tipo inteiro.

E:

  playerHealth

é o nome que escolhemos para nossa variável.

Finalmente:

  100

é seu valor inicial.


3. O que é uma variável?

Uma definição inicial bastante útil é:

Uma variável é uma representação nomeada de uma informação que nosso programa pode armazenar e utilizar durante sua execução.

Em nosso exemplo:

  int playerHealth = 100;

podemos pensar conceitualmente:

  playerHealth
┌──────────────┐
│     100      │
└──────────────┘

Agora nosso programa possui uma informação chamada:

  playerHealth

com valor:

  100

Essa representação é propositalmente simplificada.

Quando chegarmos a memória, endereços, referências, pointers, stack e lifetime, construiremos um modelo muito mais preciso.

Por enquanto, ela é suficiente para começarmos.


4. Por que não chamar a variável de x?

Poderíamos escrever:

  int x = 100;

O compilador aceitaria.

Mas compare:

  int x = 100;

com:

  int playerHealth = 100;

Qual deles explica melhor a intenção?

No contexto do nosso futuro jogo:

  playerHealth

é muito mais expressivo.

O nome nos informa:

esta informação representa a vida do jogador.

Código também é comunicação entre desenvolvedores.

Por isso nomes importam.


5. Nossa convenção para variáveis

A partir daqui começaremos a aplicar uma das convenções estabelecidas para nosso projeto.

Variáveis utilizarão:

camelCase

Por exemplo:

  playerHealth
playerCoins
playerLevel
playerEnergy
currentScore

Observe:

  playerHealth
│     │
│     └── nova palavra começa com maiúscula
│
└── primeira palavra começa com minúscula

Também utilizaremos identificadores em inglês.

Portanto, preferiremos:

  playerHealth

em vez de:

  vidaJogador

As explicações continuam em português do Brasil.

O código seguirá nomenclatura técnica em inglês.


6. Vamos colocar nossa variável no programa

Altere nosso main.cpp:

  #include <iostream>

int main()
{
    int playerHealth = 100;

    std::cout << "Player Health: " << playerHealth << std::endl;

    return 0;
}

Faça:

  Save
↓
Build
↓
Run

O resultado deverá ser:

  Player Health: 100

Visualmente, o resultado parece semelhante ao que tínhamos antes.

Mas internamente existe uma diferença fundamental.


7. Antes e depois

Antes:

  std::cout << "Player Health: 100" << std::endl;

O valor estava preso dentro do texto.

Agora:

  int playerHealth = 100;

std::cout << "Player Health: " << playerHealth << std::endl;

Temos duas coisas separadas:

  "Player Health: "

e:

  playerHealth

Podemos visualizar:

  playerHealth
     │
     ▼
    100
     │
     ▼
std::cout
     │
     ▼
Player Health: 100

Agora o valor existe como informação manipulável pelo programa.


8. Observe o << novamente

No Capítulo 02 aprendemos:

  std::cout << "Hello";

Agora temos:

  std::cout << "Player Health: " << playerHealth << std::endl;

Estamos inserindo diferentes informações no fluxo:

  std::cout
    │
    ├── << "Player Health: "
    │
    ├── << playerHealth
    │
    └── << std::endl

O primeiro valor é texto.

O segundo vem da variável.


9. Vamos provar que a variável realmente pode mudar

Depois da primeira saída, adicione:

  playerHealth = 80;

Nosso código:

  #include <iostream>

int main()
{
    int playerHealth = 100;

    std::cout << "Player Health: " << playerHealth << std::endl;

    playerHealth = 80;

    std::cout << "Player Health: " << playerHealth << std::endl;

    return 0;
}

Execute.

Resultado:

  Player Health: 100
Player Health: 80

Agora aconteceu algo completamente novo em nossa série.


10. Nosso programa mudou seu próprio estado

Começamos com:

  playerHealth
┌──────────────┐
│     100      │
└──────────────┘

Depois executamos:

  playerHealth = 80;

Conceitualmente:

  ANTES

playerHealth
┌──────────────┐
│     100      │
└──────────────┘

        ↓

playerHealth = 80;

        ↓

DEPOIS

playerHealth
┌──────────────┐
│      80      │
└──────────────┘

Essa capacidade é fundamental.

Um jogo é cheio de estado que muda.


11. Estado

Vamos introduzir uma palavra muito importante:

State — Estado

O estado representa informações que descrevem determinada situação do programa em um momento.

Imagine nosso jogador:

  Player State
│
├── Health: 100
├── Energy: 80
├── Coins: 25
└── Level: 1

Depois de alguns acontecimentos:

  Player State
│
├── Health: 75
├── Energy: 60
├── Coins: 40
└── Level: 2

O jogador continua sendo conceitualmente o mesmo.

Mas seu estado mudou.

Variáveis serão uma das ferramentas fundamentais para representar esse estado.


12. Nosso primeiro pequeno estado de jogo

Vamos expandir um pouco:

  #include <iostream>

int main()
{
    int playerHealth = 100;
    int playerCoins = 25;
    int playerLevel = 1;

    std::cout << "Player Health: " << playerHealth << std::endl;
    std::cout << "Player Coins: " << playerCoins << std::endl;
    std::cout << "Player Level: " << playerLevel << std::endl;

    return 0;
}

Execute.

Resultado:

  Player Health: 100
Player Coins: 25
Player Level: 1

Agora nosso programa possui três informações independentes.


13. Visualizando nosso estado

Podemos imaginar:

  MEMÓRIA — MODELO CONCEITUAL

playerHealth
┌───────┐
│  100  │
└───────┘

playerCoins
┌───────┐
│   25  │
└───────┘

playerLevel
┌───────┐
│    1  │
└───────┘

Novamente:

esse desenho é uma abstração didática.

Ainda não estamos afirmando detalhes sobre endereços, tamanho, stack ou representação física.

Chegaremos lá progressivamente.


14. Declaração

Quando escrevemos:

  int playerHealth;

estamos declarando uma variável.

Estamos dizendo, de maneira simplificada:

haverá uma variável chamada playerHealth do tipo int.

Observe que ainda não fornecemos explicitamente um valor nessa linha.


15. Inicialização

Quando escrevemos:

  int playerHealth = 100;

estamos declarando a variável e fornecendo um valor inicial.

Podemos pensar:

  int playerHealth = 100;
│       │          │
│       │          └── valor inicial
│       │
│       └── nome
│
└── tipo

Para nossos exemplos iniciais, vamos preferir inicializar as variáveis quando as criamos sempre que fizer sentido.

Isso reduz estados indeterminados e torna a intenção mais clara.


16. Declaração e atribuição posterior

Também poderíamos escrever:

  int playerHealth;

playerHealth = 100;

Aqui temos duas etapas.

Primeiro:

  int playerHealth;

Depois:

  playerHealth = 100;

Mas isso não é exatamente a mesma operação conceitual que:

  int playerHealth = 100;

No primeiro caso declaramos e posteriormente atribuímos.

No segundo fornecemos um valor durante a inicialização.

Essa diferença ficará mais importante quando estudarmos tipos e objetos mais sofisticados.


17. Inicialização versus atribuição

Vamos registrar:

Inicialização

  int playerHealth = 100;

A variável nasce com aquele valor.

Atribuição

Depois:

  playerHealth = 80;

Estamos alterando o valor de uma variável que já existe.

Conceitualmente:

  Inicialização

playerHealth
     ↓
    100

Depois

Atribuição
     ↓
playerHealth = 80
     ↓
novo valor


18. O sinal = merece atenção

Em:

  playerHealth = 80;

o:

  =

não deve ser lido simplesmente como a igualdade matemática tradicional.

Aqui estamos utilizando o operador de atribuição.

Podemos inicialmente ler:

atribua 80 a playerHealth.

Ou:

  80
 ↓
playerHealth

Mais adiante veremos operadores em detalhes.


19. Uma variável pode aparecer dos dois lados de uma operação

Considere:

  playerHealth = playerHealth - 20;

Ainda não estudamos operadores formalmente, mas conseguimos entender a ideia.

Se:

  playerHealth = 100

então:

  playerHealth - 20

produz:

  80

e depois atribuímos esse resultado novamente:

  playerHealth = 80

Conceitualmente:

  valor atual
   ↓
100
   ↓
100 - 20
   ↓
80
   ↓
novo playerHealth

Isso começa a parecer um jogo.


20. Nosso primeiro "dano"

Vamos experimentar:

  #include <iostream>

int main()
{
    int playerHealth = 100;

    std::cout << "Player Health: " << playerHealth << std::endl;

    playerHealth = playerHealth - 20;

    std::cout << "Player Health: " << playerHealth << std::endl;

    return 0;
}

Resultado:

  Player Health: 100
Player Health: 80

Ainda não temos um sistema de combate.

Nem deveríamos.

Mas já conseguimos representar uma mudança de estado.


21. Isso ainda não é uma regra de gameplay completa

Não devemos olhar para:

  playerHealth = playerHealth - 20;

e criar imediatamente:

  DamageSystem
CombatManager
HealthComponent
EventBus

Temos uma linha.

Ela resolve nosso problema atual.

Mais tarde talvez apareçam necessidades como:

  • diferentes fontes de dano;

  • defesa;

  • resistência;

  • invulnerabilidade;

  • efeitos;

  • morte;

  • eventos;

  • UI;

  • testes.

Quando esses problemas surgirem, nossa solução poderá evoluir.

Hoje ela não precisa.


22. Mudando as moedas

Podemos fazer algo semelhante:

  int playerCoins = 25;

playerCoins = playerCoins + 10;

Conceitualmente:

  25
↓
+ 10
↓
35

Depois:

  std::cout << "Player Coins: " << playerCoins << std::endl;

Resultado:

  Player Coins: 35

Nosso programa agora consegue representar:

  perder Health
ganhar Coins

mesmo que ainda de forma extremamente simples.


23. Nosso primeiro pequeno fluxo de estado

Experimente:

  #include <iostream>

int main()
{
    int playerHealth = 100;
    int playerCoins = 25;
    int playerLevel = 1;

    std::cout << "=== Initial State ===" << std::endl;
    std::cout << "Health: " << playerHealth << std::endl;
    std::cout << "Coins: " << playerCoins << std::endl;
    std::cout << "Level: " << playerLevel << std::endl;

    playerHealth = playerHealth - 20;
    playerCoins = playerCoins + 10;
    playerLevel = 2;

    std::cout << std::endl;
    std::cout << "=== Current State ===" << std::endl;
    std::cout << "Health: " << playerHealth << std::endl;
    std::cout << "Coins: " << playerCoins << std::endl;
    std::cout << "Level: " << playerLevel << std::endl;

    return 0;
}

Resultado:

  === Initial State ===
Health: 100
Coins: 25
Level: 1

=== Current State ===
Health: 80
Coins: 35
Level: 2

Agora existe uma transformação observável.


24. O jogo começa a existir como dados

Ainda não temos gráficos.

Mas já começamos a representar algo essencial:

  GAME STATE

Health
Coins
Level

Essa é uma lição importante de Game Engineering.

Um jogo não é apenas aquilo que aparece na tela.

Existe uma grande quantidade de estado e regras por trás da apresentação visual.

A interface gráfica futuramente mostrará esses dados.

Mas os dados precisam existir independentemente da aparência.


25. A HUD do futuro

Imagine futuramente uma HUD exibindo:

  ❤️ 80
🪙 35
⭐ 2

Visualmente teremos sprites, fonts, UI e rendering.

Mas por trás dela poderá existir algo conceitualmente equivalente a:

  playerHealth
playerCoins
playerLevel

A interface apresenta o estado.

Ela não deveria ser o próprio estado.

Essa separação ficará muito importante quando começarmos a pensar em arquitetura.


26. Variável não é apenas "uma caixinha"

Muitos cursos definem variável assim:

"Uma variável é uma caixa na memória."

Essa analogia pode ajudar no começo.

Por isso utilizamos desenhos como:

  playerHealth
┌───────┐
│  100  │
└───────┘

Mas precisamos tomar cuidado para não transformar a analogia em uma definição absoluta.

C++ possui detalhes importantes envolvendo:

  • storage;

  • lifetime;

  • scope;

  • object representation;

  • references;

  • addresses;

  • memory;

  • optimization.

Então prefiro que você pense:

uma variável nos permite dar um nome a uma informação armazenada/manipulada pelo programa.

A metáfora da caixa é apenas um primeiro modelo visual.


27. Nomes ruins começam a cobrar preço rapidamente

Imagine:

  int a = 100;
int b = 25;
int c = 1;

Depois:

  a = a - 20;
b = b + 10;
c = 2;

Você consegue descobrir o significado?

Talvez.

Mas precisa lembrar:

  a = Health
b = Coins
c = Level

Agora compare:

  int playerHealth = 100;
int playerCoins = 25;
int playerLevel = 1;

playerHealth = playerHealth - 20;
playerCoins = playerCoins + 10;
playerLevel = 2;

A intenção está muito mais clara.


28. Código deve revelar intenção

Uma das ideias que aparecerá repetidamente durante nossa jornada é:

o código deve tentar revelar o que está fazendo.

Isso não significa escrever nomes gigantescos para tudo.

Significa escolher nomes adequados ao contexto.

Por exemplo:

  playerHealth

é melhor que:

  x

para nosso caso.

Mas algo absurdo como:

  currentIntegerValueRepresentingTheHealthOfTheMainPlayer

provavelmente seria desnecessário.

Clareza também envolve equilíbrio.


29. Variáveis diferentes podem ter valores iguais

Considere:

  int playerHealth = 100;
int playerEnergy = 100;

Temos duas variáveis.

Mesmo que seus valores sejam iguais:

  100
100

elas representam conceitos diferentes.

  playerHealth ≠ playerEnergy

semanticamente.

Se reduzirmos:

  playerEnergy = 80;

isso não deveria alterar automaticamente:

  playerHealth

São estados independentes.


30. O nome faz parte do significado

Observe:

  int playerHealth = 100;
int enemyHealth = 100;

Os valores iniciais são iguais.

Mas representam entidades conceitualmente diferentes.

  playerHealth
enemyHealth

Isso será extremamente importante quando começarmos a modelar objetos.

Ainda não precisamos de uma classe Player.

Mas o problema que um dia poderá justificá-la começa a nascer.


31. Escopo está esperando por nós

No Capítulo 02 vimos rapidamente que:

  {
}

define um bloco.

Agora nossas variáveis estão dentro:

  int main()
{
    int playerHealth = 100;
}

Isso terá implicações importantes.

Onde playerHealth existe?

Quem consegue utilizá-la?

Quando ela deixa de existir?

Essas perguntas envolvem:

  Scope
Lifetime

E terão capítulos próprios.

Não vamos antecipá-las.


32. Não transforme tudo em global

Talvez você encontre exemplos na internet colocando variáveis fora de main:

  int playerHealth = 100;

int main()
{
}

Não faremos isso apenas para "facilitar o acesso".

Variáveis globais possuem implicações importantes para:

  • dependências;

  • estado compartilhado;

  • testes;

  • manutenção;

  • concorrência;

  • arquitetura.

Quando tivermos um problema que nos obrigue a discutir esse tipo de decisão, estudaremos com contexto.

Por enquanto nossas variáveis ficam dentro de main.


33. Podemos criar qualquer nome?

Não.

Existem regras da linguagem para identificadores.

Por exemplo, não podemos utilizar uma palavra reservada da linguagem como nome comum de variável.

Algo como:

  int return = 10;

não é válido porque:

  return

possui significado especial em C++.

Também existem outras regras de formação de identificadores que estudaremos progressivamente.


34. Um nome também não deve começar com número

Algo como:

  int 1player = 100;

não representa um identificador válido.

Enquanto:

  int player1 = 100;

pode ser sintaticamente válido.

Mas validade sintática não significa automaticamente bom nome.

Sempre precisamos considerar intenção.


35. Case sensitivity novamente

No capítulo anterior aprendemos que C++ diferencia maiúsculas e minúsculas.

Então:

  playerHealth
PlayerHealth
PLAYERHEALTH

podem ser identificadores diferentes.

Nossa convenção elimina parte dessa confusão:

  Variável
↓
camelCase
↓
playerHealth

Mais tarde:

  Class
↓
PascalCase
↓
Player

E constantes:

  Constant
↓
UPPERCASE
↓
MAX_PLAYER_HEALTH

Consistência reduz carga mental.


36. E constantes?

Você talvez esteja pensando:

"Se uma variável muda, como representamos algo que não deveria mudar?"

Excelente pergunta.

Teremos:

  constants

em um capítulo específico.

Quando chegarmos lá, nossa convenção será:

  MAX_PLAYER_HEALTH

em UPPERCASE.

Não precisamos antecipar a implementação ainda.

Primeiro precisamos dominar variáveis.


37. Um pequeno erro proposital

Escreva:

  int playerHealth = 100;

std::cout << playerhealth << std::endl;

Observe:

  playerHealth

versus:

  playerhealth

Faça Build.

O compilador deverá reclamar porque esses identificadores não correspondem.

Use nossa metodologia:

  OBSERVAR
↓
LER
↓
LOCALIZAR
↓
COMPARAR
↓
CRIAR HIPÓTESE
↓
CORRIGIR
↓
VALIDAR

Depois restaure:

  std::cout << playerHealth << std::endl;


38. Outro erro proposital

Tente:

  int playerHealth = 100;

playerHealth = "eighty";

Faça Build.

Temos uma variável declarada como:

  int

e estamos tentando atribuir texto a ela.

Não precisamos compreender ainda todos os detalhes do diagnóstico.

A pergunta importante é:

Por que uma variável inteira não aceita simplesmente qualquer tipo de informação?

Essa pergunta nos leva diretamente ao próximo capítulo.


39. Variáveis possuem tipo

Até agora usamos:

  int

em:

  int playerHealth = 100;

Mas nosso futuro jogo terá informações que não são apenas números inteiros.

Por exemplo:

  Health: 100
Player Name: Alex
Speed: 4.5
Is Alive: true

Esses valores possuem naturezas diferentes.

E C++ precisa lidar com essas diferenças.

Isso significa que variáveis e tipos estão profundamente relacionados.


40. Por que não estudar todos os tipos agora?

Porque isso transformaria este capítulo em algo muito maior do que precisa ser.

Hoje nosso objetivo é específico:

compreender por que variáveis existem e utilizá-las para representar estado mutável.

No próximo capítulo, o problema será:

nem toda informação do jogo é igual.

Aí estudaremos tipos com profundidade adequada.

Essa separação mantém nossa progressão clara.


41. Microdesafio — estado inicial do jogador

Crie três variáveis:

  playerHealth
playerCoins
playerLevel

com:

  100
25
1

Depois produza:

  === PLAYER ===
Health: 100
Coins: 25
Level: 1

Use apenas aquilo que já aprendemos.


42. Uma possível solução

  #include <iostream>

int main()
{
    int playerHealth = 100;
    int playerCoins = 25;
    int playerLevel = 1;

    std::cout << "=== PLAYER ===" << std::endl;
    std::cout << "Health: " << playerHealth << std::endl;
    std::cout << "Coins: " << playerCoins << std::endl;
    std::cout << "Level: " << playerLevel << std::endl;

    return 0;
}

Execute.

Confirme o resultado.


43. Microdesafio — faça o estado mudar

Agora simule:

  Player sofre 25 de dano
Player ganha 15 moedas
Player sobe para Level 2

Estado esperado:

  Health: 75
Coins: 40
Level: 2

Tente antes de continuar.


44. Uma possível solução

  #include <iostream>

int main()
{
    int playerHealth = 100;
    int playerCoins = 25;
    int playerLevel = 1;

    playerHealth = playerHealth - 25;
    playerCoins = playerCoins + 15;
    playerLevel = 2;

    std::cout << "=== PLAYER ===" << std::endl;
    std::cout << "Health: " << playerHealth << std::endl;
    std::cout << "Coins: " << playerCoins << std::endl;
    std::cout << "Level: " << playerLevel << std::endl;

    return 0;
}

Resultado:

  === PLAYER ===
Health: 75
Coins: 40
Level: 2

Nosso programa agora possui estado que muda durante a execução.

Esse é o resultado observável deste capítulo.


45. O que nosso futuro Game Loop fará?

Ainda estamos longe do Game Loop real.

Mas podemos começar a enxergar a relação.

Hoje fazemos:

  Estado inicial
     ↓
Alteração
     ↓
Novo estado
     ↓
Mostrar resultado

Um jogo fará algo conceitualmente muito mais próximo de:

  Estado
  ↓
Input
  ↓
Update
  ↓
Novo estado
  ↓
Render
  ↓
repetir

Quando chegarmos ao Game Loop, variáveis deixarão de parecer apenas um exercício de fundamentos.

Elas estarão em toda parte.


46. Não precisamos de novas pastas

Nosso projeto continua:

  CppGameEngine/
└── main.cpp

Isso é suficiente.

Ainda não existe razão para:

  Player/
Stats/
State/
Game/
Engine/

Temos três variáveis e algumas instruções.

Nossa arquitetura deve acompanhar o problema.

Não antecipá-lo.


47. O código final deste capítulo

Podemos manter como evolução prática:

  #include <iostream>

int main()
{
    int playerHealth = 100;
    int playerCoins = 25;
    int playerLevel = 1;

    std::cout << "=== Initial State ===" << std::endl;
    std::cout << "Health: " << playerHealth << std::endl;
    std::cout << "Coins: " << playerCoins << std::endl;
    std::cout << "Level: " << playerLevel << std::endl;

    playerHealth = playerHealth - 20;
    playerCoins = playerCoins + 10;
    playerLevel = 2;

    std::cout << std::endl;
    std::cout << "=== Current State ===" << std::endl;
    std::cout << "Health: " << playerHealth << std::endl;
    std::cout << "Coins: " << playerCoins << std::endl;
    std::cout << "Level: " << playerLevel << std::endl;

    return 0;
}

Agora existe uma mudança real em relação ao nosso primeiro programa.

Portanto, desta vez faz sentido registrá-la no Git.


48. Nosso commit

Depois de validar:

  Save
↓
Build succeeded
↓
Run
↓
resultado correto

verifique:

  git status

Depois adicione o arquivo correspondente ao projeto.

Por exemplo:

  git add CppGameEngine/main.cpp

Confirme o caminho real no seu repositório antes de executar.

O commit pode ser:

  git commit -m "feat: add initial player state variables"

O commit descreve a evolução real:

agora nosso programa possui variáveis representando estado inicial do jogador.


49. Atualizando o CHANGELOG

Como houve evolução funcional real no exemplo principal, podemos registrar em [Unreleased] algo como:

  ### Added

- Added initial player state variables for health, coins, and level.
- Added state updates during program execution.
- Added console output for initial and current player state.

Depois:

  git add CHANGELOG.md
git commit -m "docs: update changelog with player state variables"

Não precisamos alterar o ROADMAP apenas para marcar cada pequeno conceito educacional.

O ROADMAP técnico continuará acompanhando marcos técnicos maiores.


50. O que aprendemos?

Partimos de:

  std::cout << "Health: 100" << std::endl;

onde 100 era apenas parte do texto.

Chegamos a:

  int playerHealth = 100;

Agora playerHealth representa informação manipulável pelo programa.

Depois:

  playerHealth = 80;

e descobrimos que o estado pode mudar durante a execução.

Também começamos a diferenciar:

  declaração
inicialização
atribuição

e estabelecemos nossa convenção:

  Variáveis
→ camelCase
→ inglês

Como:

  playerHealth
playerCoins
playerLevel

Mais importante, nosso programa começou a possuir estado.


Conclusão

Até aqui nosso programa sabia produzir saída.

Agora ele começou a lembrar informações.

Essa diferença parece pequena:

  std::cout << "Health: 100";

para:

  int playerHealth = 100;

mas representa um avanço fundamental.

Um jogo precisa constantemente manter e transformar estado:

  Health
Energy
Coins
Experience
Inventory
Position
Time
Weather
NPC State
Quest State
World State

Hoje demos o primeiro passo.

Começamos com:

  playerHealth
playerCoins
playerLevel

e observamos:

  Estado inicial
      ↓
Acontecimento
      ↓
Estado atualizado

Nosso código ainda é minúsculo.

Mas agora ele não apenas mostra uma frase.

Ele possui informações que podem mudar.

E isso cria imediatamente nossa próxima pergunta:

Se playerHealth é um número inteiro, como representaremos velocidade, nome, verdadeiro/falso e outras informações do jogo?

Porque nem todo dado é igual.


Próximo capítulo

Capítulo 06 — Tipos: nem toda informação é igual

No próximo artigo vamos partir de um problema concreto:

  Health       → 100
Speed        → 4.5
Player Name  → Alex
Is Alive     → true

Todos são dados.

Mas não representam a mesma coisa.

Vamos começar a compreender por que C++ precisa conhecer o tipo da informação que estamos armazenando e explorar, progressivamente, os tipos necessários para começar a representar nosso mundo.

Sem tentar decorar uma tabela gigantesca de tipos.

Primeiro veremos o problema.

Depois entenderemos por que o sistema de tipos existe.

E então nosso pequeno estado de jogo começará a ficar muito mais interessante.

Subscreve "Aeca" para receber atualizações diretamente na tua caixa de entrada
aeca

Subscreve aeca para reagir

Subscrever

Comentários

Ainda não há comentários. Sê o primeiro a comentar!

Subscreve Aeca para receber atualizações diretamente na tua caixa de entrada