Chega de enrolação vamos fala do primeiro jogo. Como falei antes eu me baseei no código feito pelo Marcos Romeiro usando o MRDX
A imagem acima mostra o jogo feito no MRDX.
O primeiro dilema que tive foi como fazer o código, faço tudo em um arquivo carro.c ou divido em mais parte. faço tudo na main.c ou crio outras funções?... A minha escolha foi divide o código em 3 arquivos estruturas.h, estruturas.c e main.c.
As estruturas iriam conter as funções, para manipular o jogador, os carros inimigos e a bandeira. E o main.c ia ter funções para inicializar o allegro e a criação das variáveis do jogo. Eu criei 3 estruturas:
tipo_carro_inimigo, tipo_bandeira e tipo_jogador.
Eu achei legal desse código, pois me lembro de certa vez, ter lido em um site a seguinte pergunta: "Como faço no GameMaker ficar aparecendo as Naves inimigas" (algo do tipo)... O cara estava tentando fazer um jogo de nave. Não sei se a solução de ficar aparecendo os carros inimigos resolveria o problema dele. Vou tentar depois criar um jogo de nave XD....
Continuando...
Tinha que resolver os seguintes casos.
1) Como fazer os movimentos dos carros inimigos
2) Como fazer o movimento do personagem.
3) Como fazer o movimento da bandeira
4) Colisões
5) Escolhas dos pontos, e niveis.
Como fazer os movimentos dos carros inimigos
0 movimento do carro na vertical foi o mais simples de escolher. Escolhi simplesmente aumentar o valor do y do carro inimigo com base na velocidade (d = v * t kkkkkkkkkk... )...
E o movimento na horizontal que tive que escolher um método. Então a minha escolha foi movimentar aleatoriamente... com probabilidade de 1/3 para cada um dos seguintes movimento: no mover na vertical, mover para esquerda e para direita... Como pode ser visto no video essa escolha de movimento não foi muito legal.
Como fazer o movimento do personagem
A escolha do movimento do personagem. Foi algo bem tranquilo, as setas de direção move o personagem. Só que tive uma grande dificuldade para fazer essa parte. A ideia original era usar eventos. Usando evento eu não conseguir fazer os movimentos nas diagonais (segundo a internet, esse problema rola por causa da "matriz do teclado" , é utilizado esse método para economizar na produção dos teclados)...
A ideia original era o seguinte:
void atualiza_jogador(tipo_jogador *jogador, int tecla)
{
switch(tecla)
{
case ALLEGRO_KEY_UP:
if(jogador->y - 8 > 0)
{
jogador->y -= 8;
}
else
{
jogador->y = 0;
}
break;
case ALLEGRO_KEY_DOWN:
if(jogador->y + 8 < 416)
{
jogador->y += 8;
}
else
{
jogador->y = 416;
}
break;
case ALLEGRO_KEY_RIGHT:
if(jogador->x + 8 < 440)
{
jogador->x += 8;
}
else
{
jogador->x = 440;
}
break;
case ALLEGRO_KEY_LEFT:
if(jogador->x - 8 > 160)
{
jogador->x -= 8;
}
else
{
jogador->x = 160;
}
}
break;
}
E na funcao jogo_main
(...)
while(!al_is_event_queue_empty(fila_eventos)) //Verifica se tem eventos
{
al_wait_for_event(fila_eventos, &evento);
if (evento.type == ALLEGRO_EVENT_DISPLAY_CLOSE) //Fecha a janela
{
return;
}
if (evento.type == ALLEGRO_EVENT_KEY_DOWN)
{
atualiza_jogador(&jogador, evento.keyboard.keycode);
}
}
(...)
Mais infelizmente não deu certo se alguém tiver uma solução para "Como usar eventos para reconhecer 2 teclas pressionadas" eu aceito... A solução foi pesquisar... E pesquisar... No Allegro 4 (eu nunca programei e nem estudei a biblioteca do Allegro 4, só vi alguns exemplos) tinha uma maneira legal de ver se uma tecla estava ativa. Então achei algo "semelhante": ALLEGRO_KEYBOARD_STATE *key_state, al_get_keyboard_state(key_state) e al_key_down(key_state, ALLEGRO_KEY_UP)... A ultima funcao retorna 1 se a tecla estiver pressionada... bem legal neh...
Como fazer o movimento da bandeira
O movimento da bandeira é bem simples, equivale ao movimento dos carros inimigos na vertical só que com o dobro de velocidade...
Colisões
A colisão escolhida foi o modelo mais simples... Usando colisão por retângulo. Mais por algum motivo desconhecido ainda não esta 100%funcional... pretendo melhorar isso...
Escolhas dos pontos, e niveis
Toda vez que é pego uma bandeira... Aumenta 1 ponto... Toda vez q estiver em multiplos de 5 o numero de pontos aumenta 1 nível e a velocidade... Simples neh? Mais tem uma pequena valha nesse método... Quanto os ponto com um valor múltiplo de 5... os níveis vão aumenta infinitamente... Ate que o jogador pegue uma outra bandeira... A solução para isso foi da 1 ponto, toda vez q o jogador muda de nivel... Mais quero mudar isso... =]
Outras rotinas e melhorias vou explicar na próxima postagem. A versão 1.04 ja esta pronta... XD
E na minha opinião ela esta muito boa...
Imagens do jogo
Para baixar o código e o programa:
estruturas.h:
1: #include <stdio.h>
2: // Inclui o cabeçalho da bibilioteca Allegro 5
3: #include <allegro5/allegro.h>
4: #include <allegro5/allegro_image.h>
5: //Definicoes
6: #define MAX_CARROS 4
7: //-------------------------------------------------Carro inimigo--------------------------------------
8: typedef struct tipo_carro_inimigo
9: {
10: ALLEGRO_BITMAP *imagem;
11: short ativo;
12: int x;
13: int y;
14: } tipo_carro_inimigo;
15: //Carrega a imagem do carro
16: void carrega_carro_inimigo (tipo_carro_inimigo* carro_inimigo, char endereco[100]);
17: //Atualiza a posicao do carro
18: void atualiza_carro_inimigo (tipo_carro_inimigo* carro_inimigo, int velocidade);
19: //Desenha o carro na tela
20: void desenha_carro_inimigo (tipo_carro_inimigo* carro_inimigo);
21: //Verifica se o carro esta ativo
22: int status_carro_inimigo (tipo_carro_inimigo* carro_inimigo);
23: //Adiciona um carro no "jogo"
24: void add_carro_inimigo (tipo_carro_inimigo* carro_inimigo);
25: //-------------------------------------------------------bandeira------------------------------------
26: typedef struct tipo_bandeira
27: {
28: ALLEGRO_BITMAP *imagem;
29: int x;
30: int y;
31: } tipo_bandeira;
32: //Carrega a imagem da bandeira
33: void carrega_bandeira(tipo_bandeira *bandeira, char endereco[100]);
34: //Atualiza a posicao da bandeira
35: void atualiza_bandeira(tipo_bandeira *bandeira, int velocidade);
36: //Desenha bandeira
37: void desenha_bandeira(tipo_bandeira *bandeira);
38: //-------------------------------------------------------jogador-------------------------------------
39: typedef struct tipo_jogador
40: {
41: ALLEGRO_BITMAP *imagem;
42: int x;
43: int y;
44: } tipo_jogador;
45: //Carrega a imagem do jogador
46: void carrega_jogador(tipo_jogador *jogador, char endereco[100]);
47: //Atualiza a posicao do jogador
48: void atualiza_jogador(tipo_jogador *jogador, ALLEGRO_KEYBOARD_STATE *key_state);
49: //Desenha o jogador na tela
50: void desenha_jogador(tipo_jogador *jogador);
51: //verifica se o jogador colidiu com algum carro
52: int colicao_jogador_carro_inimigo (tipo_jogador *jogador, tipo_carro_inimigo* carro_inimigo);
53: //verifica se o jogador colidiu com a bandeira
54: int colicao_jogador_bandeira (tipo_jogador *jogador, tipo_bandeira *bandeira);
estruturas.c:
1: #include "estruturas.h"
2: void carrega_carro_inimigo (tipo_carro_inimigo* carro_inimigo, char endereco[100])
3: {
4: //Carrega a imagem do carro
5: carro_inimigo->imagem = al_load_bitmap(endereco);
6: if(!(carro_inimigo->imagem))
7: {
8: fprintf(stderr, "Falha ao carregar a imagem %s\n", endereco);
9: exit(-1);
10: }
11: carro_inimigo->ativo = 0;
12: }
13: void atualiza_carro_inimigo (tipo_carro_inimigo* carro_inimigo, int velocidade)
14: {
15: carro_inimigo->y += velocidade;
16: if(carro_inimigo->y > 640)
17: {
18: carro_inimigo->ativo = 0;
19: return;
20: }
21: switch(rand()%3) //Move para esquerda ou direita
22: {
23: case 0:
24: break;
25: case 1:
26: carro_inimigo->x += velocidade;
27: break;
28: case 2:
29: carro_inimigo->x -= velocidade;
30: }
31: if(carro_inimigo->x > 440)
32: {
33: carro_inimigo->x = 440;
34: }
35: else if(carro_inimigo->x < 160)
36: {
37: carro_inimigo->x = 160;
38: }
39: }
40: //Desenha o carro na tela
41: void desenha_carro_inimigo (tipo_carro_inimigo* carro_inimigo)
42: {
43: al_draw_bitmap(carro_inimigo->imagem, carro_inimigo->x, carro_inimigo->y, 0);
44: }
45: void carrega_jogador(tipo_jogador *jogador, char endereco[100])
46: {
47: //Carrega a imagem
48: jogador->imagem = al_load_bitmap(endereco);
49: if(!(jogador->imagem))
50: {
51: fprintf(stderr, "Falha ao carregar a imagem %s\n", endereco);
52: exit(-1);
53: }
54: //Coloca a posição inicial do jogador
55: jogador->x = 208;
56: jogador->y = 400;
57: }
58: //Verifica se o carro esta ativo
59: int status_carro_inimigo (tipo_carro_inimigo* carro_inimigo)
60: {
61: return carro_inimigo->ativo;
62: }
63: //Adiciona um carro no "jogo"
64: void add_carro_inimigo (tipo_carro_inimigo* carro_inimigo)
65: {
66: carro_inimigo->y = -60;
67: carro_inimigo->x = rand()%280 + 160;
68: carro_inimigo->ativo = 1;
69: }
70: void atualiza_jogador(tipo_jogador *jogador, ALLEGRO_KEYBOARD_STATE *key_state)
71: {
72: al_get_keyboard_state(key_state);
73: if (al_key_down(key_state, ALLEGRO_KEY_UP))
74: {
75: if(jogador->y - 8 > 0)
76: {
77: jogador->y -= 8;
78: }
79: else
80: {
81: jogador->y = 0;
82: }
83: }
84: if (al_key_down(key_state, ALLEGRO_KEY_DOWN))
85: {
86: if(jogador->y + 8 < 416)
87: {
88: jogador->y += 8;
89: }
90: else
91: {
92: jogador->y = 416;
93: }
94: }
95: if (al_key_down(key_state, ALLEGRO_KEY_LEFT))
96: {
97: if(jogador->x - 8 > 160)
98: {
99: jogador->x -= 8;
100: }
101: else
102: {
103: jogador->x = 160;
104: }
105: }
106: if (al_key_down(key_state, ALLEGRO_KEY_RIGHT))
107: {
108: if(jogador->x + 8 < 440)
109: {
110: jogador->x += 8;
111: }
112: else
113: {
114: jogador->x = 440;
115: }
116: }
117: }
118: void desenha_jogador(tipo_jogador *jogador)
119: {
120: al_draw_bitmap(jogador->imagem, jogador->x, jogador->y, 0);
121: }
122: //verifica se o jogador colidiu com algum carro
123: int colicao_jogador_carro_inimigo (tipo_jogador *jogador, tipo_carro_inimigo* carro_inimigo)
124: {
125: if(jogador->x >= carro_inimigo->x + 40)
126: {
127: return 0;
128: }
129: if (jogador->x + 40 <= carro_inimigo->x)
130: {
131: return 0;
132: }
133: if(jogador->y >= carro_inimigo->y + 40)
134: {
135: return 0;
136: }
137: if (jogador->y + 40 <= carro_inimigo->y)
138: {
139: return 0;
140: }
141: return 1;
142: }
143: int colicao_jogador_bandeira (tipo_jogador *jogador, tipo_bandeira *bandeira)
144: {
145: if(jogador->x >= bandeira->x + 32)
146: {
147: return 0;
148: }
149: if (jogador->x + 40 <= bandeira->x)
150: {
151: return 0;
152: }
153: if(jogador->y >= bandeira->y + 32)
154: {
155: return 0;
156: }
157: if (jogador->y + 40 <= bandeira->y)
158: {
159: return 0;
160: }
161: bandeira->y = -60;
162: bandeira->x = rand()%280 + 160;
163: return 1;
164: }
165: //Carrega a imagem da bandeira
166: void carrega_bandeira(tipo_bandeira *bandeira, char endereco[100])
167: {
168: bandeira->imagem = al_load_bitmap(endereco);
169: if(!(bandeira->imagem))
170: {
171: fprintf(stderr, "Falha ao carregar a imagem %s\n", endereco);
172: exit(-1);
173: }
174: bandeira->y = -60;
175: bandeira->x = rand()%280 + 160;
176: }
177: //Atualiza a posicao da bandeira
178: void atualiza_bandeira(tipo_bandeira *bandeira, int velocidade)
179: {
180: bandeira->y += velocidade;
181: if(bandeira->y > 480)
182: {
183: bandeira->y = -60;
184: bandeira->x = rand()%280 + 160;
185: }
186: }
187: void desenha_bandeira(tipo_bandeira *bandeira)
188: {
189: al_draw_bitmap(bandeira->imagem, bandeira->x, bandeira->y, 0);
190: }
main.c :
1: //allegro 5
2: #include <allegro5/allegro.h>
3: #include <allegro5/allegro_image.h>
4: #include <allegro5/allegro_primitives.h>
5: #include <allegro5/allegro_font.h>
6: #include <allegro5/allegro_ttf.h>
7: #include <stdio.h>
8: #include <stdlib.h>
9: #include <time.h>
10: #include "estruturas.h"
11: //protótipos
12: //Inicializa a biblioteca Allegro
13: void inicializa_allegro(int LARGURA_TELA, int ALTURA_TELA, ALLEGRO_DISPLAY **janela, ALLEGRO_EVENT_QUEUE **fila_eventos);
14: //Principal funcao do jogo
15: void jogo_main (ALLEGRO_DISPLAY *janela, ALLEGRO_EVENT_QUEUE *fila_eventos);
16: int jogo_menu(ALLEGRO_DISPLAY *janela, ALLEGRO_EVENT_QUEUE *fila_eventos, ALLEGRO_FONT *fonte, int recorde);
17: int main ()
18: {
19: ALLEGRO_DISPLAY *janela = NULL;
20: ALLEGRO_EVENT_QUEUE *fila_eventos = NULL;
21: //Tamanho da tela
22: int LARGURA_TELA = 640;
23: int ALTURA_TELA = 480;
24: inicializa_allegro( LARGURA_TELA, ALTURA_TELA, &janela, &fila_eventos);
25: //Muda o titulo da janela
26: al_set_window_title(janela, "Carros");
27: //Gera uma chave aleatoria;
28: srand(time(NULL));
29: jogo_main(janela, fila_eventos);
30: return 0;
31: }
32: void inicializa_allegro(int LARGURA_TELA, int ALTURA_TELA, ALLEGRO_DISPLAY **janela, ALLEGRO_EVENT_QUEUE **fila_eventos)
33: {
34: // Inicializa a Allegro
35: if (!al_init())
36: {
37: fprintf(stderr, "Falha ao inicializar a Allegro.\n");
38: exit (-1);
39: }
40: // Inicializa o add-on para utilização de imagens
41: if (!(al_init_image_addon()))
42: {
43: fprintf(stderr, "Falha ao inicializar add-on allegro_image.\n");
44: exit (-1);
45: }
46: //Cria a janela
47: *janela = al_create_display(LARGURA_TELA, ALTURA_TELA);
48: if (!(*janela))
49: {
50: fprintf(stderr, "Falha ao criar janela.\n");
51: exit (-1);
52: }
53: //Cria uma fila de eventos
54: *fila_eventos = al_create_event_queue();
55: if (!(*fila_eventos))
56: {
57: fprintf(stderr, "Falha ao criar fila de eventos.\n");
58: al_destroy_display(*janela);
59: exit (-1);
60: }
61: //Inicia o teclado
62: if (!al_install_keyboard())
63: {
64: fprintf(stderr, "Falha ao inicializar o teclado.\n");
65: exit(-1);
66: }
67: if (!al_init_primitives_addon())
68: {
69: fprintf(stderr, "Falha ao inicializar add-on de primitivas.\n");
70: exit(-1);
71: }
72: // Inicialização do add-on para uso de fontes
73: al_init_font_addon();
74: // Inicialização do add-on para uso de fontes True Type
75: if (!al_init_ttf_addon())
76: {
77: fprintf(stderr, "Falha ao inicializar add-on allegro_ttf.\n");
78: exit(-1);
79: }
80: }
81: void jogo_main (ALLEGRO_DISPLAY *janela, ALLEGRO_EVENT_QUEUE *fila_eventos)
82: {
83: ALLEGRO_FONT *fonte;
84: int velocidade;
85: int pontuacao;
86: int nivel;
87: int recorde = 0;
88: int distancia;
89: int i;
90: int indicie_carro;
91: int menu = 0;
92: const int CARRO_MAX = 4; //Numero maximo de carro
93: tipo_jogador jogador;
94: tipo_carro_inimigo carro_inimigo[CARRO_MAX];
95: tipo_bandeira bandeira;
96: ALLEGRO_EVENT evento;
97: ALLEGRO_KEYBOARD_STATE key_state;
98: //inicia o jogador
99: carrega_jogador(&jogador, "jogador.png");
100: //Carrega inimigos
101: for(i = 0; i < CARRO_MAX; i++)
102: {
103: carrega_carro_inimigo(&carro_inimigo[i], "inimigo.png");
104: }
105: //Carrega a bandeira
106: carrega_bandeira(&bandeira, "bandeira.png");
107: //Regista evento da janela
108: al_register_event_source(fila_eventos, al_get_display_event_source(janela));
109: al_register_event_source(fila_eventos, al_get_keyboard_event_source());
110: //Carrega a fonte usada
111: fonte = al_load_font("Ubahn.ttf", 24, 0);
112: if(!fonte)
113: {
114: fprintf(stderr ,"Falha ao carregar a fonte\n");
115: exit(-1);
116: }
117: while(1)
118: {
119: velocidade = 4;
120: pontuacao = 0;
121: nivel = 0;
122: distancia = 0;
123: indicie_carro = 0;
124: menu = 0;
125: //inicia o menu;
126: if(!jogo_menu(janela, fila_eventos, fonte, recorde))
127: {
128: return;
129: }
130: while(1)
131: {
132: while(!al_is_event_queue_empty(fila_eventos)) //Verifica se tem eventos
133: {
134: al_wait_for_event(fila_eventos, &evento);
135: if (evento.type == ALLEGRO_EVENT_DISPLAY_CLOSE) //Fecha a janela
136: {
137: return;
138: }
139: }
140: //Atualiza jogador
141: atualiza_jogador(&jogador, &key_state);
142: //Adiciona carros
143: if(distancia >= 200)
144: {
145: add_carro_inimigo(&carro_inimigo[indicie_carro]);
146: indicie_carro++;
147: indicie_carro %= CARRO_MAX;
148: distancia = 0;
149: }
150: else
151: {
152: distancia += velocidade;
153: }
154: //Limpa a tela
155: al_clear_to_color(al_map_rgb(0, 0, 0));
156: //Desenha um retangulo
157: al_draw_filled_rectangle(160, 0, 480, 480, al_map_rgb(125, 125, 125));
158: //Atualiza os carros inimigos
159: for(i = 0; i < CARRO_MAX; i++)
160: {
161: if(status_carro_inimigo(&carro_inimigo[i]))
162: {
163: atualiza_carro_inimigo(&carro_inimigo[i], velocidade);
164: //Desenha o carro
165: desenha_carro_inimigo(&carro_inimigo[i]);
166: if(colicao_jogador_carro_inimigo(&jogador, &carro_inimigo[i]))
167: {
168: menu = 1; //Volta para o menu inicial
169: }
170: }
171: }
172: if(menu) break; //Volta para o menu inicial
173: //Atualiza a bandeira
174: atualiza_bandeira(&bandeira, 2 * velocidade);
175: desenha_bandeira(&bandeira);
176: if(colicao_jogador_bandeira(&jogador, &bandeira))
177: {
178: pontuacao++;
179: printf("%i ", nivel);
180: }
181: if(pontuacao%5 == 0) //Mudar isso
182: {
183: pontuacao++;
184: nivel++;
185: velocidade++;
186: }
187: //Desenha o jogador
188: desenha_jogador(&jogador);
189: //Atualiza a tela
190: al_draw_textf(fonte, al_map_rgb(255, 0, 0), 10, 10, ALLEGRO_ALIGN_LEFT, "Nivel: %i", nivel);
191: al_draw_textf(fonte, al_map_rgb(255, 0, 0), 10, 34, ALLEGRO_ALIGN_LEFT, "pontuacao: %i", pontuacao);
192: al_flip_display();
193: al_rest(0.08);
194: }
195: //Muda o record
196: if(recorde < pontuacao)
197: {
198: recorde = pontuacao;
199: }
200: }
201: }
202: int jogo_menu(ALLEGRO_DISPLAY *janela, ALLEGRO_EVENT_QUEUE *fila_eventos, ALLEGRO_FONT * fonte, int recorde)
203: {
204: //Limpa a tela
205: al_clear_to_color(al_map_rgb(0, 0, 0));
206: al_draw_text(fonte, al_map_rgb(255, 0, 0), 220, 120, ALLEGRO_ALIGN_LEFT, "Enter - Novo Jogo");
207: al_draw_text(fonte, al_map_rgb(255, 0, 0), 220, 144, ALLEGRO_ALIGN_LEFT, "ESC - sair");
208: al_draw_textf(fonte, al_map_rgb(255, 0, 0), 220, 168, ALLEGRO_ALIGN_LEFT, "Recorde: %i", recorde);
209: al_flip_display();
210: ALLEGRO_EVENT evento;
211: while(1) //Verifica se tem eventos
212: {
213: if(!al_is_event_queue_empty(fila_eventos))
214: {
215: al_wait_for_event(fila_eventos, &evento);
216: if(evento.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
217: {
218: return 0;
219: }
220: if (evento.keyboard.keycode == ALLEGRO_KEY_ENTER)
221: {
222: return 1;
223: }
224: if (evento.type == ALLEGRO_EVENT_DISPLAY_CLOSE) //Fecha a janela
225: {
226: return 0;
227: }
228: }
229: }
230: return 0;
231: }
Nenhum comentário:
Postar um comentário