Программирование игр для Windows. Советы профессионала

       

Пример обработчика прерывания № 1 - Там полно звезд...


Чтобы продемонстрировать вам, насколько полезными могут оказаться многозадачность и прерывания, я написал в виде обработчика прерывания программу, которая рисует трехмерное звездное небо. Как вам уже известно, при каждом приращении счетчика внутреннего таймера, генерируется прерывание. При помощи вектора 0х1С я сопоставил этому прерыванию свою процедуру обслуживания, которая и создает трехмерное звездное небо. Поскольку обращение к моему обработчику происходит 18.2 раза в секунду, значит и картина звездного неба обновляется с этой же частотой. Нечто подобное мы могли бы использовать при написании игры, работающей на одном экране (игры типа «перестреляй их всех»). Наше звездное небо будет изменяться независимо от того, что будет происходить на переднем плане.

Обратите внимание на то, что процедура обслуживания прерывания сделана автономной. Это означает, что она инициализирует свои данные при первом обращении к ней (в этот момент она создает базу данных с информацией о звездах), а при последующих вызовах просто видоизменяет картинку.

И напоследок еще одно маленькое замечание: завершая программу, вы можете оставить ее резидентной в памяти, нажав клавишу Е. Сделав это, вы увидите, что звездное небо присутствует в строке приглашения DOS, что выглядит несколько странно! Причина такого поведения программы кроется в том, что когда вы завершаете ее нажатием клавиши Е, она не восстанавливает прежний обработчик прерывания. Компьютер продолжает вызывать по прерыванию от таймера наш обработчик. Вы наверняка даже и представить себе не могли, что это сработает! И, тем не менее, завершаясь, программа оставляет в оперативной памяти большую часть своего кода неизменным, в результате чего обработчику прерывания удается пережить окончание работы породившей его программы. Если вы попытаетесь запустить еще какую-нибудь программу, компьютер, скорее всего, «зависнет». Поэтому для написания настоящих резидентных программ такой метод применять не стоит. (На самом деле для этих целей предназначена специальная функция DOS, которая называется dos keep, но сейчас мы не будем подробно рассматривать резидентные программы.


Мы просто случайно создали одну из них). Если система «зависнет», вам придется перезагрузиться.
Текст программы, изображающей трехмерное звездное небо, представлен в Листинге 12.6.
Листинг 12.6. Трехмерное звездное небо (STARS.C).
// ВКЛЮЧАЕМЫЕ ФАЙЛЫ /////////////////////////////////////
#include <dos.h>
#include <bios.h>
#include <stdio.h>
#include <math.h>


#include <conio.h>
#include <graph.h>
// ОПРЕДЕЛЕНИЯ //////////////////////////////////////////
#define TIME_KEEPER_INT 0x1C
#define NUM_STARS 50
// структуры ////////////////////////////////////////////
typedef struct star_typ
int x,y;    // координаты звезды
int vel;    // проекция скорости звезды на ось Х
int color; // цвет звезды
} star, *star_ptr;
// ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ /////////////////////////////////////////
void (_interrupt _far *01d_Isr)(void);
// хранит старый обработчик прерывания
unsigned char far *video_buffer = (char far *)0xA0000000L;
// указатель на видеобуфер
int star_first=1; // флаг первого вызова автономной функции
// звездного неба
star starstNUM_STARS]; //звездное небо
// функции ///////////////////////////////////////////////////////
void Plot_Pixel_Fast(int x,int y,unsigned char color)
{
// эта функция рисует точку заданного цвета несколько быстрее,
// чем обычно за счет применения операции сдвига вместо операции
// умножения
// используем известный факт, что 320*у = 256*у + 64*у = у<<8 + у<<6
video_buffer[((у<<8) + (у<<6)) + х] = color;
} // конец Plot Pixel_Fast
/////////////////////////////////////////////////////////////
void _interrupt _far Star_Int(void)
{
// эта функция создает иллюзию трехмерного звездного неба,
// наблюдаемого из иллюминатора космического корабля Enterprise
// Замечание: эту функцию следует исполнять не реже одного раза
// в 55.4мс, иначе не избежать перезагрузки!
int index;
// проверка, надо ли нам инициализировать звездное поле
// (то есть первый ли раз вызывается функция)         


if (star_first)
{
// сброс флага первого вызова
star_first=0;
// инициализация всех звезд
for(index=0; index<NUM_STARS; index++)
{
// инициализация цвета, скорости и координаты каждой звезды
stars[index].х     = rand()%320;
stars[index].у     = rand()%180;
// выбор плоскости для звезды switch(rand()%3)
{ case 0:
// плоскость 1 - наиболее удаленная плоскость
{
// установка скорости и цвета звезды
stars[index].vel = 2;
stars[index].color = 8;
} break;
case 1: // плоскость 2 - плоскость, расположенная
// посередине
{
stars[index].vel = 4;
stars [index] .color =7;
} break;
case 2: // плоскость 3 -самая ближняя плоскость
{
stars[index].vel = 6;
stars[index].color = 15;
} break;
} // конец оператора switch
} // конец цикла
} // конец оператора if
else
{ // не первый вызов функции, поэтому производим рутинные
// действия: стирание, перемещение, рисование
for (index=0; index<NUM_STARS; index++)
{ // стирание
Plot_Pixel_Fast(stars[index].х,stars[index]-у,0);
// перемещение
if ((stars[index].x+=stars[index].vel) >=320 ) stars[index].х = 0;
// рисование
Plot_Pixel_Fast(stars[index],x,stars[index],y, stars[index].color);
} // конец цикла
} // конец else
} // конец Star_Int
// ОСНОВНАЯ ПРОГРАММА ///////////////////////////////////
void main(void)
{ int num1, num2,с
;
_setvideomode(_MRES256COLOR) ;
// установка обработчика прерывания
Old_Isr = _dos_getvect(TIME_KEEPER_INT) ;
_dos_setvect(TIME_KEEPER_INT, Star_Int);
// ожидание нажатия клавиши пользователем
_settextposition(23,0);
printf("Hit Q - to quit.");
printf("\nHit E - to see something wonderful...");
// чтение символа
с = getch();
// хочет ли пользователь рискнуть?
if (c=='e')
{
printf("\nLook stars in DOS, how can this be ?") ;
exit(0);
// выход без восстановления старого обработчика прерывания
} // конец оператора if
/ восстановление старого обработчика прерывания
_dos_setvect(TIME_KEEPER_INT, 01d_Isr);
_setvideomode(_DEFAULTMODE) ;
}// конец
функции main

Содержание раздела