Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Листинг 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-файлы и перемещать битовые образы;

§ Мы поговорили о спрайтах и создали простую библиотеку для работы с ними;

§ Мы затронули довольно сложные вещи, такие как дублирующий буфер и

§ вертикальная синхронизация, о которых более подробно мы поговорим чуть позже;

§ И, наконец, собрав все вместе, мы сделали демонстрационную программу, рисующую маленького ковбоя, который ходит по городу.

До встречи в новой главе.







© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.