Aula 09 - Enumerações e Estruturas
Conceitos-Chave:
- enumerações, como forma de atribuir um sentido lógico ao código
- estruturas, como um conjunto de propriedades de uma variável
Enumerações
As enumerações servem para ajudar a fazer um código mais lógico. Imaginemos que temos uma função que recebe o parâmetro:
int cor;
Decidíamos, para representar cores em números inteiros, convencionar o valor do azul como 1, o do vermelho como 2 e o do verde como 3. Assim, para representar a cor azul faríamos algo do tipo:
cor = 1;
Teríamos então que memorizar uma tabela com as cores, ou andar sempre com uma quando programamos... Felizmente, existem as enumerações:
#include <iostream>
using namespace std;
enum CORES { AZUL = 1, VERMELHO = 2, VERDE = 3 };
//não se esqueçam das chavetas, NEM DO PONTO E VÍRGULA
int VerificarCor(CORES cor_a_ver); //função para verificar qual a cor
int main()
{
CORES cor; //vejam! CORES é um tipo de variável
cor = AZUL;
VerificarCor(cor);
cor = VERMELHO;
VerificarCor(cor);
VerificarCor(VERDE);
cout << AZUL << " " << VERMELHO << " " << VERDE << " " << cor << endl;
cin.get();
return 0;
}
int VerificarCor(CORES cor_a_ver)
{
if (cor_a_ver == AZUL)
{
cout << "A Cor que escolheu foi Azul" << endl;
}
else if (cor_a_ver == VERMELHO)
{
cout << "A Cor que escolheu foi Vermelho" << endl;
}
else if (cor_a_ver == VERDE)
{
cout << "A Cor que escolheu foi Verde" << endl;
}
}
Acho simples de perceber, afinal as enumerações existem para
simplificar a escrita (e posterior leitura) do código.
Resta só dizer que uma enumeração é uma variável constante, ou
seja, o valor de AZUL, VERMELHO e VERDE não poderá ser alterada.
Não se esqueçam que, se fizerem cout << AZUL; irá aparecer '1' e não
"AZUL", mas isso é obvio...
Dica:
No exemplo acima fizemos:
enum CORES { AZUL = 1, VERMELHO = 2, VERDE = 3 };
Mas poderíamos ter feito:
enum CORES { AZUL = 1, VERMELHO, VERDE};
Que faz rigorosamente o mesmo efeito, pois basta atribuir valor a
uma variável, que as outras são incrementadas ( += 1)
Também poderíamos fazer:
enum CORES { AZUL, VERMELHO, VERDE};
Mas desta vez AZUL seria igual a 0 e não a 1
Uso de enumerações em jogos
Dentro de programação de jogos existem vários usos para enumerações. Por exemplo, é comum usar enumerações para representar o teclado, uma vez que, em algumas bibliotecas, o valor da tecla premida pelo utilizador está expresso em números (em alguns casos em hexadecimal). Assim:
enum Teclas
{ ... KEY_LEFT = 112, KEY_RIGHT = 113, ... };
Teclas t;
if(t == KEY_LEFT)
{ moverNaveEsquerda(); }
Os valores são inventados, mas processa-se algo semelhante nos jogos. Em vez de fazermos if(t == 112) podemos fazer if(t == KEY_LEFT) que é muito mais simples.
Outro uso para enumerações dentro dos jogos é no ciclo de jogo. São criados vários estados (CORRER, PARADO, NOVO_JOGO, MENU_JOGO, por exemplo) e sempre que quisermos mudar de um estado para o outro, bastaria modificar a variável que guarda os valores. Veremos isto mais adiante, quando criarmos o primeiro jogo em 2D.
Estruturas
Uma estrutura pode ser considerada como um esboço das propriedades de uma determinada variável. Imaginemos que temos 3 personagens num jogo: Nillight, Laveius e Nysker. Cada personagem tem as seguintes variáveis: int hp (Health Points = Pontos de Saúde), int mp (Magic Points = Pontos de Magia) e
Criaremos então uma estrutura chamada Personagem:
#include <iostream>
using namespace std;
struct Personagem
{
int hp, mp; //podem fazer isto; explicação abaixo.
}; //Olhem o ponto e vírgula ; !!!!!!!
int main()
{
//diferentes maneiras de preencher as variáveis:
Personagem Nillight = { 30, //HP
10, //MP
};
Personagem Laveius = { 50, 7 };
Personagem Nysker;
Nysker.hp = 20; //dá para fazer isto
Nysker.mp = 60;
cout << "HP de Nillight e de " << Nillight.hp << " e o MP e de " << Nillight.mp << endl;
cout << "HP de Laveius e de " << Laveius.hp << " e o MP e de " << Laveius.mp << endl;
cout << "HP de Nysker e de " << Nysker.hp << " e o MP e de " << Nysker.mp << endl;
cin.get();
return 0;
}
Uma estrutura define-se da seguinte forma:
struct nome_da_estrutura {
//...variáveis
};
Aviso:
Nunca se esqueçam do ';' depois de fecharem as chavetas '{}'.
Para podermos aceder às variáveis que estão dentro da estrutura, utilizamos um ponto a separar a variável "estruturada" e a propriedade:
Personagem teste;
teste.hp = 0;
cout << teste.hp;
Podemos criar estruturas para praticamente tudo. No exemplo seguinte vou representar uma estrutura de um quadrado (figura geométrica):
#include <iostream>
using namespace std;
struct Quadrado
{
int lado;
int area;
};
int calcularArea(Quadrado quadrado)
{
return (quadrado.lado * quadrado.lado);
}
int main()
{
Quadrado square;
square.lado = 4;
square.area = calcularArea(square);
cout << "Area do Quadrado: " << square.area << endl;
cin.get();
return 0;
}
Para trabalho de casa, podem criar funções para alterar ou mostrar
facilmente os vários atributos. Assim o protótipo da função para visualizar o
HP
de uma personagem seria:
int getHP(Personagem personagem);
E para modificar o valor seria:
void setHP(int hp, Personagem personagem);
Jogo - Hall of Monsters
É um jogo simples, criado por mim, baseado nas aventuras em modo de texto (estilo MUD). Pode-se dizer que é um resumo das aulas até agora:
/*
* Exemplo 9.4 - Hall of Monsters
* Propriedade de http://agnor.gamedev-pt.net
*
* Autor : João Portela aka Agnor
* Data : 20/02/2004 a 21/02/2004
* Desc : Hall of Monsters - jogo-tutorial
*
*/
#include <iostream>
#include <windows.h> //para usar o GetTickCount();
using namespace std;
/************************************
**************ESTRUTURAS*************
************************************/
struct Personagem
{
int hp; //os pontos de vida
int mp; //Pontos de Mana
int max_hp; // vai ser usada para recuperar o personagem no fim de cada partida
int max_mp; // como dito em cima.....
int forca; // a forca do personagem
};
struct Monstro
{
int hp; // HP do monstro
int forca; //forca do monstro
//monstros não necessitam de MP
char *nome; // necessário para podermos alterar o valor do nome sempre que quisermos...
//será explicado na aula 11 - referências e apontadores
};
/////////////////////////////////////
///////////Variáveis/////////////////
/////////////////////////////////////
Personagem player = {50, 7, 50, 7, 5};
Monstro ORC = { 40, 10, "Orc" };
Monstro LIZARD = { 60, 15, "Lizard" };
Monstro SHADOW = { 100, 23, "Shadow" };
Monstro BAHAMUT = { 140, 31, "Bahamut" };
Monstro ULTIMA = { 1000, 100, "Ultima" }; // tentem matar este :P
/* *
Declarações das funções
* */
int menuJogo();
int chamarBatalha(Monstro monstro);
int menuBatalha(Monstro monstro);
int MonstroIA(Monstro monstro);
int ganhou();
int perdeu();
int getRandom(int de, int ate);
//que main pequeno não é?
int main()
{
menuJogo();
cin.get();
return 0;
}
/* chamarBatalha(monstro);
Desc: chama uma Batalha para um determinado monstro ( ex: chamarBatalha(SHADOW); )
*/
int chamarBatalha (Monstro monstro)
{
cout << "\n\nApareceu um " << monstro.nome << endl;
menuBatalha(monstro);
return 0;
}
/* Cria o menu de Batalha ( utilizada por chamarBatalha(monstro); )
*/
int menuBatalha (Monstro monstro)
{
int escolha;
cout << "\n\nSeu HP: " << player.hp << '/' << player.max_hp << endl;
cout << "Seu MP: " << player.mp << '/' << player.max_mp << endl;
cout << "Escolha um ataque:" << endl;
cout << "\n1 - Ataque normal" << endl;
cout << "2 - Fogo" << endl;
cin >> escolha;
switch (escolha) {
case 1:
monstro.hp -= player.forca * 7;
cout << "\nVoce atacou!" << endl;
break;
case 2:
monstro.hp -= player.forca * 10;
player.mp -= 7;
cout << "\nVoce usou o fogo!" << endl;
break;
default:
cout << "\nComando nao conhecido..." << endl;
menuBatalha(monstro);
//estamos a utilizar recursividade nas funções: o menu vai ser chamado de novo
break;
}
if ( monstro.hp <= 0 )
ganhou(); //se só tiver uma instrução, um if não precisa de ter chavetas { ... }
else
MonstroIA(monstro);
return 0;
}
// A intelegência artificial do Monstro. Para dar mais hipoteses aos jogadores
// só há 25% do Monstro utilizar o ataque especial
int MonstroIA(Monstro monstro)
{
int random;
random = getRandom(1, 4);
switch (random)
{
case 1:
case 2:
case 3:
cout << "\n\n" << monstro.nome << " atacou!" << endl;
player.hp -= monstro.forca;
break;
case 4:
cout << "\n\n" << monstro.nome << " usou o seu ataque especial" << endl;
player.hp -= monstro.forca * 2;
break;
}
if (player.hp <= 0)
perdeu();
else
menuBatalha(monstro);
return 0;
}
//a popular função getRandom
int getRandom(int de, int ate) {
srand(GetTickCount());
int random = ( rand() % ate ) + de;
return random;
}
// perdeu :(((((
int perdeu()
{
cout << "\nPerdeu... Na proxima vez vais ter mais sorte :(" << endl;
menuJogo();
return 0;
}
//ganhou... e também subiu de nível :PPPP
int ganhou()
{
cout << "\n\n\nWee ganhou!!!!! e subiu de nivel :P" << endl;
player.forca += 2; //as modificações para "subir de nivel"
player.max_hp += 10;
player.max_mp += 7;
player.hp = player.max_hp; //recuperar a energia
player.mp = player.max_mp;
//esperar.....
cin.get();
menuJogo();
return 0;
}
// o menu do jogo
int menuJogo()
{
int escolha;
cout << "\nEscolha um adversario:" << endl;
cout << "\n1 - Orc" << endl;
cout << "\n2 - Lizard" << endl;
cout << "\n3 - Shadow" << endl;
cout << "\n4 - Bahamut" << endl;
cout << "\n5 - ULTIMA" << endl;
cin >> escolha;
switch (escolha)
{
case 1:
chamarBatalha(ORC);
break;
case 2:
chamarBatalha(LIZARD);
break;
case 3:
chamarBatalha(SHADOW);
break;
case 4:
chamarBatalha(BAHAMUT);
break;
case 5:
chamarBatalha(ULTIMA);
break;
default:
cout << "Comando nao conhecido.... tente outra vez\n\n" << endl;
menuJogo();
break;
}
return 0;
}
É um jogo bastante simples e com alguns bugs (erros lógicos), mas demonstra tudo o que aprendemos.
Experimentem fazer uma modificação do programa, adicionando mais monstros, corrigindo bugs, adicionando ataques.
Podem usar o email rpgplus@iol.pt para me mandarem o jogo para corrigir (e quem sabe publicar no site as modificações :)
Próxima aula -> C++ 10 - Alcance e Tempo de Vida de Variáveis
Fazer o download do código fonte dos exemplos da aula
Fazer o download da aula em PDF (Brevemente)
Ir para o topo da página