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

Листинг 5.16. Tombstone (TOMB.С).

Листинг 5.4. Рисование точки в позиции (х,у). | Листинг 5.5. Программа быстрого рисования точки. | Листинг 5.6. Рисование горизонтальной линии. | Листинг 5.7. Рисование вертикальной линии. | Листинг 5.8. Создание и отображение цветовой палитры (PALDEMO.C). | Листинг 5.9. Структура заголовка PCX-файла. | Листинг 5.10. Программа чтения файла формата PCX. | Листинг 5.12. Функция извлечения спрайта из загруженного PCXфайла. | Листинг 5.13. Функция рисования спрайта. | Листинг 5.14. Сохранение фона под спрайтом. |


Читайте также:
  1. Листинг 11.2. Структура данных игрока.
  2. Листинг 11.3. Функции полета мухи.
  3. Листинг 11.4. Муравейник (ANTS.С).
  4. Листинг 11.5. Падение мяча (BALL.C).
  5. Листинг 11.6. Идеальный газ (GAS.C).
  6. Листинг 12.2. Шпионим за часами (SPY.C)._________________
  7. Листинг 12.3. Автономное управление светом.

// ВКЛЮЧАЕМЫЕ ФАЙЛЫ /////////////////////////////////////////////

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

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

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

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

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

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


Дата добавления: 2015-07-12; просмотров: 134 | Нарушение авторских прав


<== предыдущая страница | следующая страница ==>
Листинг 5.15. Отображение символа.| ТРЕТЬЕ ИЗМЕРЕНИЕ

mybiblioteka.su - 2015-2024 год. (0.052 сек.)