Pac – Man
Transcrição
Pac – Man
Pac – Man Relatório do Grupo – Engenharia de Computação Universidade Federal do Espírito Santo – UFES Departamento de Informática – Programação II – 2011/2 Grupo Breno Simão Boscaglia Diego Paixão Rodrigues Nicolas Garcia Cavalcante Professores Crediné Silva de Menezes. Orivaldo de Lira Tavares. Universidade Federal do Espírito Santo Departamento de Informática 1. Introdução: O problema escolhido e desenvolvido pelo grupo foi o famoso jogo Pac– Man. Pac-Man é um jogo eletrônico criado por Toru Iwatani para a empresa Namco, e sendo distribuído para o mercado americano pela Midway. Produzido originalmente para Arcade no início da década de 80, tornou-se um dos jogos mais populares do momento, tendo versões para diversos consoles e continuações para tantos outros, inclusive na atualidade. A estrutura do jogo é bem simples: o jogador é uma cabeça redonda com uma boca que se abre e fecha, posicionado em um labirinto simples repleto de pastilhas e 4 fantasmas que o perseguiam. O objetivo é comer todas as pastilhas sem ser alcançado pelos fantasmas, em ritmo progressivo de dificuldade. A versão do jogo desenvolvida e trabalhada pelo grupo consiste basicamente nos principais objetivos do original. O usuário comanda o Pac–Man, que é o personagem principal, e se movimenta com ele ao longo do mapa, que possui obstáculos. Assim como o original, seu objetivo é comer todas as comidas e os bônus distribuídos ao longo do mapa, fugindo dos monstros simultaneamente. As comidas valem 1 ponto cada uma, e os bônus, que consistem no símbolo “$”, valem 10 pontos cada. Vale ressaltar que na tela do jogo, o usuário pode visualizar a pontuação que ele acumula ao longo do jogo, por meio do “Score”, que fica visível em cima do mapa. Antes de iniciar o jogo o usuário se depara com uma capa principal, que se segue por um menu, onde ele pode escolher em ver as instruções para o mesmo, ler sua breve história, ou joga-lo. Escolhendo a opção de jogo, tem-se dois níveis de dificuldade: o nível fácil (1 monstro) ou o difícil (2 monstros). Durante qualquer momento, inclusive na execução do jogo, o usuário tem a opção de sair, teclando “Esc”, onde ele irá visualizar uma mensagem se ele deseja realmente sair ou voltar para jogo, e o jogo então retorna exatamente de onde parou. Algumas diferenças entre a versão desenvolvida pelo grupo e o jogo original: No jogo original quando o Pac–Man come as comidas maiores, uma espécie de bônus, o usuário pode por um instante correr atrás dos monstros e então destruí-los momentaneamente, enquanto que na versão do grupo isto não é possível, somente os monstros podem comer o Pac– Man, ou seja, o usuário deve sempre fugir dos monstros de forma a tentar comer todas as comidas. No jogo original o usuário possui 3 vidas, enquanto que na versão desenvolvida pelo grupo o usuário possui somente 1 vida. 2 Universidade Federal do Espírito Santo Departamento de Informática Segue abaixo algumas fotos das principais telas do jogo: Capa: Menu Principal: 3 Universidade Federal do Espírito Santo Departamento de Informática Durante o Jogo: 2. Proposta: Para a melhor organização do problema codificado, foram utilizadas funções parametrizadas ou não. Para cada movimento, seja do Pac-Man ou dos monstros, para cada menu e para a impressão do mapa na tela, temos funções diferentes. A baixo seguem seus nomes e suas características: void menu(): Essa função é responsável por imprimir o menu do jogo, assim como levar o jogador para sua escolha (Jogo, História, Instruções ou Sair). void capa(): Essa função imprime apenas uma vez, quando o programa é rodado, há informações sobre o jogo, como os nomes dos desenvolvedores e dos professores. 4 Universidade Federal do Espírito Santo Departamento de Informática void layout(): Tal função é muito importante pois é nela que o jogo é criado. Todas as comidas, obstáculos e os bônus são atribuídos à matriz do jogo. void movimentoMon1(): Essa função tem como importância movimentar o monstro 1, que é aquele que está no canto superior esquerdo da tela. Toda a inteligência incorporada a ele deve-se a esta função que analisa a posição do Pac-Man em relação ao monstro, e realiza o melhor movimento possível. void movimentoMon2(): Assim como a função do monstro 1, essa daqui tem como objetivo movimentar o mostro 2 que está no canto inferior direito da tela. Ao ser chamada, ela analisa a sua posição em relação ao Pac-Man e faz o movimento mais adequado. void movimentoPac(): Esta função é a base do jogo, pois é nela que a tecla pressionada pelo usuário é identificada e o movimento do Pac-Man é realizado. Depois que tal movimento é feito, essa função chama as outras duas funções que realizam o movimento dos monstros (dependendo da dificuldade escolhida pelo jogador). void posicoes(int a, int b, int c, int d, int e, int f): Essa função paramétrica é responsável diretamente por imprimir o mapa para o jogador e está estritamente ligada à função “movimentoPac()”, pois a cada vez que há um movimento do Pac-Man ela é chamada para que “atualize” o mapa visto pelo usuário. int main(): A função principal serve para fazer as principais conexões entre as funções. Logo no início da criação do jogo, nos deparamos com um problema que foi solucionado com a criação de uma estrutura. Nós precisaríamos criar uma matriz que fosse possível alterar suas entradas a todo instante e em todas as funções. Por isso, não poderíamos declara-la em cada função separadamente. Portanto, criamos o struct { char mapa[25][60]; }jogo; que nos possibilita alterar sempre a mesma matriz. 5 Universidade Federal do Espírito Santo Departamento de Informática Dentre muitos algoritmos utilizados na criação do jogo os mais importantes são os que movimentam o Pac-man e os monstros. A função movimentoPac() é chamada no main() e ali ela fica aguardando a direção que o jogador deseja andar. Se a tecla pressionada for o “w”, então será atribuído à mesma coluna e uma linha a menos que a posição atual do Pac-Man a letra ‘C’ e aonde ele estava será atribuído um espaço vazio (‘0’ na tabela ASCII). Isso vale para os botões “a”, “s” e “d”, entretanto, o movimento será para a esquerda, para baixo e para a direita, respectivamente. Vale reforçar que no caso do movimento à esquerda, a nova posição será a mesma linha mas uma coluna a menos na matriz, assim como no movimento à direita será uma coluna a mais. Para o “s” a coluna da matriz permanece e linha é acrescida de um. É importante saber que antes que ocorra tais movimentos é necessário que seja conferido se a posição destino é parede, se for, o Pac-Man ficará parado. Dentro de cada um desses movimentos, as funções movimentoMon1() e movimentoMon2() são chamadas para que movimente os monstros. Para melhor explicar como funciona tais funções utilizaremos como referência apenas uma mas tudo se aplica para a outra. A função do monstro comparará a posição atual entre ele e o Pac-Man, sendo 8 possíveis situações, veja figura ao lado. Caso apenas as colunas da matriz esteja variando o monstro tentará ir em linha reta até o Pac-Man, mas se algum obstáculo (parede) for encontrado no caminho ele terá rotas de fuga alternativas. Agora, tomando o monstro como a origem do plano cartesiano e imaginando que o seu objetivo esteja no primeiro quadrante ele tentará alcança-lo fazendo movimentos em forma de escada. Entretanto, quando esta situação ocorre, um número aleatório (0 ou 1) é gerado e cada um deles faz um movimento diferente (o 0 varia a linha e o 1 varia a coluna). Assim, temos um movimento aleatório que sempre visa o seu objetivo. Assim como no caso em que eles estão na mesma linha, caso o movimento gerado (0 ou 1) for parede ele terá rotas de fuga programadas. Vale lembrar que as outras situações tem a mesma lógica, entretanto em sentido e direção diferentes. Algo muito importante, utilizado no decorrer do programa são as bibliotecas importadas no início do código, dentre elas temos: #include <stdio.h>: Do inglês “standard input-output header”, possui definições de entrada e saída como leitura de dados digitados e impressão de informações na tela. Utilizada no “printf” e “scanf”. #include <conio.h>: Tamebém ultilizada para entrada e sáida de dados. Ela possui funções mais complexas que a stdio.h não tem. Utilizada no getch(). 6 Universidade Federal do Espírito Santo Departamento de Informática #include <time.h>: Biblioteca responsável pela manipulação de data e hora. Com ela conseguimos gerar um número “aleatório” apartir do tempo da máquina. #include <windows.h>: Possui declarações de todas as funções no Windows API. Foi utilizada para o comando “Sleep”. É importante lembrar a interação entre o jogador e o jogo. Tentamos fazer com que ele fosse mais flexível possível. A toda hora, colocamos opções de voltar ao menu principal, e opções de sair do jogo. As teclas necessária para se jogar são mostradas antes que o jogo se inicie e são “w”,“a”,”s” e ”d” que faz o moviemnto do Pac-Man. 3. Testes: Por ser um jogo que não possui dados de entrada e saida numérica direta, para testá-lo foi necessário que criássemos situações críticas com o jogo, onde poderíamos encontrar erros. As tabelas a seguir são os testes feitos para o PacMan e para o monstro, respectivamente. Tecla Antes do movimento Movimento Esperado w w w w a a a a s s s s d d d d vazio comida parede monstro vazio comida parede monstro vazio comida parede monstro vazio comida parede monstro Cima Cima --Cima Esquerda Esquerda --Esquerda Baixo Baixo --Baixo Direita Direita --Direita Movimento Feito Depois do Movimento Cima Cima --Cima Esquerda Esquerda --Esquerda Baixo Baixo --Baixo Direita Direita --Direita vazio vazio parede Game Over vazio vazio parede Game Over vazio vazio parede Game Over vazio vazio parede Game Over Tabela 1: Teste feito com os movimentos do Pac-Man. Pode-se observar que todos os movimentos esperados aconteceram, comprovando sua eficiência. 7 Universidade Federal do Espírito Santo Departamento de Informática Monstro Pac-Man Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem Origem eixo x + eixo x + eixo x + Quadrante 1 Quadrante 1 Quadrante 1 Quadrante 1 Quadrante 1 Quadrante 1 eixo y + eixo y + eixo y + Quadrante 2 Quadrante 2 Quadrante 2 Quadrante 2 Quadrante 2 Quadrante 2 eixo x eixo x eixo x Quadrante 3 Quadrante 3 Quadrante 3 Quadrante 3 Quadrante 3 Quadrante 3 eixo y eixo y eixo y Quadrante 4 Quadrante 4 Quadrante 4 Quadrante 4 Quadrante 4 Quadrante 4 t 1ª Opção 2ª Opção 3ª Opção Movimento Esperado Movimento Feito ------0 0 0 1 1 1 ------0 0 0 1 1 1 ------0 0 0 1 1 1 ------0 0 0 1 1 1 Livre Parede Parede Livre Parede Parede Livre Parede Parede Livre Parede Parede Livre Parede Parede Livre Parede Parede Livre Parede Parede Livre Parede Parede Livre Parede Parede Livre Parede Parede Livre Parede Parede Livre Parede Parede --Livre Parede --Livre Parede --Livre Parede --Livre Parede --Livre Parede --Livre Parede --Livre Parede --Livre Parede --Livre Parede --Livre Parede --Livre Parede --Livre Parede ----Livre ----Livre ----Livre ----Livre ----Livre ----Livre ----Livre ----Livre ----Livre ----Livre ----Livre ----Livre Direita Cima Esquerda Cima Direita Esquerda Direita Cima Esquerda Cima Esquerda Baixo Cima Esquerda Direita Esquerda Cima Direita Esquerda Baixo Direita Cima Esquerda Direita Esquerda Cima Direita Cima Direita Baixo Cima Direita Esquerda Direita Cima Esquerda Direita Cima Esquerda Cima Direita Esquerda Direita Cima Esquerda Cima Esquerda Baixo Cima Esquerda Direita Esquerda Cima Direita Esquerda Baixo Direita Cima Esquerda Direita Esquerda Cima Direita Cima Direita Baixo Cima Direita Esquerda Direita Cima Esquerda Tabela 2: Teste feito com os movimentos dos Monstros. Pode-se observar que todos os movimentos esperados aconteceram, comprovando sua eficiência. Vale lembrar que a coluna “t” é o número aleatório gerado(0 ou 1). 8 Universidade Federal do Espírito Santo Departamento de Informática 4. Conclusão: À princípio o problema nos pareceu bastante simples, mas com o decorrer de sua idealização percebemos que teríamos um grande desafio pela frente. Com o trabalho pronto, podemos observar que nossos principais objetivos foram alcançados, até aqueles que julgávamos muito difíceis, como no caso dos monstros perseguirem o Pac-Man. Entretanto, nem tudo foi um sucesso em nosso projeto, um exemplo disso foi o fato de não conseguirmos fazer com que os monstros seguissem trajetórias diferentes, uma vez que eles estivessem juntos. Um outro problema encontrado, foi o fato de armazenarmos o que havia na entrada que o monstro iria ocupar, para que depois isso fosse impresso quando ele mudasse de posição, com isso, se e eventualmente eles ocuparem a mesma posição na matriz, vários outros monstros seriam “gerados”. Algumas soluções para resolver esses problemas foram pensadas e testadas, porém não obtivemos sucesso. Acreditamos que se tivéssemos mais tempo, com certeza solucionaríamos todos eles. 9