Полезное:
Как сделать разговор полезным и приятным
Как сделать объемную звезду своими руками
Как сделать то, что делать не хочется?
Как сделать погремушку
Как сделать так чтобы женщины сами знакомились с вами
Как сделать идею коммерческой
Как сделать хорошую растяжку ног?
Как сделать наш разум здоровым?
Как сделать, чтобы люди обманывали меньше
Вопрос 4. Как сделать так, чтобы вас уважали и ценили?
Как сделать лучше себе и другим людям
Как сделать свидание интересным?
Категории:
АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника
|
Листинг 5.16. Tombstone (TOMB.С)// ВКЛЮЧАЕМЫЕ ФАЙЛЫ ///////////////////////////////////////////// #include <io.h> #include <conio.h> #include <stdio.h> #include <stdlib.h> #include <dos.h> #include <bios.h> #include <fcntl.h> #include <memory.h> #include <math.h> #include <string.h> // ОПРЕДЕЛЕНИЯ ////////////////////////////////////////////////// #define ROM_CHAR_SET_SEG 0xF000 // сегмент описания символов в ПЗУ #define ROM_CHAR_SET_OFF 0xFA6E // смещение, соответствующее // описанию первого символа #define VGA256 0х13 #define TEXT_MODE 0х03 #define PALETTE_MASK ОхЗC6 #define PALETTE_REGISTER_RD 0x3C7 #define PALETTE_REGISTER_WR 0x3C8 #define PALETTE_DATA 0x3C9 #define SCREEN_WIDTH (unsigned int)320 #define SCREEN_HEIGHT (unsigned int)200 #define CHAR_WIDTH 8 #define CHAR_HEIGHT 8 #define SPRITE_MIDTH 24 #define SPRITE_HEIGHT 24 #define MAX_SPRITE_FRAMES 16 #define SPRITE_DEAD 0 #define sprite_alive 1 #define SPRITE_DYING 2 // СТРУКТУРЫ ДАННЫХ //////////////////////////////////////// typedef struct RGB_color_typ { unsigned char red; // красная составляющая цвета (0-63) unsigned char green; // зеленая составляющая цвета (0-63) unsigned char blue; // синяя составляющая цвета (0-63) } RGB_color, *RGB_color_ptr;
typedef struct pcx_header_typ { char manufacturer; char version; char encoding; char bits_per_pixel; int x,y; int width,height; int horz_res; int vert_res; char ega_palette[46]; char reserved; char num_color_planes; int bytes_per_line; int palette_type; char padding[58]; } pcx_header, *pcx_header_ptr; typedef struct pcx_picture_typ { pcx_header header; RGB_color palette[256]; char far *buffer; } pcx_picture, *pcx_picture_ptr; typedef struct sprite_typ { int x,y; // текущая позиция спрайта int x_old,y_old; // предыдущая позиция спрайта int width,height; // размеры спрайта int anim_clock; // время анимации int anim_speed; // скорость анимации int motion_speed; // скорость движения int motion_clock; // время движения char far *frames[MAX_SPRITE__FRAMES]; // массив указателей // на образы int curr_frame; // отображаемый фрейм int num_frames; // общее число фреймов int state; // статус спрайта char far *background; // фон под спрайтом }sprite, *sprite_ptr; // ВНЕШНИЕ ФУНКЦИИ ///////////////////////////////// extern Set_Mode(int mode); // ПРОТОТИПЫ /////////////////////////////////////// void Set_Palette_Register(int index, RGB_color_ptr color); void Plot_Pixel_Fast(int x,int y,unsigned char color); void PCX_Init(pcx_picture *image); void PCX_Delete(pcx_picture *image); void PCX_Load(char *filename, pcx_picture_ptr image, int enable_palette); void PCX_Show_Buffer(pcx_picture_ptr image); // ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ////////////////////////////// unsigned char far *video_buffer = (char far *) 0xA0000000L; unsigned int far *video_buffer_w = (int far *)0xA0000000L; unsigned char far *rom_char_set = (char far *)0xF000FA6EL; // ФУНКЦИИ //////////////////////////////////////////// void Blit_Char(int xc,int yc,char c,int color) { // эта функция отображает символ на экране // используя описание // символов размером 8х8 точек, хранящееся в ПЗУ int offset,х,у; unsigned char data; char far *work_char; unsigned char bit_mask = 0х80; // вычисляем смещение описания символа в ПЗУ work_char = rom_charset + с * CHAR_HEIGHT; // вычисляем смещение символа в видеобуфере offset = (ус << 8} + (ус << 6) + хс; for (у=0; y<CHAR_HEIGHT; y++) { // сбросить битовую маску bit_mask = 0х80; for (x=0; x<CHAR_WIDTH; x++) { // если бит равен 1, рисуем пиксель if ((*work_char & bit_mask)) video_buffer[offset+x] = color; // сдвигаем маску bit_mask = (bit_mask>>1); } // конец отрисовки строки // переходим к следующей строке offset += SCREEN_WIDTH; work_char++; } // конец рисования } // конец функции ////////////////////////////////////////////////////////// void Blit_String(int x,int y,int color, char *string) { // функция отображает на экране передаваемую строку символов // Расстояние между символами строки постоянно // Для отображения символов вызывается функция blit_char int index; for (index=0; string[index]!=0; index++) { Blit_Char(x+(index<<3),y, string[index],color); } // конец цикла for } // конец функции /////////////////////////////////////////////////////// void Delay(int t) { float x = 1; while(t—>0) x=cos(x); } // конец функции /////////////////////////////////////////////////////// void Set_Palette_Register(int index, RGB_color_ptr color) { // функция устанавливает элемент таблицы цветов задаваемый // параметром index. Значения компонент цвета задаются полями // структуры color. // указываем VGA-карте, что мы будем изменять регистр палитры _outp(PALETTE_MASK,Oxff); // указываем номер изменяемого регистра _outp(PALETTE_REGISTER_WR, index); // теперь меняем значения компонентов. Каждый раз используется // один и тот же порт _outp(PALETTE_DATA,color->red); _outp(PALETTE_DATA,color->green); _outp(PALETTE_DATA,color->blue); } // конец функции /////////////////////////////////////////////////////// void PCX_Init(pcx_picture_ptr image) { // функция выделяет память для загрузки PCX-файла if ((image->buffer = (char far *)malloc (SCREEN_WIDTH * SCREEN_HEIGHT +1))); printf("\ncouldn't allocate screen buffer"); } // конец функции /////////////////////////////////////////////////////// void Plot_Pixel_Fast(int x,int y,unsigned char color) { // функция отображает на экране точку заданного цвета // вместо умножения используется сдвиг // пользуемся тем, что 320*у=256*у+64*у=у<<8+у<<6 video_buffer[ ((у<<8) + (у<<6)) + х] = color; } // конец функции /////////////////////////////////////////////////////////////////////////// void PCX_Delete(pcx_picture_ptr image) { // функция освобождает память, выделенную для загрузки PCX-файла _ffree (image->buffer); } // конец функции ////////////////////////////////////////////////////////// void PCX_Load(char *filename, pcx_picture_ptr image, int enable_palette} { // функция загружает PCX-файл и заполняет поля структуры // pcx_picture, включая изображение (после декомпрессии), // заголовок и палитру FILE *fp; int num_bytes,index; long count; unsigned char data; char far *temp_buffer; // открыть файл fp = fopen(filename,"rb"); // загрузить заголовок temp_buffer = (char far *)image; for (index=0; index<128; index++) { temp_buffer[index] = getc(fp); } // конец цикла for // загрузить данные и декодировать их в буфере count=0; while(count<=SCREEN_WIDTH * SCREEN_HEIGHT) { // получить первую часть данных data = getc(fp); // это RLE? if (data>=192 && data<=255) { // сколько байт сжато? num_bytes = data-192; // получить значение цвета для сжатых данных data = getc(fp); // заполняем буфер полученным цветом while(num_bytes-->0) { image->buffer[count++] = data; } // конец цикла while } // конец обработки сжатых данных else { // поместить значение цвета в очередную позицию image->buffer[count++] = data; } // конец обработки несжатых данных } // конец цикла while // перейти в позицию, не доходя 768 байт от конца файла fseek(fp,-768L,SEEK_END); // загрузить палигру for (index=0; index<256; index++) { // красная составляющая image->palette[index].red = (getc(fp) >> 2); // зеленая составляющая image->palette[index].green = (getc(fp) >> 2); // синяя составляющая image->palette[index].blue = (getc(fp) >> 2); } // конец цикла for fclose(fp); // если установлен флаг enable_palette, установить новую палитру if (enable_palette) { for (index=0; index<256; index++) { Set_Palette_Register(index, (RGB_color_ptr)&image->palette[index]); } // конец цикла for
} // конец установки палитры } // конец функции
////////////////////////////////////////// void PCX_Show_Buffer (pcx_picture_ptr image) { // функция копирует буфер, содержащий изображение из PCX-файла, // в видеопамять _fmemcpy(char far *)video_buffer, (char far *) image->buffer,SCREEN_WIDTH*SCREEN__HEIGHT); } // конец функции //////////////////////////////////////////////////// void Sprite_Init(sprite_ptr sprite, int x,int y, int ac, int as,int mc,int ms) { // функция инициализирует спрайт int index; sprite->x = x; sprite->y = у; sprite->x_old = x; sprite->y_old = у; sprite->width = SPRITE_WIDTH; sprite->height = SPRITE_HEIGHT; sprite->anim_clock = ac; sprite->anim_speed = as; sprite->motion_clock = me; sprite->motion_speed = ms; sprite->curr frame = 0; sprite->state = SPRITE_DEAD; sprite->num_frames = 0; sprite->background = (char far *)malloc (SPRITE_WIDTH * SPRITE_HEIGHT+1); // устанавливаем все указатели в значение NULL for (index=0; index<MAX_SPRITE_FRAMES; index++) sprite->frames[index] = NULL; } // конец функции //////////////////////////////////////////////////////// void Sprite_Delete(sprite_ptr sprite) { // функция освобождает всю связанную со спрайтом память int index; _ffree(sprite->background); // освобождаем память, выделенную под кадры анимации for (index=0; index<MAX_SPRITE_FRAMES; index++) _ffree(sprite->frames(index]); } // конец функции /////////////////////////////////////////////////////// void PCX_Grap_Bitmap (pcx_picture_ptr image, sprite_ptr sprite, int sprite_frame, int grab_x, int grab_y) { // функция выделяет один кадр из буфера PCX-файла. // Предполагается, что изображение размером 320х200 пикселей // в действительности представляет собой массив 12х8 изображений // каждое размерностью по 24х24 пикселя int x_off,y_off, x,y, index; char far *sprite_data; //вначале выделяем память для размещения спрайта sprite->frames[sprite_frame] = (char far *)malloc (SPRITE_WIDTH * SPRITE_HEIGHT); // создаем альтернативный указатель для ускорения доступа sprite_data = sprite->frames[sprite_frame]; // загружаем битовый образ в выделенную область памяти // вначале вычисляем, какое из изображений копировать. // Помните: в действительности PCX-файл представляет собой массив // из отдельных элементов размером 24х24 пикселя. // Индекс (0,0) соответствует левому верхнему изображению, // (11,7) - правому нижнему. x_off = 25 * grab_x + 1; y_off = 25 * grab_y + 1; // вычисляем начальный адрес y_off = y_off * 320; for (y=0; y<SPRITE__HEIGHT; y++) { for (x=0; x<SPRITE_WrETH; x++) { // берем очередной байт и помещаем его в текущую позицию буфера sprite_data[y*24 + х] = image->buffer [y_off + х_off + х]; } // конец копирования строки // переходим к следующей строке y_off+=320; } // конец копирования // увеличиваем счетчик кадров sprite->num_frames++; } // конец функции ////////////////////////////////////// void Behind_Sprite(sprite_ptr sprite) { // функция сохраняет содержимое видеопамяти в той области, // куда будет выведен спрайта char far *work back; int work_offset=0,offset,y; // создаем альтернативный указатель для ускорения доступа work_back = sprite->background; // вычисляем смещение в видеопамяти offset = (sprite->y << 6) + (sprite->y << 6) + sprite->x; for (y=0; y<SPRITE_HEIGHT; y++) { // копируем очередную строку видеопамяти в буфер _fmemcpy((char far *)&work_back[work_offset], (char far *)&video_buffer[offset], SPRITE_WIDTH); // переходим к следующей строке offset += SCREEN_WIDTH; work_offset += SPRITE_WIDTH; } // конец цикла for } // конец функции /////////////////////////////////////////// void Erase_Sprite(sprite_ptr sprite) { // функция восстанавливает фон, сохраненный перед выводом спрайта char far *work_back; int work_offset=0,offset,y; // создаем альтернативный указатель для ускорения доступа work_back = sprite->background; // вычисляем смещение в видеобуфере offset = (sprite->y_old << 8) + (sprite->y_old << 6} + sprite->x_old; for (y=0; y<SPRITE_HEIGHT; y++) { // копируем в видеопамять очередную строку буфера _fmemcpy((char far *)&video_buffer [offset],(char far *)&work_back[work_offset], SPRITE_WIDTH); // перейти к следующей строке offset += SCREEN_WIDTH; work_offset += SPRITE_WIDTH; } // конец цикла for } // конец функции /////////////////////////////////////////////////////// void Draw_Sprite(sprite_ptr sprite) { // функция, рисующая спрайт на экране вместо умножения // используется сдвиг char far *work sprite; int work_offset=0,offset,x,y; unsigned char data; work sprite = sprite->frames[sprite->curr_frame]; // вычислить смещение спрайта в видеобуфере offset = (sprite->y << 8) + (sprite->y << 6) + sprite->x; for (y=0; y<SPRITE_HEIGHT;y++) { for (x=0; X<SPRITE_WIDTH; X++) { // проверяем, не является ли пиксель "прозрачным" (с кодом 0), // если нет - рисуем if ((data=work_sprite[work_offset+x])) video_buffer[offset+x] = data; } // конец вывода строки // перейти к следующей строке в видеобуфере и буфере спрайта offset += SCREEN_WIDTH; work_offset += SPRITE_WIDTH; } //конец цикла no Y } // конец функции // ОСНОВНАЯ ПРОГРАММА ///////////////////////////////////////// void main(void) { long index,redraw; RGB_color color; int frame_dir = 1; pcx_picture town, cowboys; sprite cowboy; // установить видеорежим 320х200х256 Set_Mode(VGA256); // установить глобальные указатели на область памяти экрана Set_Screen_Pointers(); // загрузить фон PCX_Init((pcx_picture_ptr)&town); PCX_Load("town. pox", (pcx_picture_ptr)&town, 1); PCX_Show_Buffer((pcx_picture_ptr)&town); PCX_Delete((pcx_picture_ptr)&town); // вывести на экран заставку игры Blit_String(128, 24,50, "TOMBSTONE"); // загрузить образы PCX_Init((pcx_picture_ptr)&cowboys); PCX_Load("cowboys.pcx", (pcx_picture_ptr) &cowboys,0); // извлечь все образы из PCX-файла Sprite_Init((sprite_ptr)&cowboy,SPRITE_WIDTH,100,0,7,0,3); PCX_Grap_Bitmap ((pcx_picture_ptr) &cowboys, (sprite_ptr) &cowboy, 0, 0, 0); PCX Grap_Bitmap((pcx_picture_ptr) &cowboys, (sprite_ptr)&cowboy,1,1,0); PCX_Grap_Bitmap((pcx_picture_ptr)&cowboys, (sprite_ptr)&cowboy,2,2, 0); PCX_Grap_Bitmap ((pcx_picture_ptr)&cowboys, (sprite_ptr)&cowboy,3,1,0); // очистить память, выделенную для загрузки PCX-файла PCX_Delete((pcx_picture_ptr)&cowboys); Behind_Sprite((sprite_ptr)&cowboy); Draw_Sprite ((sprite_ptr) &cowboy); // главный цикл cowboy.state = SPRITE_ALIVE; while (!kbhit()) { redraw = 0; // используется как флаг необходимости перерисовки if (cowboy.state==SPRITE_ALIVE) { //не пора ли менять кадр? if (++cowboy.anim_clock > cowboy.anim_speed) { // сбрасываем счетчик времени cowboy.anim_clock = 0; if (++cowboy.curr_frame >= cowboy. num_frames) { cowboy.curr_frame = 0; } // конец обработки достижения последнего кадра redraw=1; } // конец смены кадра // проверяем не пора ли передвигать спрайт if (++cowboy.motion_clock > cowboy.motion_speed) { // переустановить счетчик движения cowboy.motion clock =0; // сохранить старую позицию cowboy.x_old == cowboy.x; redraw =1; //передвинуть спрайт if (++cowboy.x >= SCREEN_WIDTH-2*SPRITE_WIDTH) { Erase_Sprite((sprite_ptr)&cowboy); cowboy.state = SPRITE_DEAD; redraw = 0; } // конец обработки достижения последнего кадра } // конец обработки движения спрайта } // конец обработки ситуации "ковбой жив" else { // пытаемся "оживить" ковбоя if (rand()%100 == 0) { cowboy.state = SPRITE_ALIVE; cowboy.x = SPRITE_WIDTH; cowboy.curr frame = 0; cowboy.anim.speed = 3 + rand()%6; cowboy.motion_speed = 1 + rand()%3; cowboy.anim_clock = 0; cowboy.motion_clock = 0; Behind_Sprite{(sprite_ptr)&cowboy); } } // конец процесса "оживления" // теперь состояние спрайта изменено if (redraw) { // удалить спрайт в старой позиции Erase_Sprite((sprite_ptr)&cowboy); // сохранить фон в новой позиции Behind_Sprite((sprite_ptr)&cowboy); // нарисовать спрайт в новой позиции Draw_Sprite((sprite_ptr)&cowboy); // обновить старые координаты cowboy.x_old = cowboy.x; cowboy.у_old = cowboy.у; } // конец перерисовки Delay(1000); } // конец главного игрового цикла for(index=0; index <300000;index++,Plot_Pixel_Fast(rand()%320, rand()%200,0)); //Перейти обратно в текстовый режим Set_Mode(TEXT_MODE); }//Конец функции main
Итог Эта глава, наверное, самая важная в книге. Среди всей информации, которая, может быть, не относится напрямую к играм, вы узнали общую концепцию построения видеоигр, что абсолютно необходимо для их написания. Так что, если вы чего-то не поняли, то остановитесь и прочтите главу вновь (не беспокойтесь, я вас подожду). Если вы прочитали и поняли в этой главе все, то.должны знать, что: § Мы изучили VGA-карту и ее архитектуру; § Мы узнали о режиме l3h, который дает лучшее разрешение и наиболее прост для программирования; § Мы узнали, как в режиме l3h программировать регистры цвета, рисовать пиксели, загружать PCX-файлы и перемещать битовые образы; § Мы поговорили о спрайтах и создали простую библиотеку для работы с ними; § Мы затронули довольно сложные вещи, такие как дублирующий буфер и § вертикальная синхронизация, о которых более подробно мы поговорим чуть позже; § И, наконец, собрав все вместе, мы сделали демонстрационную программу, рисующую маленького ковбоя, который ходит по городу. До встречи в новой главе.
|