EIC0020 – Laboratório de Computadores 2009/2010 – 2S ARKANOID Turma 5, Grupo 3 Francisca Teixeira - 090509139 – [email protected] Ricardo Cunha – 080509117 – [email protected] Faculdade de Engenharia da Universidade do Porto Rua Roberto Frias, s/n, 4200-465 Porto, Portugal Maio, 2010 Laboratório de Computadores | T5G03 Declaração de originalidade Declaramos sob compromisso de honra que este trabalho nas suas partes constituintes de código e relatório é original e da nossa autoria, não correspondendo, portanto, a cópia ou tradução de outros trabalhos já realizados, na FEUP ou fora dela. Mais declaramos que todos os documentos ou código que serviram de base ao desenvolvimento do trabalho descrito no relatório e seus anexos são adequadamente citados e explicitados e que todas as eventuais partes transcritas ou utilizadas de outras fontes estão devidamente assinaladas, identificadas e evidenciadas. Subscrevemos a declaração acima: Francisca Teixeira e Ricardo Cunha 2 Laboratório de Computadores | T5G03 Índice 1.Resumo ..................................................................................................................................................... 4 2. Descrição do Programa ............................................................................................................................ 5 Interface do jogo: ................................................................................................................................. 5 Regras do jogo: .................................................................................................................................... 5 3. Implementação ......................................................................................................................................... 6 3.1.Arquitectura do Programa................................................................................................................... 6 Módulos do trabalho: ............................................................................................................................ 6 3.2. Funcionalidades ................................................................................................................................ 7 Funcionalidades implementadas: ......................................................................................................... 7 Funcionalidades não especificadas mas implementadas:.................................................................... 7 Limitações do programa: ...................................................................................................................... 7 3.3 Detalhes Relevantes da Implementação ............................................................................................ 8 3.4 Instruções de compilação e utilização ................................................................................................ 8 3.5 Funcionamento do programa.............................................................................................................. 8 4. Conclusões ............................................................................................................................................... 9 5. Referências ............................................................................................................................................... 9 6. Anexos .................................................................................................................................................... 10 Anexo A – Documentação do Código..................................................................................................... 10 game.h ............................................................................................................................................... 10 video-graphics.h ................................................................................................................................. 12 sprite.h ............................................................................................................................................... 13 timer.h ................................................................................................................................................ 15 kbc.h................................................................................................................................................... 16 music.h ............................................................................................................................................... 19 ints.h................................................................................................................................................... 20 gqueue.h ............................................................................................................................................ 21 Anexo B – Diagrama UML ...................................................................................................................... 23 Anexo C – Diagrama de Chamadas de funções..................................................................................... 24 Anexo D – Histórico de Desenvolvimento .............................................................................................. 25 Anexo E – Makefile................................................................................................................................. 27 Anexo F – Proposta inicial ...................................................................................................................... 28 3 Laboratório de Computadores | T5G03 1.Resumo O presente relatório foi realizado no âmbito da disciplina de Laboratórios de Computadores, do 2º Semestre, 2º Ano, do Mestrado Integrado em Engenharia Informática e Computação, da Faculdade de Engenharia da Universidade do Porto. O objectivo foi criar, em linguagem C estruturada, uma aplicação que integrasse os diversos periféricos estudados na disciplina. Foram também usadas várias ferramentas de desenvolvimento de software, como SVN, MAKEFILES ou gerador de documentação DOXYGEN. Optou-se por criar um jogo, baseado no existente ARKANOID, do tipo breakout. Relativamente aos periféricos, foram incluídos: Teclado, para seleccionar menus e mover a tabela durante o jogo; Placa em modo gráfico com animação de sprites e texto; RTC, para periodicamente contar o tempo, e para obter a hora actual; Timer 2 e altifalante do sistema, para poder reproduzir as várias músicas e sons do jogo; Durante todo o processo foram usadas com frequência as ferramentas de desenvolvimento, nomeadamente: MAKEFILES, que gerem os ficheiros do projecto e respectivas dependências e simplificam o processo de compilação; GDB, um debugger que permite facilmente encontrar erros na aplicação; SVN, software de controlo de versões usado para manter o código e o seu histórico num servidor. DOXYGEN, gerador de documentação, o qual exigiu comentários em todos os ficheiros que constituem a aplicação. 4 Laboratório de Computadores | T5G03 2. Descrição do Programa O projecto desenvolvido baseia-se no conhecido jogo “Arkanoid”, apesar de naturais limitações em relação ao jogo original. No começo, o programa pergunta ainda na linha de comandos o nome do jogador. Depois do utilizador fornecer o seu nome (ou nick) ao programa este entre no modo gráfico, onde será apresentado um Menu. Aqui o utilizador terá quatro opções: Start Game (iniciar jogo), Show Best Scores (mostrar os melhores resultados), Show Instructions (mostrar as instruções do jogo) e Exit (sair do programa). Interface do jogo: No decorrer do jogo, estarão presentes os seguintes elementos gráficos, visualizados pelo utilizador: tabela movível pelo utilizador através do teclado, que se situa na parte do inferior do ecrã; bola que é animada e movimenta-se pelo ecrã; blocos que deverão ser destruídos pela bola, quando esta embate nos mesmos e estarão presentes na zona central do ecrã; duas paredes e um tecto, que simbolizam os limites na cena e são representados por longas barras na vertical e na horizontal. Também será apresentado no ecrã, na parte superior: o nome do jogador; o nível actual; o score actual; o número de vidas restantes; Regras do jogo: Em cada nível, o jogador terá de controlar o movimento horizontal da tabela, de forma a manter a bola em movimento, para que esta embata e destrua um total de 30 blocos. A bola irá sofrer desvios através de embates nas paredes, no tecto, na tabela movível e nos próprios blocos. Por cada bloco atingido, o jogador ganha 200 pontos, que será colocado imediatamente no seu score. Depois de ter derrubado todos os blocos, o nível acaba, passando para o seguinte, onde volta a encontrar 30 blocos. No entanto, e como já é um nível superior, a 5 Laboratório de Computadores | T5G03 velocidade da bola irá aumentar, o que dificultará a tarefa ao jogador de acompanhar a trajectória da mesma. O jogador tem no máximo três vidas. Ou seja, não pode deixar que a bola atinja a parte inferior do ecrã mais de três vezes. Caso contrário perde o jogo, e o seu score actual irá ser comparado com os dos melhores (presentes no ficheiro bestscores.txt) e colocado neste caso seja um dos dez melhores resultados. 3. Implementação 3.1.Arquitectura do Programa Módulos do trabalho: Main – este módulo é o responsável pela instalação e desinstalação das interrupções, entrada e saída do modo gráfico, e chamada função startMenu presente no módulo Game, depois de perguntar o nome ao jogador. Game – este é o módulo mais importante de todo o projecto desenvolvido. É responsável por criar o menu, o ambiente de jogo, a visualização das melhores pontuações efectuadas e o controlo das acções feitas pelo utilizador. Sprite – contém as funções essenciais para a construção de sprites. Cria um sprite a partir da leitura de um pixmap, desenha o sprite no ecrã, anima os sprites que se movem no mesmo ecrã e destrói os mesmos. Video Graphics – contém as funcionalidades necessárias para o uso da placa gráfica no modo gráfico. Destas funcionalidades, incluem-se a entrada e saída do modo gráfico, o preenchimento de pixels no ecrã e também o desenho de caracteres no modo gráfico. Ints – este módulo contém as funções de instalação e desinstalação de interrupções (por exemplo, o teclado) e também de habilitar/desabilitar PIC’s. Music – contém as funções necessárias ao uso de sons no programa, especialmente as frequências das notas musicais. KBC – controlador do teclado que contém as funções relativas à utilização do mesmo. 6 Laboratório de Computadores | T5G03 Timer – activa/desactiva as interrupções necessárias no timer. RTC – Este módulo inclui a leitura/escrita no RTC, bem como a função de interrupção escrita em C, e que é usada para a utilização dos sons presentes no programa. Queue – contém algumas funções típicas de gerenciamento de uma pilha (first in-first out). Além de inicializar a fila, tem as operações de adicionar e remover elementos da pilha. Esta é do tipo char. Queue Genérica – semelhante à Queue. No entanto pode aceitar elementos de outros tipos. Há ainda a referir o módulo Utypes que contém algumas definições para simplificar a escrita do código. Faz ainda parte do programa uma função assembly: kbd_handler que é um handler da interrupção do teclado. 3.2. Funcionalidades Funcionalidades implementadas: Controlo de interrupções do teclado, do TIMER0 e do RTC; Sons especiais de acordo com o evento, usando interrupções do RTC; Sprites animados; Escrita de texto em modo gráfico; Introdução das teclas numa queue (através da interrupção em Assembly) e leitura a partir da mesma. Funcionalidades não especificadas mas implementadas: Informação sobre o jogador (nome, vidas, nível, score, etc.) na parte superior do ecrã. Limitações do programa: Impossibilidade de bónus enviados para baixo (depois de um bloco ser destruído), para ser apanhado pela tabela (exemplos de bónus: tabela maior, mais pequena, mais bolas, etc..). 7 Laboratório de Computadores | T5G03 3.3 Detalhes Relevantes da Implementação Os blocos são criados a cada novo jogou (ou nível), para assim poder serem criados blocos coloridos diferentes aleatoriamente. As interrupções do teclado são tratadas através da função em assembly kbd_handler, que guarda a informação da tecla (scancode) numa queue. Através de uma máquina de estados, o programa consegue saber se está no menu ou no ambiente do jogo está e assim processar devidamente a informação transmitida pelo teclado. Os sons produzidos no jogo são efectuados a partir da rotina de interrupção do RTC (escrita em C), onde também funciona dentro duma máquina de estados. A qualquer momento do jogo, o jogador pode carregar na tecla ESC, onde será enviado directamente para o menu, saindo assim do jogo actual. 3.4 Instruções de compilação e utilização A ligação do programa e de todos os módulos pode ser efectuada através do uso de uma MAKEFILE. Para compilar pode executar-se na consola: make – gera um executável chamado akanoid.exe, todos os ficheiros de código e cabeçalhos e o ficheiro kbc_init.o devem estar na mesma directoria da makefile, local onde é executado o comando make; Para proceder a uma limpeza do código (eliminando todos os ficheiros terminados em *.o) pode executar-se: make clean – limpa todos os ficheiros *.o presentes na directoria onde é executado o comando (o ficheiro kbc_init.o não é eliminado); Para invocar o programa basta, apenas, chamar o executável, sem quaisquer parâmetros adicionais. Durante a execução do programa é possível sair do jogo carregando na tecla ESCAPE, desde que o jogo se encontre a decorrer. 3.5 Funcionamento do programa O programa começa por pedir o nome ao jogador. Após esse primeiro momento, o jogador é imediatamente levado até ao Menu, onde pode começar um jogo novo, ver os melhores resultados, ver as instruções do jogo ou sair do programa. O jogador escolhe a opção com ↑ (seta para cima) ou ↓ (seta para 8 Laboratório de Computadores | T5G03 baixo). Após carregar ENTER, o programa escolhe a opção seleccionada no ecrã pela tabela do jogo. Caso o jogador inicie um novo jogo será levado para o ambiente jogável, onde pode interagir com a cena através de três teclas: , para mover a tabela para a esquerda; , para mover a tabela para a direita. Durante a execução do programa é também possível sair do jogo carregando na tecla ESCAPE, desde que o jogo se encontre a decorrer. 4. Conclusões Este trabalho serviu essencialmente para aprofundar e aplicar conhecimentos adquiridos previamente nas aulas práticas. Permitiu uma boa aprendizagem sobre como interligar todos os componentes que haviam sido tratados separadamente. Possibilitou também entender, de uma forma mais prática e real, qual o uso de todos os periféricos usados na disciplina. Ao longo do desenvolvimento do projecto, apesar de terem sido encontradas algumas dificuldades em diversos pontos, foi sempre prestada a devida ajuda, quer devido às explicações das aulas teóricas, quer no auxílio das aulas práticas. Foram encontradas dificuldades iniciais na instalação/desinstalação das interrupções bem como na gestão de todas as interrupções em simultâneo. No final, conseguimos colmatar e gerir com sucesso essas dificuldades. Caso fosse possível, existiriam alguns melhoramentos a fazer ao programa: Utilizar o rato como periférico; Criar menu que permitisse ao utilizador pequenas configurações, como ligar o som; 5. Referências [1] DJGPP - http://www.delorie.com/djgpp/ [2] NASM - http://www.nasm.us/ [3] Makefile - http://www.gnu.org/software/make/ [4] SVN - http://subversion.tigris.org/ [5] Doxygen - http://www.stack.nl/~dimitri/doxygen/ [6] Microsoft Windows 98 - http://www.microsoft.com/en/us/default.aspx 9 Laboratório de Computadores | T5G03 6. Anexos Anexo A – Documentação do Código game.h /** Variáveis para comparar colisões */ #define MAX_LEN 600 #define WALL_HIT 0x01 #define ROOF_HIT 0x02 #define TABLE_HIT 0x03 #define BLOCK_HIT 0x04 #define GROUND_HIT 0x05 /** Enumeraçãoe e variável que permite determinar o estado em que a aplicação se encontra */ enum STATES {MENU, JOGO}; int state; /** Pilha que guarda os scancodes obtidos do teclado, de forma a processálos devidamente */ Queue *kbd_queue; /** Estrutura que guarda toda a informação relativa a um jogo, e que permite inicializá-lo */ typedef struct { char player[20]; int level; int score; int lives; Sprite* table; Sprite* roof; Sprite* leftWall; Sprite* rightWall; Sprite* ball; //Sprite* block; Sprite*** blocks; } Game; /** Estrutura que guarda as melhores pontuações obtidas no jogo */ typedef struct { char player[20]; int score; } BestScores; /** 10 Laboratório de Computadores | T5G03 Gera nºs aleatorios entre 0 e 8 para escolher um bloco dos oito existentes para desenhar */ int n_random(); /** Cria blocos para mostrar no ecrã de jogo, usando aleatoriamente a funcao n_random() */ Sprite*** createBlocks(char* base, int nrows, int ncol); /** Coloca na base "principal" o conteúdo da base "temporária" */ void refreshScreen(char* base, char* basetmp); /** Verifica colisões da bola (paredes, tecto, blocos e barra movivel) */ int check_colision(Sprite * sprite, char* base, int x, int y); /** Actualiza o buffer temporário para depois copiar para a base */ void actualizar(char* baseTmp, Game* game); /** Coloca o bloco apontado por block a preto para não aparecer no ecrã e não afectar as colisões */ void setBlackBlock(Sprite* block); /** Verifica se todos os blocos estão a preto */ Bool allBlackBlocks(Game* game); /** Processa as colisões ocorridas entre a bola e os vários elementos */ void process_colision(Game* game, int colision, char* base); /** Acrescenta o score final às melhores pontuacões caso o score for melhor que as 10 melhores já existente */ void newBestScores(char* base, Game* game); /** Inicia um novo jogo, tendo em conta a nova estrutura "Game" criada. */ void startGame(char* base, char* baseTmp, Game* game); /** Liberta memória de uma estrutura Game passada como argumento. */ void destroy_game(Game* game); /** 11 Laboratório de Computadores | T5G03 Cria um novo jogo, ou seja, cria todos os elementos gráficos necessários ao jogo e um segundo buffer, necessário para o bom funcionamento do programa. De seguida chama a função void startGame(char* base, char* baseTmp, Game* game) */ void createGame(char* base, Game* game); /** Mostra as instruções do jogo */ void showInstructions(char* base); /** Mostra as melhores pontuações até ao momento */ void showBestScores(char* base); /** Processa os acontecimentos do teclado, dependendo do estado em que o programa se encontra */ int process_kbd(char* base, Game* game); /** Mostra o menu principal e permite escolher a opcão desejada */ void startMenu(char* base); video-graphics.h /** @defgroup Video Video * @{ * Entering/leaving/utility video functions */ /* * there are two global variables, declared (but not defined) here */ int HRES; /**< global variable with the horizontal resolution in pixels */ int VRES; /**< global variable with the vertical resolution in pixels */ #define #define #define #define #define CHAR_H 16 MODE_640x480 0x101 MODE_800x600 0x103 MODE_1024x768 0x105 MODE_1280x1024 0x107 /** Returns the video memory address. */ ulong get_video_addr(int mode); /** Enter graphics mode, enabling near pointers and mapping video physical memory * to program virtual address. * * Returns a generic pointer pointing to video memory address or NULL on error. 12 Laboratório de Computadores | T5G03 * "mode" specifies the VESA graphics mode to use, and * the mapping information is returned through "map". * * Also initializes two global variables, VRES and HRES, */ char * enter_graphics(int mode, __dpmi_meminfo *map); /** Unmap video memory, disable near pointer and returns to text mode */ void leave_graphics(__dpmi_meminfo map); /** Draws a pixel of color "color" at screen coordinates x, y at memory address "base" */ void set_pixel(int x, int y, int color, char *base); /** Returns the pixel color at screen coordinates x, y at memory address "base" */ int get_pixel(int x, int y, char *base); /** Set graphics memory at memory address "base" to "color". */ void clear_screen(char color, char *base); /** Draw a line of color "color" between point (xi,yi) and (xf,yf) at memory address "base" */ void draw_line(int xi, int yi, int xf, int yf, int color, char *base); /** Desenha um caracter c em xi e yi, com cor fore_color e background back_color, redimensionado char_scale. */ void drawCharAt(char c, int xi, int yi, int fore_color, int back_color, int char_scale, char* video_base, char *table); /** Desenha uma string s em x_ori e y_ori, com cor fore_color e background back_color, redimensionado char_scale. */ void drawStringAt(char* s, int xi, int yi, int fore_color, int back_color, int char_scale, char* video_base, char *table); /** Desenha um inteiro num em xi e yi, com cor fore_color e background back_color, redimensionado char_scale. */ void drawIntAt(int num, int xi, int yi, int fore_color, int back_color, int char_scale, char* video_base, char *table) ; /** @} end of video */ sprite.h /** @defgroup Sprite Sprite * @{ * Sprite related functions */ /** A Sprite is an "object" that contains all needed information to * create, animate, and destroy a pixmap. The functions assume that 13 Laboratório de Computadores | T5G03 * the background is BLACK and they take into account collision with * other graphical objects or the screen limits. */ typedef struct { int x, y; ///< current sprite position int width, height; ///< sprite dimensions int xspeed, yspeed; ///< sprite current speed in the x and y direction char *map; ///< the sprite pixmap (use read_xpm()) } Sprite; #define */ #define #define #define MAX_SPEED 5 /**< each sprite maximum speed in pixels/frame RIGHT_HIT 2 LEFT_HIT 3 MOUSE_HIT 4 /**< collision with right block (WHITE) */ /**< collision with left block (WHITE) */ /**< collision with mouse (LIGHTMAGENTA) */ /** Reads a xpm-like sprite defined in "map" (look at pixmap.h for * examples). Returns the address of the allocated memory where the * sprite was read. Updates "width" and "heigh" with the sprite * dimension. Return NULL on error. * Assumes that VRES and HRES (the screen vertical and horizontal resolution) * are externaly defined. * * Usage example, using the defined sprite in pixmap.h: * <pre> * #include "pixmap.h" // defines pic1, pic2, etc * int wd, hg; * char *sprite = read_xpm(pic1, &wd, &hg); * </pre> */ char *read_xpm(char *map[], int *width, int *height); /** Creates with random speeds (not zero) and position * (within the screen limits), a new sprite with pixmap "pic", in * memory whose address is "base". * Returns NULL on invalid pixmap. */ Sprite * create_sprite(char *pic[], char *base); void draw_sprite(Sprite* sprite, char *base); /** Animates the figure, giving it the new position calculated with the values of its speed */ void animate_sprite(Sprite *fig, char *base); /** The "fig" sprite is erased from memory whose address is "base" * and used resources released. */ /** Liberta a memória da sprite passada como argumento */ void destroy_sprite(Sprite *sprite); /** Apaga a sprite do buffer base conseiderado */ void clear_sprite(Sprite *sprite, char *base); 14 Laboratório de Computadores | T5G03 timer.h /** @defgroup TimerCounter TimerCounter * @{ * * Timer-Counter definitions */ /** @name Timer Address */ /*@{*/ #define TIMER_0 0x40 ///< #define TIMER_1 0x41 ///< #define TIMER_2 0x42 ///< #define TIMER_CTRL 0x43 ///< register /*@}*/ /** @name Speaker and Timer2 /*@{*/ #define SPEAKER_CTRL 0x61 register, whose bits 0 and 1 the speaker #define TIMER2_ENABLE (1 << #define SPEAKER_ENABLE (1 << /*@}*/ Adress of Timer0 divider Adress of Timer1 divider Adress of Timer2 divider The address of the timer control control and bit meanings */ ///< The address of a generic PC control the timer2 clock and output to 0) ///< Enable Timer 2 clock 1) ///< Enable Timer 2 output to speaker /** @name Some usefull (and nice) definitions */ /*@{*/ #define TIMER_CLK 1193181 ///< The timers input frequency #define LCOM_MODE 0x36 ///< Control byte: LSB followed by MSB, mode 3, binary count #define LSB(i) ((i) & 0xFF) ///< The Least Significative Byte of a Word #define MSB(i) ((i) >> 8) ///< The Most Significative Byte of a Word /*@}*/ /** Program timer (0,1,2) with mode */ void timer_init(int timer, int mode); /** Load timer (0,1,2) with value */ void timer_load(int timer, int value); /** Wait mili miliseconds, indirectly counting T0 interrupts */ void mili_sleep(int mili); /** wait secs seconds, indirectly counting T0 interrupts */ void sec_sleep(int secs); /** @} end of TimerCounter * 15 Laboratório de Computadores | T5G03 kbc.h /** @defgroup KeyboardController KeyboardController * @{ * * Keyboard and Mouse related functions */ #define KBC_TIMEOUT 30 ///< maximum amount of milliseconds to wait for KBC response/availability /** @name The hardware register addresses */ /*@{*/ #define CMD_REG 0x64 ///< command register (read only) #define STAT_REG 0x64 ///< status register (write only) #define DATA_REG 0x60 ///< data register (read/write) /*@}*/ /** @name Bit meanings in the /*@{*/ #define OBF (1 << 0) ///< #define IBF (1 << 1) ///< #define AUX (1 << 5) ///< interface #define PAR_ERR (1 << 7) ///< #define TO_ERR (1 << 6) ///< /*@}*/ status register */ Output Buffer Full Input Buffer Full 1 if data at DATA_REG came from mouse Parity Error Timeout Error /** @name "Historical" commands to send to DATA_REG, response in DATA_REG */ /*@{*/ #define ResetKBC 0xFF ///< Reset the KBC interface #define DefaultKBD 0xF6 ///< Set default scancode and repeat rate #define DisableKBD 0xF5 ///< Historical Disable keyboard #define EnableKBD 0xF4 ///< Historical clear buffer and enable keyboard #define KBDRate 0xF3 ///< Keyboard repeat rate, one arg, bits 0-4 repeat rate, bits 5-6 start delay #define WriteLEDS 0xED ///< Turn on/off KBD LEDS, one arg, one bit per led, bits 0-2, 0-off, 1-on #define SCROLL_LOCK (1 << 0) ///< SCROLL_LOCK led for WriteLEDS command #define NUM_LOCK (1 << 1) ///< NUM__LOCK led for WriteLEDS command #define CAPS_LOCK (1 << 2) ///< CAPS_LOCK led for WriteLEDS command /*@}*/ /** @name Response /*@{*/ #define ACK #define Resend commands the whole #define Error /*@}*/ codes to commands/data written in DATA_REG */ 0xFA ///< Acknowledge OK response 0xFE ///< Resend error response; on multibyte command must be resent from the beginning 0xFC ///< Error /** @name Command codes to DATA_REG, return values in /*@{*/ #define ReadCommand 0x20 #define WriteCommand 0x60 #define DisableMouse 0xA7 send to CMD_REG, args, if exists, to DATA_REG */ ///< Read Command_Byte ///< Write Command_Byte, one arg ///< Disable Mouse Interface 16 Laboratório de Computadores | T5G03 #define EnableMouse #define TestMouse #define Test8042 on error #define TestKBD #define NDisableKBD keyboard #define NEnableKBD keyboard #define WriteMouse for the Mouse" #define ResetPC /*@}*/ 0xA8 ///< Enable Mouse Interface 0xA9 ///< Test Mouse Interface, returns 0 if OK 0xAA ///< Test KBC, returns 0x55 if sucess, 0xFC 0xAB ///< Test mouse, returns 0 if OK 0xAD ///< New (versus historical) Disable 0xAE ///< New (versus historical) Enable 0xD4 ///< Write Mouse, one arg, see "Commands 0xFE ///< Reset PC (reboot) /** @name Bit meanings in the Command_Byte * (read/write with command ReadCommand/WriteCommand) */ /*@{*/ #define INT_1 (1 << 0) ///< Enable generation of interrupts from keyboard #define INT_12 (1 << 1) ///< Enable generation of interrupts from mouse #define EN_KBD (1 << 4) ///< Enable keyboard interface (zero enables, one disables) #define EN_MOUSE (1 << 5) ///< Enable mouse interface (zero enables, one disables) /*@}*/ /** @name Bit meaning */ /*@{*/ #define YOVF (1 << 7) #define XOVF (1 << 6) #define YSGN (1 << 5) #define XSGN (1 << 4) #define MBT (1 << 2) #define RBT (1 << 1) #define LBT (1 << 0) /*@}*/ in first byte of mouse data packet ///< ///< ///< ///< ///< ///< ///< X overflow Y overflow Sign of data packet byte 3 (y movement) Sign of data packet byte 2 (x movement) Middle button Right button Left button /** @name Utility macros to inquiry first byte of mouse data packet */ /*@{*/ #define LEFT_BUTTON(dt) (((dt) & LBT) == LBT) ///< 1 if left button pressed #define RIGHT_BUTTON(dt) (((dt) & RBT) == RBT) ///< 1 if right button pressed #define MIDDLE_BUTTON(dt) (((dt) & MBT) == MBT) ///< 1 if middle button pressed #define Y_OVERFLOW(dt) in x movement #define X_OVERFLOW(dt) in y movement (((dt) & XOVF) == XOVF) ///< 1 if overflow (((dt) & YOVF) == YOVF) ///< 1 if overflow #define X_SIGN(dt) (((dt) & XSGN) == XSGN ? -1 : 1) ///< 1 if positive x movement, -1 if negative #define Y_SIGN(dt) (((dt) & YSGN) == YSGN ? -1 : 1) ///< 1 if positive y movement, -1 if negative /*@}*/ 17 Laboratório de Computadores | T5G03 /** Initializes the KeyBoard Controller. If 'debug' is not 0 every * read or write to the KBC, together with the read or writed data is * echoed to the screen. In this mode the function name being executed * is printed followed by a ':', add=xx means the I/O address written, * and data=xx the data read or written. * * A 1 is returned if a mouse is found. * * The function starts to flush any pending data in the KBC, reading * the data register until a timeout is received. * * Then it enables the KBC mouse interface, send a MouseReset to the * mouse and checks for the correct answer (0xFA, 0xAA then 0x00). If * the mouse was detected, data streaming is disabled (StreamDisable), * SampleRate is set to 100, Resolution is set to 8 counts/mm, Scaling * is set to 1:1, the mouse interrupts generation are enabled at the * KBC (not at the PIC!), and data streaming enabled * (StreamEnable). All this (but StreamEnable) shouldn't be necessary, * as MouseReset is supposed to do it properly. * * The KBDRate is also set to its maximum speed. * * Uses write_kbc_cmd(), write_kbc_data(), read_kbc() and write_aux() * */ void kbd_handler(void); /** Write 'data' to the command register, returning 0 for OK or -1 on * timeout. * * Uses write_kbc() */ int write_kbc_cmd( unsigned data); /** Returns 1 if a DOS mouse driver is installed, 0 if not. * * Needed to know if a DOS mouse driver is installed in order * to reinstall it at program end. * */ /** Write 'data' to the data register, returning ACK, Error or -1 on timeout. * * If a Resend reply is received from the KBC, it retries up to 3 times to * write the data. * * Uses write_kbc() and read_kbc() */ int write_kbc_data( unsigned data); /** Send 'cmd' to the mouse, prefacing it with the WriteMouse command * to the command register. * If a Resend reply is received from the KBC, it retries up to 3 times to write 'cmd', resending the whole sequence. * * Uses write_kbc_cmd(), write_kbc() and read_kbc() */ int write_aux(unsigned cmd); 18 Laboratório de Computadores | T5G03 /** Returns the data read a the data register. * * Waits for OBF on status register up to KBC_TIMEOUT milliseconds, * then reads and returns the data read at the data register. Returns * -1 on timeout or transmission error. */ int read_kbc(void); /** Write 'data' at IO address 'adr' , returning -1 on error or timeout. * * Waits for IBF on status register , than writes data to 'adr', * return -1 on timeout. */ int write_kbc(unsigned adr, unsigned data); /** @} end of KeyboardController */ music.h /** @defgroup Music Music * @{ * * Music related functions */ /** Note definition */ typedef struct { int freq; /**< note frequency */ int dur; /**< note duration in miliseconds */ } Note; /** Song definition */ typedef struct { int lenght; /**< number of notes */ int pause; /**< pause between notes (ms) */ Note *notes; /**< pointer to array of notes */ } Song; /** Turns the speeker on */ void speaker_on(); /** Turns the speeker off */ void speaker_off(); /** Plays a single note */ void play_note(Note *note); /** Plays a song using busy-waiting <pre> usage example: Note notes[] = {{Sol6, 100}, {Mi6,50}, {Sol6, 50}, {Mi6, 25}}; Song s = { sizeof(notes)/sizeof(Note), 10, notes}; 19 Laboratório de Computadores | T5G03 play_song(&s); </pre> */ void play_song(Song *s); ints.h /** @defgroup interrupts Interrupts * @{ * * Interrupt related functions */ /** @name PIC registers address */ /*@{*/ #define EOI 0x20 ///< End Of Interrupt Command #define PIC1_CMD 0x20 ///< PIC1 register address to #define PIC2_CMD 0xA0 ///< PIC2 register address to #define PIC1_MASK 0x21 ///< PIC1 register address to interrupt mask */ <-----------#define PIC2_MASK 0xA1 ///< PIC2 register address to interrupt mask */ /*@}*/ */ send EOI */ send EOI */ read/write read/write /** @name PC Interrupts */ /*@{*/ #define T0_IRQ 0 ///< Timer 0 <--------------#define KBD_IRQ 1 ///< keyboard #define COM2_IRQ 3 ///< serial port 2 #define COM1_IRQ 4 ///< serial port 1 #define FLP_IRQ 6 ///< floppy #define LPT_IRQ 7 ///< parallel port #define RTC_IRQ 8 ///< realtime clock #define MOUSE_IRQ 12 ///< mouse #define FPU_IRQ 13 ///< Floating point #define DISK1_IRQ 14 ///< Hard disk controller 1 #define DISK2_IRQ 15 ///< Hard disk controller 2 /*@}*/ /** @name Some usefull definitions */ /*@{*/ /** Gives mask bit associated with a given irq. * <em>Warning</em>, if irq > 7 the result must be applied to PIC2 */ #define IRQ_MASK_BIT(irq) ((irq) < 8 ? 1 << (irq) : (1 << (irq)) >> 8) /** gives the vector associated with a given IRQ */ #define IRQ_VECTOR(irq) ((irq) < 8 ? (irq) + 0x08 : (irq) - 8 + 0x70) /*@}*/ //void irq_func(void); /** Installs the ASM written function 'irq_func' as the interrupt * handler associated with interrupt 'irq', updating the 'old_irq' * structure with the current interrupt handler. Returns 0 on success * or -1 on error, in which case the original interrupt handler * remains installed. 20 Laboratório de Computadores | T5G03 * * See reinstall_asm_irq_handler() to reinstall the original handler. */ int install_asm_irq_handler(int irq, void (*irq_func)(void), _go32_dpmi_seginfo *old_irq); /** Installs the C written 'irq_func' interrupt handler at the * interrupt handler associated with interrupt 'irq', updating the * old_irq structure with the current interrupt handler. Returns 0 on * success or -1 on error, in which case the original interrupt * handler remains installed. * * See reinstall_c_irq_handler() to reinstall the original handler. */ int install_c_irq_handler(int irq, void (*irq_func)(void), _go32_dpmi_seginfo *old_irq); /** Reinstalls the interrupt handler specified in 'old_irq' for interrupt * 'irq'. See install_asm_irq_handler(). */ void reinstall_asm_irq_handler(int irq, _go32_dpmi_seginfo *old_irq); /** Reinstalls the interrupt handler specified in 'old_irq' for interrupt * 'irq'. See install_c_irq_handler(). */ void reinstall_c_irq_handler(int irq, _go32_dpmi_seginfo *old_irq); /** Mask the bit corresponding to 'irq', disabling its interrupts. * The correct PIC is used. */ void disable_irq(int irq); /** Unmask the bit corresponding to 'irq', enabling its interrupts. * The correct PIC is used. */ void enable_irq(int irq); /** @} end of interrupts */ gqueue.h / Generic Queue definition typedef struct { void *ptr; ///< int in; ///< int out; ///< from int cnt; ///< int size; ///< int ele_size; ///< } GQueue; generic pointer for a queue index on array where to put next element index on array where to get next element current number of elements in the queue queue capacity size of the element to put in the queue /** Initialize the queue */ GQueue * newGQueue(int n_ele, int size_ele); 21 Laboratório de Computadores | T5G03 /** Delete the queue */ void deleteGQueue(GQueue *q); /** Put ele in the queue pointed to by 'q' * Returns false if operation failed (the queue is full) */ Bool putGQueue(GQueue *q, void *ele); /** Get next element from queue * Returns -1 (an int) if there are no elements in the queue */ void * getGQueue(GQueue *q); /** Returns true if the queue is empty */ Bool isEmptyGQueue(GQueue *q); /** Returns true if the queue if full */ Bool isFullGQueue(GQueue *q); utypes.h /** @defgroup UserTypes UserTypes * @{ * * Typedefs for lazzy programmers */ typedef unsigned unsigned char typedef unsigned typedef unsigned typedef unsigned char uchar; ///< uchar is shorter to type than short ushort; ///< ushort is an unsigned short int uint; ///< uint is an unsigned int long ulong; ///< ulong is an unsigned long typedef unsigned char Byte; typedef unsigned short Word; ///< 8 bits, only on i386 ///< 16 bits, only on i386 /** User defined boolean type * <pre> * usage example: * Bool done = false; * while (done == false) {...} * </pre> */ typedef enum { false = 0, ///< the false value true = 1 ///< the true value } Bool; ///< user defined boolean type /**@} end of user types */ 22 Laboratório de Computadores | T5G03 Anexo B – Diagrama UML 23 Laboratório de Computadores | T5G03 Anexo C – Diagrama de Chamadas de funções 24 Laboratório de Computadores | T5G03 Anexo D – Histórico de Desenvolvimento 27 Maio 2010 r66 (Actualizações no relatório e modificações nas colisões) committed by ricardo.cunha.mieic r65 ([No log message]) committed by ricardo.cunha.mieic - [No log message] r64 ([No log message]) committed by klfrancisca - [No log message] r63 ([No log message]) committed by klfrancisca - [No log message] r62 ([No log message]) committed by klfrancisca - [No log message] r61 ([No log message]) committed by klfrancisca - [No log message] r60 ([No log message]) committed by ricardo.cunha.mieic - [No log message] r59 (Pequenas alterações nas colisões dos blocos) committed by klfrancisca - Pequenas alterações nas colisões dos blocos r58 ([No log message]) committed by ricardo.cunha.mieic - [No log message] r57 ([No log message]) committed by klfrancisca - [No log message] r56 ([No log message]) committed by klfrancisca - [No log message] r55 ([No log message]) committed by klfrancisca - [No log message] r54 ([No log message]) committed by klfrancisca - [No log message] r53 ([No log message]) committed by klfrancisca - [No log message] r52 ([No log message]) committed by klfrancisca - [No log message] r51 ([No log message]) committed by ricardo.cunha.mieic - [No log message] r50 ([No log message]) committed by klfrancisca - [No log message] r49 ([No log message]) committed by ricardo.cunha.mieic - [No log message] r48 ([No log message]) committed by klfrancisca - [No log message] r47 (Actualização do Relatorio.doc) committed by ricardo.cunha.mieic - Actualização do Relatorio.doc 26 Maio 2010 r46 ([No log message]) committed by klfrancisca - [No log message] r45 ([No log message]) committed by klfrancisca - [No log message] r44 ([No log message]) committed by klfrancisca - [No log message] r43 ([No log message]) committed by ricardo.cunha.mieic - [No log message] r42 ([No log message]) committed by ricardo.cunha.mieic - [No log message] Commits mais antigos May 25, 2010 r41 (Adicionadas musicas ) committed by ricardo.cunha.mieic - Adicionadas musicas May 24, 2010 r40 ([No log message]) committed by ricardo.cunha.mieic - [No log message] May 23, 2010 r39 ([No log message]) committed by klfrancisca - [No log message] May 23, 2010 r38 (Modificacoes no RTC handler de modo a tocar musica ) committed by ricardo.cunha.mieic Modificacoes no RTC handler de modo a tocar musica May 23, 2010 r37 ([No log message]) committed by klfrancisca - [No log message] May 23, 2010 r36 (Modificações básicas nno funcionamento da pilha para os scan...) committed by klfrancisca Modificações básicas nno funcionamento da pilha para os scancodes. May 21, 2010 r35 ([No log message]) committed by klfrancisca - [No log message] May 21, 2010 r34 ([No log message]) committed by klfrancisca - [No log message] May 20, 2010 25 Laboratório de Computadores | T5G03 r33 ([No log message]) committed by klfrancisca - [No log message] May 20, 2010 r32 ([No log message]) committed by klfrancisca - [No log message] May 20, 2010 r31 (Melhorado sistema de mostrar pontuações - colisões dos bloco...) committed by ricardo.cunha May 19, 2010 r30 (Foram incluídas as queues para o movimento da barra.) committed by klfrancisca r29 ([No log message]) committed by ricardo.cunha.mieic - [No log message] May 17, 2010 r28 ([No log message]) committed by klfrancisca - [No log message] May 13, 2010 r27 ([No log message]) committed by ricardo.cunha.mieic - [No log message] May 11, 2010 r26 ([No log message]) committed by ricardo.cunha.mieic - [No log message] May 05, 2010 r25 ([No log message]) committed by klfrancisca - [No log message] May 05, 2010 r24 ([No log message]) committed by klfrancisca - [No log message] May 05, 2010 r23 ([No log message]) committed by ricardo.cunha.mieic - [No log message] May 05, 2010 r22 ([No log message]) committed by klfrancisca - [No log message] May 05, 2010 r21 ([No log message]) committed by klfrancisca - [No log message] May 04, 2010 r20 (Adicionado createGame() para criar uma nova estrutura do tipo Game) committed by ricardo.cunha.mieic Apr 30, 2010 r19 ([No log message]) committed by ricardo.cunha.mieic - [No log message] Apr 29, 2010 r18 ([No log message]) committed by klfrancisca - [No log message] Apr 29, 2010 r17 (Adicionado makefile, criado showMenu, process_kbd, showBestS...) committed by ricardo.cunha.mieic Apr 28, 2010 r16 ([No log message]) committed by klfrancisca - [No log message] Apr 28, 2010 r15 ([No log message]) committed by klfrancisca - [No log message] Apr 28, 2010 r14 ([No log message]) committed by ricardo.cunha.mieic - [No log message] Apr 28, 2010 r13 ([No log message]) committed by klfrancisca - [No log message] Apr 24, 2010 r12 (modificado sprite.c, adicionado kbc.c e rtc.c para interrupc...) committed by ricardo.cunha.mieic modificado sprite.c, adicionado kbc.c e rtc.c para interrupcoes do teclado e RTC. Funcao em assembly kbc_isr, para buscar scancode de uma tecla. Apr 24, 2010 r11 (modificado sprite.c, adicionado kbc.c e rtc.c para interrupc...) committed by ricardo.cunha.mieic modificado sprite.c, adicionado kbc.c e rtc.c para interrupcoes do teclado e RTC. Funcao em assembly kbc_isr, para buscar scancode de uma tecla. Apr 23, 2010 r10 (adicionado Gqueue.c Gqueue.h e pixmap.h para as sprites) committed by ricardo.cunha.mieic adicionado Gqueue.c Gqueue.h e pixmap.h para as sprites Apr 23, 2010 r9 ([No log message]) committed by ricardo.cunha.mieic - [No log message] 26 Laboratório de Computadores | T5G03 Apr 23, 2010 r8 (Update da proposta de trabalho) committed by ricardo.cunha.mieic - Update da proposta de trabalho Apr 22, 2010 r7 ([No log message]) committed by klfrancisca - [No log message] Apr 22, 2010 r6 ([No log message]) committed by klfrancisca - [No log message] Apr 22, 2010 r5 ([No log message]) committed by klfrancisca - [No log message] Apr 22, 2010 r4 ([No log message]) committed by klfrancisca - [No log message] Apr 22, 2010 r3 ([No log message]) committed by klfrancisca - [No log message] Apr 14, 2010 r2 (Proposta de trabalho para entregar a 16 de Abril.) committed by klfrancisca - Proposta de trabalho para entregar a 16 de Abril. Apr 13, 2010 Project lcomproject created by klfrancisca - Trabalho Práctico LCOM - FEUP - 2009 - 2010 Anexo E – Makefile LDFLAGS = -g OBJ = main.o game.o kbc.o kbd_isr.o ints.o sprite.o video-graphics.o rtc.o time_tick.o timer.o queue.o music.o gqueue.o all: arkanoid.exe arkanoid.exe: $(OBJ) gcc -Wall $(OBJ) -o arkanoid.exe main.o: main.c game.h rtc.h video-graphics.h gcc -Wall -c main.c game.o: game.c game.h utypes.h kbc.h ints.h pixmap.h local_table.h queue.h gcc -Wall -c game.c queue.o: queue.h queue.c utypes.h gcc -Wall -c queue.c gqueue.o: gqueue.h gqueue.c utypes.h gcc -Wall -c gqueue.c kbc.o: kbc.c kbc.h gcc -Wall -c kbc.c music.o: music.c music.h timer.h utypes.h gcc -Wall -c music.c timer.o: timer.c timer.h gcc -Wall -c timer.c rtc.o: rtc.c rtc.h ints.h utypes.h music.h timer.h gcc -Wall -c rtc.c kbd_isr.o: kbd_isr.asm 27 Laboratório de Computadores | T5G03 nasm -t -f coff kbd_isr.asm -o kbd_isr.o time_tick.o: time_tick.asm nasm -t -f coff time_tick.asm -o time_tick.o ints.o: ints.c ints.h gcc -Wall -c ints.c sprite.o: sprite.c sprite.h video-graphics.h utypes.h gcc -Wall -c sprite.c video-graphics.o: video-graphics.c video-graphics.h gcc -Wall -c video-graphics.c clean: rm -f *.o arkanoid.exe Anexo F – Proposta inicial Proposta de Trabalho para Laboratórios de Computadores 2009-2010 Nomes: Francisca Teixeira (090509139) e Ricardo Cunha (080509117) Turma: 2MIEIC6 Grupo: 3 Link do trabalho: http://code.google.com/p/lcomproject/ Titulo: Arkanoid Tipo: Bat and ball - Breakout Baseado em: Jogo com o mesmo nome Periféricos: Placa gráfica em modo texto e gráfico, teclado, RTC, timer Interrupções: Teclado, RTC Funções Assembly: (a preencher na 2ª semana) Descrição: O jogo é formado por uma bola, uma tabela móvel e blocos coloridos. O ecrã é limitado superior e lateralmente por paredes indestrutíveis, e aberto inferiormente. Os blocos encontram-se agregados na zona superior do ecrã. O jogador tem controlo apenas sobre a tabela móvel (na direcção horizontal), devendo utilizá-la para evitar que a bola, que se encontra em constante movimento horizontal e vertical desde o ínicio do jogo, caia no limite inferior (aberto) do ecrã, desaparecendo. Caso não consiga evitá-lo, perderá uma das três hipóteses (vidas) que dispõe. A bola, por sua vez, ao bater num bloco destrói-o, fazendo-o desaparecer. Cada vez que esta embata numa parede, bloco ou na tabela móvel, mudará de direcção. O jogador somará pontos por cada bloco destruído. Durante a realização do jogo o tempo corrente do mesmo é mostrado, assim como o 28 Laboratório de Computadores | T5G03 número de blocos destruídos e o número de vidas restantes. Para passar ao nível seguinte, o jogador deve eliminar todos os blocos coloridos do nível em que se encontra. Subindo de nível, a velocidade da bola aumenta, tornandose mais difícil o controlo desta. Planeamento: (a preencher na 2ª semana. Deve incluir protótipo de funções a implementar. Se não for desde já possível incluir protótipos das funções a implementar em cada semana, fazê-lo só para a 1ª semana, e apresentar em cada aula os protótipos das funções a implementar na semana seguinte) 1ª semana: Os objectivos para esta semana consistem em: criar sprites, animar sprites, limpar sprites do ecrã e verificar colisões com as paredes. Protótipos a implementar: Sprite* create_sprite(char* pic, char* base, int x, int y); Int animate_sprite(Sprite* fig, char* base); void destroy_sprite(Sprite* fig, char* base); int checkColision(Sprite* fig, int x, int y); 2ª semana: Nesta semana comprometemo-nos a criar o ambiente gráfico do jogo e torná-lo navegável, ou seja, menu inicial, menu de instrucções, menu de melhores pontuações e ambiente de acção do jogo. Protótipos: void startMenu(char* base); void showInstructions(char* base) void showBestScores(char* base); void process_kbd(char* base); void startGame(char* base); 3ª semana: Os objectivo passam por: - Modificar a rotina void kbd_handler() para guardar os scancodes do teclado numa queue, de forma a processar eficientemente o movimento da tabela no ambiente do jogo. - Desenvolver a função Sprite *** createBlocks(char* base, int nrows, int ncol), que cria e devolve um apontador para uma estrutura que contém os blocos a serem desenhados na cena e posteriormente destruídos. - Terminar o desenvolvimento da função void startGame(char* base, char* baseTmp, Game* game), para que seja possível jogar efectivamente, isto é, processar o devido comportamento da bola quando embate na tabela, paredes indestrutíveis que compõem a cena do jogo e blocos. - Activar outras pequenas funcionalidades como a contagem de vidas que o jogador possui, pontos por jogo e no total, best-score, etc. 29