Capítulo 10 — Decisões: ensinando nosso programa a escolher
Série: Do zero ao jogo comercial com C++ e SFML
Nosso código já calcula resultados. Agora ele precisa observar uma situação e decidir se deve agir.
Até agora, nosso programa executa suas instruções praticamente em sequência.
Algo parecido com:
criar variáveis
↓
calcular valores
↓
alterar estado
↓
mostrar resultados
↓
encerrar
Nos últimos capítulos já conseguimos escrever:
playerHealth -= damage;
playerCoins += reward;
Também construímos expressões como:
int finalDamage = (baseDamage + bonusDamage) * criticalMultiplier;
Mas existe um problema cada vez mais evidente.
Imagine:
playerHealth -= damage;
E se o dano for maior que a vida atual?
Poderíamos terminar com:
Health: -40
Ou imagine:
playerCoins -= itemPrice;
E se o jogador não possuir moedas suficientes?
Poderíamos produzir:
Coins: -75
O programa sabe calcular.
Mas ainda não sabe perguntar:
Essa operação deveria acontecer?
Para isso, precisamos começar a tomar decisões.
1. O problema que já existe em nosso código
Considere:
int playerHealth = 30;
int damage = 50;
playerHealth -= damage;
O cálculo será:
30 - 50 = -20
Tecnicamente, C++ consegue realizar essa operação.
Mas talvez nossa regra seja:
Health nunca deve ficar abaixo de zero.
Então precisamos de uma lógica semelhante a:
calcular nova vida
↓
nova vida ficou abaixo de zero?
↓
SIM → usar zero
NÃO → usar o valor calculado
Estamos começando a falar sobre decisão.
2. O programa precisa avaliar uma condição
Uma decisão começa com uma pergunta.
Por exemplo:
playerHealth é maior que zero?
Ou:
playerCoins é suficiente para a compra?
Ou:
damage ultrapassou a vida atual?
Essas perguntas podem produzir dois resultados fundamentais:
true
false
Já conhecemos esse tipo:
bool
Agora ele começa a mostrar por que é tão importante.
3. Uma comparação produz um valor booleano
Considere:
playerHealth > 0
Se:
playerHealth = 30
temos:
30 > 0
Resultado:
true
Agora:
playerHealth = 0
Temos:
0 > 0
Resultado:
false
Portanto:
playerHealth > 0
é uma expressão.
Só que, desta vez, o resultado dela é:
bool
4. Do capítulo anterior para este
No Capítulo 09 vimos expressões como:
baseDamage + bonusDamage
que podem produzir um número.
Agora teremos expressões como:
playerHealth > 0
que produzem:
true
ou:
false
Podemos visualizar:
playerHealth > 0
↓
comparação
↓
bool
↓
true ou false
Essa será a base das nossas decisões.
5. Nosso primeiro operador de comparação: >
O operador:
>
significa:
maior que
Exemplo:
int playerHealth = 30;
bool isAlive = playerHealth > 0;
A expressão:
playerHealth > 0
é avaliada.
Como:
30 > 0
é verdadeiro:
isAlive
recebe:
true
6. Vamos observar isso
#include <iostream>
int main()
{
int playerHealth = 30;
bool isAlive = playerHealth > 0;
std::cout << std::boolalpha;
std::cout << "Health: " << playerHealth << std::endl;
std::cout << "Is Alive: " << isAlive << std::endl;
return 0;
}
Resultado:
Health: 30
Is Alive: true
Agora altere:
int playerHealth = 0;
Resultado:
Health: 0
Is Alive: false
Nosso programa já consegue avaliar uma condição.
Mas ainda não está escolhendo executar ou não uma ação.
7. Conhecendo if
C++ possui uma estrutura de decisão chamada:
if
Sua forma inicial é:
if (condition)
{
// código executado se a condição for verdadeira
}
Podemos ler:
se a condição for verdadeira, execute este bloco.
É exatamente o comportamento de que precisamos.
8. Nosso primeiro if
#include <iostream>
int main()
{
int playerHealth = 30;
if (playerHealth > 0)
{
std::cout << "Player is alive." << std::endl;
}
return 0;
}
Temos:
playerHealth > 0
Se essa expressão produzir:
true
o bloco:
{
std::cout << "Player is alive." << std::endl;
}
será executado.
9. Visualizando o fluxo
Podemos imaginar:
playerHealth > 0?
│
├── true
│ ↓
│ mostrar mensagem
│
└── false
↓
ignorar bloco
Esse detalhe é importante.
Quando a condição é falsa, o programa não para.
Ele simplesmente não executa aquele bloco e continua depois dele.
10. Testando os dois cenários
Primeiro:
int playerHealth = 30;
Resultado:
Player is alive.
Agora:
int playerHealth = 0;
O bloco:
if (playerHealth > 0)
não será executado.
Se não houver nenhuma outra saída no programa, você simplesmente não verá aquela mensagem.
Temos nossa primeira alteração real de fluxo.
11. O programa não executa mais tudo obrigatoriamente
Antes:
instrução A
↓
instrução B
↓
instrução C
Agora:
instrução A
↓
condição
├── true → executa B
└── false → ignora B
↓
instrução C
Essa mudança parece pequena.
Mas ela é uma das bases de praticamente qualquer sistema interativo.
12. Aplicando isso ao dano
Vamos voltar ao problema:
int playerHealth = 30;
int damage = 50;
Podemos primeiro calcular:
int newHealth = playerHealth - damage;
Resultado:
-20
Agora podemos perguntar:
newHealth < 0
Se for verdadeiro, precisamos impedir que nossa vida final permaneça negativa.
13. O operador <
O operador:
<
significa:
menor que
Então:
newHealth < 0
pergunta:
newHealthé menor que zero?
Se:
newHealth = -20
temos:
-20 < 0
Resultado:
true
Agora podemos usar essa condição.
14. Protegendo a vida contra valores negativos
#include <iostream>
int main()
{
int playerHealth = 30;
int damage = 50;
int newHealth = playerHealth - damage;
if (newHealth < 0)
{
newHealth = 0;
}
playerHealth = newHealth;
std::cout << "Health: " << playerHealth << std::endl;
return 0;
}
Resultado:
Health: 0
Nosso código agora aplica uma regra:
se o cálculo produzir uma vida negativa, use zero.
15. A expressão vem antes da decisão
Observe a sequência:
int newHealth = playerHealth - damage;
if (newHealth < 0)
{
newHealth = 0;
}
Primeiro temos uma expressão aritmética:
playerHealth - damage
Depois uma expressão de comparação:
newHealth < 0
Essa comparação produz:
true
ou:
false
E o if utiliza esse resultado para decidir se executará o bloco.
Os capítulos estão começando a se conectar:
variáveis
↓
tipos
↓
constantes
↓
operadores
↓
expressões
↓
condições
↓
decisões
16. Outros operadores de comparação
Precisaremos de mais algumas formas de comparação.
Para nossa etapa atual:
Operador Significado
>maior que
<menor que
>=maior ou igual
<=menor ou igual
==igual
!=diferente
Vamos entendê-los com pequenos exemplos.
17. Maior ou igual: >=
Imagine que um item custe:
int itemPrice = 50;
e o jogador tenha:
int playerCoins = 50;
Ele possui dinheiro suficiente?
A condição pode ser:
playerCoins >= itemPrice
Temos:
50 >= 50
Resultado:
true
O jogador não precisa possuir mais que o preço.
Possuir exatamente o preço também é suficiente.
18. Menor ou igual: <=
Imagine:
playerHealth <= 0
Podemos interpretar:
a vida chegou a zero ou ficou abaixo dele?
Com:
playerHealth = 0
a condição é verdadeira.
Com:
playerHealth = -10
também é verdadeira.
Mais tarde poderemos usar isso para representar estados como derrota.
19. Igualdade com ==
Aqui existe um cuidado importantíssimo.
Para comparar igualdade usamos:
==
Exemplo:
playerLevel == 2
Isso pergunta:
playerLevelpossui valor igual a2?
Compare com:
playerLevel = 2;
Esse código faz atribuição.
São operações completamente diferentes.
20. = não é ==
Temos:
=
atribuição.
E:
==
comparação de igualdade.
Compare:
playerLevel = 2;
com:
playerLevel == 2
Primeiro:
atribui 2
Segundo:
pergunta se é igual a 2
Essa diferença é pequena visualmente e enorme semanticamente.
21. Erro clássico — confundir = com ==
Quando queríamos verificar:
if (playerLevel == 2)
{
std::cout << "Level reached." << std::endl;
}
um iniciante pode escrever por engano:
if (playerLevel = 2)
{
std::cout << "Level reached." << std::endl;
}
Não faça isso.
A segunda construção contém uma atribuição, não a comparação que queríamos representar.
Compiladores modernos podem emitir warnings dependendo da situação.
Nosso princípio:
warning merece investigação.
Não ignore avisos simplesmente porque o projeto compilou.
22. Diferente com !=
O operador:
!=
significa:
diferente de
Por exemplo:
int divisor = 5;
if (divisor != 0)
{
std::cout << "Division can be performed." << std::endl;
}
Estamos dizendo:
execute o bloco apenas se
divisorfor diferente de zero.
Esse é exatamente um dos problemas que encontramos no Capítulo 08.
23. Evitando uma divisão inteira por zero
Podemos escrever:
#include <iostream>
int main()
{
int totalExperience = 200;
int divisor = 100;
if (divisor != 0)
{
int result = totalExperience / divisor;
std::cout << "Result: " << result << std::endl;
}
return 0;
}
Agora a divisão só acontece quando:
divisor != 0
produz:
true
Estamos começando a executar operações apenas quando suas condições são adequadas.
24. Uma condição já é uma expressão booleana
Considere:
playerCoins >= itemPrice
O resultado é:
true
ou:
false
Portanto poderíamos fazer:
bool hasEnoughCoins = playerCoins >= itemPrice;
E depois:
if (hasEnoughCoins)
{
std::cout << "Player can buy the item." << std::endl;
}
Isso torna explícito que o if trabalha com uma condição booleana.
25. Podemos usar a expressão diretamente
Também podemos escrever:
if (playerCoins >= itemPrice)
{
std::cout << "Player can buy the item." << std::endl;
}
As duas abordagens podem ser úteis.
Versão com variável:
bool hasEnoughCoins = playerCoins >= itemPrice;
if (hasEnoughCoins)
{
}
Versão direta:
if (playerCoins >= itemPrice)
{
}
A melhor escolha depende da clareza.
26. Nomes booleanos podem explicar regras
Compare:
if (playerCoins >= itemPrice)
{
}
com:
bool hasEnoughCoins = playerCoins >= itemPrice;
if (hasEnoughCoins)
{
}
A segunda versão dá um nome à pergunta:
hasEnoughCoins
Isso pode ajudar quando a condição começa a representar um conceito relevante.
Mas não criaremos variáveis booleanas desnecessariamente para toda comparação simples.
27. Comprando um item
Vamos montar um pequeno exemplo:
#include <iostream>
int main()
{
int playerCoins = 80;
int itemPrice = 50;
if (playerCoins >= itemPrice)
{
playerCoins -= itemPrice;
std::cout << "Item purchased." << std::endl;
}
std::cout << "Coins: " << playerCoins << std::endl;
return 0;
}
Como:
80 >= 50
é verdadeiro, a compra acontece.
Depois:
80 - 50
=
30
Resultado:
Item purchased.
Coins: 30
28. Agora teste com poucas moedas
Altere:
int playerCoins = 30;
Temos:
30 >= 50
Resultado:
false
Portanto este bloco:
{
playerCoins -= itemPrice;
std::cout << "Item purchased." << std::endl;
}
não é executado.
Resultado:
Coins: 30
O dinheiro não ficou negativo.
Nosso programa tomou uma decisão.
29. Mas falta uma resposta para o outro caso
Perceba algo.
Quando o jogador possui moedas:
Item purchased.
Quando não possui:
...
Nada acontece.
Talvez quiséssemos mostrar:
Not enough coins.
Precisaríamos representar:
se condição verdadeira
→ faça uma coisa
caso contrário
→ faça outra
Essa necessidade existe.
Mas ela será exatamente o assunto do Capítulo 11 — Quando existem alternativas.
Neste capítulo permaneceremos concentrados no if.
30. Uma decisão não precisa alterar estado
Podemos utilizar if apenas para reagir.
Por exemplo:
int playerHealth = 0;
if (playerHealth <= 0)
{
std::cout << "Player defeated." << std::endl;
}
Nenhuma variável é alterada dentro do bloco.
Ainda assim existe uma decisão:
Health <= 0?
↓
true
↓
mostrar mensagem
31. Várias decisões podem existir
Considere:
int playerHealth = 20;
int playerCoins = 80;
if (playerHealth > 0)
{
std::cout << "Player is alive." << std::endl;
}
if (playerCoins >= 50)
{
std::cout << "Player can buy the item." << std::endl;
}
São dois if independentes.
O programa avalia os dois.
Isso é diferente de uma estrutura em que apenas uma entre várias alternativas deve ser escolhida.
Novamente, chegaremos a isso depois.
32. Não confunda múltiplos if com alternativas exclusivas
Considere:
if (playerHealth > 0)
{
std::cout << "Player is alive." << std::endl;
}
if (playerCoins >= 50)
{
std::cout << "Player has enough coins." << std::endl;
}
As duas condições podem ser verdadeiras.
Então os dois blocos podem executar.
Não estamos dizendo:
execute um OU outro
Estamos dizendo:
avalie a primeira condição
depois
avalie também a segunda
Essa distinção será importante nos próximos capítulos.
33. Condições não devem ser perguntas vagas
Isto é claro:
playerHealth <= 0
Representa uma pergunta objetiva.
Já regras mal definidas como:
o jogador está meio fraco?
precisam primeiro ser transformadas em critérios concretos.
Talvez:
playerHealth <= LOW_HEALTH_THRESHOLD
Mas essa regra ainda precisaria ser definida.
Antes de escrever um if, precisamos saber exatamente:
qual condição representa a decisão?
34. Código é a tradução de uma regra
Considere a regra:
O jogador só pode comprar o item se possuir moedas suficientes.
Podemos decompor:
dados necessários
↓
playerCoins
itemPrice
pergunta
↓
playerCoins >= itemPrice
ação se verdadeira
↓
playerCoins -= itemPrice
Em C++:
if (playerCoins >= itemPrice)
{
playerCoins -= itemPrice;
}
Esse processo é extremamente importante.
Não começamos pela sintaxe.
Começamos pela regra.
35. Outro exemplo: experiência necessária
Imagine:
const int EXPERIENCE_REQUIRED = 100;
int playerExperience = 120;
Queremos apenas informar que o jogador atingiu a quantidade necessária.
if (playerExperience >= EXPERIENCE_REQUIRED)
{
std::cout << "Required experience reached." << std::endl;
}
Temos:
120 >= 100
↓
true
↓
executar bloco
Ainda não implementaremos toda a progressão de nível.
Isso exigirá outras decisões e regras.
36. Evitando regras que ainda não definimos
Seria fácil escrever agora:
playerLevel++;
playerExperience = 0;
dentro do if.
Mas isso levantaria várias perguntas:
Experiência excedente é perdida?
O jogador pode subir vários níveis?
A experiência necessária muda?
Existe nível máximo?
O que acontece no nível máximo?
Não definimos essas regras.
Portanto não devemos inventá-las silenciosamente.
Neste capítulo nosso objetivo é aprender decisões, não construir o sistema completo de progressão.
37. Blocos e chaves
Observe:
if (playerHealth <= 0)
{
std::cout << "Player defeated." << std::endl;
}
As chaves:
{
}
delimitam o bloco associado ao if.
Mesmo quando existe apenas uma instrução, manteremos as chaves.
Isso nos dá uma convenção consistente e reduz riscos quando o bloco crescer.
38. Não faremos isto
C++ permite situações como:
if (playerHealth <= 0)
std::cout << "Player defeated." << std::endl;
Mas em nosso projeto manteremos:
if (playerHealth <= 0)
{
std::cout << "Player defeated." << std::endl;
}
Clareza é mais importante que economizar duas linhas.
39. Indentação também comunica estrutura
Compare:
if (playerHealth <= 0)
{
std::cout << "Player defeated." << std::endl;
}
com:
if (playerHealth <= 0)
{
std::cout << "Player defeated." << std::endl;
}
Os dois podem representar a mesma estrutura sintática.
Mas o segundo deixa visualmente claro que a instrução pertence ao bloco.
Código é lido muito mais vezes do que escrito.
Legibilidade importa.
40. Cuidado com o ponto e vírgula após if
Observe este código incorreto para nossa intenção:
if (playerHealth <= 0);
{
std::cout << "Player defeated." << std::endl;
}
Existe um:
;
imediatamente depois da condição.
Isso encerra uma instrução vazia associada ao if.
O bloco seguinte não funciona como imaginamos.
Esse tipo de erro pode ser particularmente perigoso porque o código pode compilar.
41. Erro proposital — if com ;
Teste:
#include <iostream>
int main()
{
int playerHealth = 100;
if (playerHealth <= 0);
{
std::cout << "Player defeated." << std::endl;
}
return 0;
}
Mesmo com:
Health = 100
você poderá observar a mensagem sendo exibida.
Pergunte:
Por que o bloco executou?
Onde está o ponto e vírgula?
O que o if realmente controla?
Depois corrija:
if (playerHealth <= 0)
{
std::cout << "Player defeated." << std::endl;
}
42. Warnings começam a ficar ainda mais valiosos
Esse tipo de código pode gerar warnings dependendo do compilador e das configurações:
if (playerHealth <= 0);
Não ignore warnings.
Nosso processo deve ser:
Build succeeded
não significa automaticamente:
código perfeito
Também observe:
warnings
resultado
comportamento
Compilação é apenas uma etapa da validação.
43. Erro proposital — = em vez de ==
Teste:
int playerLevel = 1;
if (playerLevel = 2)
{
std::cout << "Level 2." << std::endl;
}
Depois compare com:
if (playerLevel == 2)
{
std::cout << "Level 2." << std::endl;
}
Não se limite a corrigir.
Explique:
= → atribuição
== → comparação
Essa diferença precisa ficar automática ao longo da prática.
44. Condições com bool
Como já possuímos o tipo:
bool
também podemos utilizá-lo diretamente:
bool isAlive = true;
if (isAlive)
{
std::cout << "Player can continue." << std::endl;
}
Não precisamos escrever:
if (isAlive == true)
quando:
if (isAlive)
já comunica claramente a intenção.
45. Uma condição booleana já carrega verdadeiro ou falso
Considere:
bool isAlive = true;
Então:
if (isAlive)
pergunta conceitualmente:
isAliveé verdadeiro?
Isso é suficiente.
Da mesma maneira, futuramente poderemos trabalhar com condições mais complexas sem escrever comparações redundantes.
46. Ainda não vamos combinar condições
Talvez você esteja pensando em algo como:
o jogador está vivo
E
possui moedas suficientes
C++ possui operadores lógicos para isso.
Por exemplo, veremos conceitos como:
AND
OR
NOT
Mas ainda não precisamos introduzi-los aqui.
Nosso objetivo neste artigo é dominar:
uma condição
↓
um if
↓
uma ação condicional
Complexidade virá progressivamente.
47. Nosso primeiro fluxo de decisão útil
Vamos juntar uma regra simples de dano:
#include <iostream>
int main()
{
int playerHealth = 30;
int damage = 50;
int newHealth = playerHealth - damage;
if (newHealth < 0)
{
newHealth = 0;
}
playerHealth = newHealth;
if (playerHealth <= 0)
{
std::cout << "Player defeated." << std::endl;
}
std::cout << "Health: " << playerHealth << std::endl;
return 0;
}
Resultado:
Player defeated.
Health: 0
Agora existem duas decisões independentes:
newHealth < 0?
e:
playerHealth <= 0?
48. Testando outro cenário
Altere:
int damage = 10;
Agora:
30 - 10 = 20
Então:
newHealth < 0
é falso.
E:
playerHealth <= 0
também é falso.
Resultado:
Health: 20
Nenhum dos blocos executa.
49. Um pequeno cenário de compra
Também podemos testar:
#include <iostream>
int main()
{
int playerCoins = 80;
int itemPrice = 50;
std::cout << "Coins Before Purchase: " << playerCoins << std::endl;
if (playerCoins >= itemPrice)
{
playerCoins -= itemPrice;
std::cout << "Item purchased." << std::endl;
}
std::cout << "Coins After Purchase: " << playerCoins << std::endl;
return 0;
}
Resultado:
Coins Before Purchase: 80
Item purchased.
Coins After Purchase: 30
Agora teste:
int playerCoins = 30;
Resultado:
Coins Before Purchase: 30
Coins After Purchase: 30
A compra não acontece.
50. Nosso código agora possui caminhos
Isso é novo.
Antes:
sempre executa
Agora temos:
condição verdadeira → determinado bloco executa
ou:
condição falsa → determinado bloco é ignorado
Nosso programa começou a ter fluxo condicional.
Isso está muito mais próximo do comportamento de um jogo.
51. Muitos sistemas futuros dependerão disso
Imagine:
Se Health <= 0 → jogador derrotado
Se Coins >= Price → permitir compra
Se Experience >= Required → progressão disponível
Se Inventory estiver cheio → impedir coleta
Se Door estiver destrancada → permitir passagem
Se Crop estiver madura → permitir colheita
Se NPC estiver próximo → permitir interação
Cada uma dessas regras começa com uma condição.
52. Não precisamos construir esses sistemas agora
Esses exemplos mostram onde estamos indo.
Não significam que criaremos agora:
InventorySystem
EconomySystem
NpcSystem
InteractionSystem
FarmingSystem
Ainda estamos aprendendo controle de fluxo.
O projeto continuará simples:
CppGameEngine/
└── main.cpp
A arquitetura crescerá quando o problema exigir.
53. Microdesafio — jogador vivo
Comece:
int playerHealth = 25;
Mostre:
Player is alive.
somente quando:
playerHealth > 0
Uma possível solução:
if (playerHealth > 0)
{
std::cout << "Player is alive." << std::endl;
}
Depois teste:
playerHealth = 0;
A mensagem não deve aparecer.
54. Microdesafio — experiência
Comece:
const int EXPERIENCE_REQUIRED = 100;
int playerExperience = 120;
Mostre:
Experience requirement reached.
apenas se o jogador possuir experiência suficiente.
Uma possível solução:
if (playerExperience >= EXPERIENCE_REQUIRED)
{
std::cout << "Experience requirement reached." << std::endl;
}
Agora teste:
playerExperience = 80;
55. Microdesafio — divisão segura
Comece:
int value = 100;
int divisor = 5;
Só execute:
int result = value / divisor;
quando:
divisor != 0
Uma possível implementação:
if (divisor != 0)
{
int result = value / divisor;
std::cout << "Result: " << result << std::endl;
}
Depois teste:
int divisor = 0;
A divisão não deve acontecer.
56. Microdesafio — compra
Comece:
int playerCoins = 75;
int itemPrice = 40;
A compra só deve acontecer quando:
playerCoins >= itemPrice
Dentro do if:
playerCoins -= itemPrice;
Resultado esperado:
Coins: 35
Depois teste:
playerCoins = 25;
O valor deve permanecer:
25
57. Código final do capítulo
Vamos reunir algumas decisões simples, sem introduzir alternativas com else ainda:
#include <iostream>
int main()
{
const int EXPERIENCE_REQUIRED = 100;
int playerHealth = 30;
int damage = 50;
int playerCoins = 80;
int itemPrice = 50;
int playerExperience = 120;
std::cout << "=== INITIAL STATE ===" << std::endl;
std::cout << "Health: " << playerHealth << std::endl;
std::cout << "Coins: " << playerCoins << std::endl;
std::cout << "Experience: " << playerExperience << std::endl;
int newHealth = playerHealth - damage;
if (newHealth < 0)
{
newHealth = 0;
}
playerHealth = newHealth;
if (playerHealth <= 0)
{
std::cout << std::endl;
std::cout << "Player defeated." << std::endl;
}
if (playerCoins >= itemPrice)
{
playerCoins -= itemPrice;
std::cout << "Item purchased." << std::endl;
}
if (playerExperience >= EXPERIENCE_REQUIRED)
{
std::cout << "Experience requirement reached." << std::endl;
}
std::cout << std::endl;
std::cout << "=== CURRENT STATE ===" << std::endl;
std::cout << "Health: " << playerHealth << std::endl;
std::cout << "Coins: " << playerCoins << std::endl;
std::cout << "Experience: " << playerExperience << std::endl;
return 0;
}
Resultado esperado:
=== INITIAL STATE ===
Health: 30
Coins: 80
Experience: 120
Player defeated.
Item purchased.
Experience requirement reached.
=== CURRENT STATE ===
Health: 0
Coins: 30
Experience: 120
58. O que esse programa já consegue decidir?
Temos três perguntas diferentes:
Health chegou a zero?
Há Coins suficientes?
Experience atingiu o necessário?
Cada uma possui:
condição
↓
true ou false
↓
ação opcional
Nosso programa finalmente começou a reagir ao estado.
59. Limitação proposital
Quando:
playerCoins < itemPrice
nada acontece.
Não mostramos:
Insufficient coins.
Quando:
playerHealth > 0
também não mostramos uma mensagem alternativa.
Isso é proposital.
Ainda sabemos apenas dizer:
SE isso for verdadeiro → execute
No próximo capítulo precisaremos dizer:
SE isso for verdadeiro → faça A
CASO CONTRÁRIO → faça B
Essa necessidade dará origem ao próximo recurso.
60. Validando o capítulo
Faça:
Ctrl + S
Depois:
Ctrl + Shift + B
Confirme:
Build succeeded
Execute:
Ctrl + F5
Depois altere os valores para produzir cenários diferentes.
Cenário A
int playerHealth = 100;
int damage = 20;
Esperado:
Health: 80
Cenário B
int playerHealth = 20;
int damage = 50;
Esperado:
Player defeated.
Health: 0
Cenário C
int playerCoins = 100;
int itemPrice = 40;
Esperado:
Item purchased.
Coins: 60
Cenário D
int playerCoins = 20;
int itemPrice = 40;
Esperado:
Coins: 20
A compra não deve ocorrer.
61. Checklist de compreensão
Antes de avançar, tente responder:
O que é uma condição?
Qual tipo de resultado uma comparação produz?
Para que serve
if?O que acontece quando a condição é falsa?
Qual é a diferença entre
=e==?O que fazem
>,<,>=,<=,==e!=?Por que usamos chaves no bloco?
Por que
if (condition);pode causar um bug?Por que uma operação matematicamente válida pode ainda violar uma regra do jogo?
Qual é a diferença entre vários
ifindependentes e escolher uma alternativa?
Se alguma dessas respostas ainda estiver confusa, execute novamente os exemplos.
62. Git
Depois da validação:
git status
Adicione:
git add CppGameEngine/main.cpp
Ajuste o caminho se necessário.
Commit sugerido:
git commit -m "feat: add conditional gameplay decisions"
Esse commit representa uma evolução importante:
nosso programa agora avalia condições antes de executar determinadas ações.
63. Atualizando o CHANGELOG
Em [Unreleased]:
### Added
- Added conditional gameplay decisions using `if`.
- Added comparison operators for health, coins, and experience rules.
- Added health clamping logic to prevent negative values.
- Added conditional item purchase validation.
- Added safe execution example for potentially invalid operations.
Depois:
git add CHANGELOG.md
git commit -m "docs: update changelog with conditional decisions"
O ROADMAP técnico continua sem necessidade de alteração neste ponto.
64. O que aprendemos?
Até o capítulo anterior tínhamos expressões como:
playerHealth - damage
Agora aprendemos a produzir expressões booleanas:
playerHealth <= 0
Conhecemos operadores de comparação:
>
<
>=
<=
==
!=
e utilizamos:
if (condition)
{
// ação
}
para modificar o fluxo do programa.
Também aprendemos que:
condições produzem
trueoufalse;ifexecuta seu bloco somente quando a condição é verdadeira;=é atribuição;==é comparação;vários
ifindependentes podem executar no mesmo fluxo;chaves tornam a estrutura explícita;
um
;colocado indevidamente depois doifpode gerar comportamento incorreto;warnings merecem atenção;
regras do jogo precisam ser transformadas em condições objetivas;
não devemos inventar sistemas completos quando ainda estamos estudando o fundamento que eles utilizarão.
Conclusão
Nosso programa começou como uma sequência totalmente linear.
Depois passou a armazenar valores.
Aprendeu tipos.
Ganhou constantes.
Passou a transformar dados com operadores.
Aprendeu a combinar operações em expressões.
Agora finalmente consegue fazer algo novo:
PERGUNTAR
↓
AVALIAR
↓
DECIDIR
↓
AGIR
Isso muda profundamente o que podemos construir.
Agora já podemos representar regras como:
Se Health ficar abaixo de zero → usar zero
Se Coins forem suficientes → realizar compra
Se Experience atingir o necessário → informar progressão
Se divisor for diferente de zero → realizar divisão
Nosso programa deixou de apenas executar cálculos.
Ele começou a reagir aos resultados desses cálculos.
Mas ainda existe uma limitação.
Observe:
if (playerCoins >= itemPrice)
{
std::cout << "Item purchased." << std::endl;
}
Quando a condição é verdadeira, sabemos o que fazer.
Mas quando ela é falsa?
Queremos provavelmente outra resposta:
Coins suficientes?
│
├── SIM → comprar
│
└── NÃO → informar que faltam moedas
Agora temos duas alternativas.
E isso nos leva diretamente ao próximo capítulo.
Próximo capítulo
Capítulo 11 — Quando existem alternativas
Série: Do zero ao jogo comercial com C++ e SFML
No próximo artigo vamos partir exatamente desta limitação:
if (playerCoins >= itemPrice)
{
std::cout << "Item purchased." << std::endl;
}
e perceber que nosso programa precisa representar dois caminhos:
condição verdadeira → executar uma ação
condição falsa → executar outra ação
Será o momento de conhecer:
else
Depois avançaremos para situações em que existem mais de duas possibilidades, preparando naturalmente o caminho para:
Capítulo 12 — Muitas opções: quando switch ajuda.
Nosso programa já sabe perguntar.
Agora ele aprenderá a responder de maneiras diferentes dependendo da resposta.
Comentários
Ainda não há comentários. Sê o primeiro a comentar!