Студопедия

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

КАТЕГОРИИ:

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






Листинг 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

Пример обработчика прерывания № 2 - Ловим нажатия клавиш!

Как мы узнали в третьей главе, «Основы работы с устройствами ввода», мы можем использовать BIOS для чтения нажатия клавиши путем проверки значения скан-кода. Это отличный способ, и он вполне применим для большинства случаев, но что делать, если вы хотите одновременно нажать две клавиши? (Примером такой ситуации может служить момент, когда вы одновременно нажимаете клавиши «стрелка вверх» или «стрелка вниз» и «стрелка вправо» чтобы изменить направление движения на диагональное). Единственный способ обработать подобную ситуацию в программе требует более тонкой работы с клавиатурой. BIOS по сравнению со стандартными функциями Си просто дает нам еще один уровень управления, но если мы хотим добиться необходимой для профессионально написанных компьютерных игр функциональности, нам следует глубже, глубже и еще глубже разобраться с клавиатурой.

На самом деле клавиатура персонального компьютера представляет собой отдельный микрокомпьютер, который называется 8048. При нажатии или отпускании клавиши клавиатура посылает последовательность сигналов персональному компьютеру на обработку. BIOS сообщает нам о том, какая клавиша нажата, но умалчивает об отпущенных клавишах. Такой половинчатой информации не достаточно для того, чтобы организовать обработку одновременного нажатия нескольких клавиш. Нам нужно знать и когда была нажата, и когда была отпущена та или иная клавиша, чтобы написать алгоритм, способный отслеживать состояния некоторого набора клавиш. При нажатии клавиши мы выставляем соответствующий ей флаг в еостояние «нажато», а при отпускании — сбрасываем значение этого флага. Применяя такой подход, мы регистрируем нажатия различных клавиш и храним эту информацию в нашей структуре данных до тех пор, пока клавиша не будет отпущена.

При нажатии клавиши клавиатурой посылается код нажатия, а при отпускании — соответствующий код отпускания. Эти коды похожи на уже известный вам скан-код. Различие состоит в том, что при отпускании клавиши, каким бы ни было значение кода нажатия, к нему всегда прибавляется 128.

Чтобы наша программа смогла взять контроль за клавиатурой на себя, мы выгрузим обработчик клавиатуры операционной системы DOS и установим наш собственный драйвер. Он будет получать коды клавиш независимо от того, что произошло — нажатие или отпускание, а затем сохранять эту информацию в глобальной переменной, к которой имеет доступ наша Си-программа. При таком подходе функция нашей программы сможет использовать текущее значение этой переменной для выяснения того, какие клавиши в данный момент нажаты, а какие отпущены. Разобравшись что к чему, функция сведет эту информацию в таблицу. Клавиатурное прерывание имеет номер 0х09. Все, что нам требуется сделать, это написать и установить соответствующую процедуру обработки данного прерывания.

Прежде чем мы этим займемся, вспомним адреса клавиатурных портов ввода/вывода и их функции. Собственно клавиатурный порт ввода/вывода находится по адресу 60h, а регистр, управляющий клавиатурой — по адресу 61lh Эти порты находятся на микросхеме PIA (Peripheral Interface Adapter). Кроме всего прочего, нам еще потребуется выполнить определенные процедуры перед вызовом нашего обработчика прерывания и после его завершения. Общий порядок всех действий таков:

1. Войти в процедуру обслуживания прерывания. Это происходит при каяждом нажатии клавиши.

2. Прочитать из порта ввода/вывода 60h код клавиши и поместить его в глобальную переменную для последующей обработки программой или обновления содержимого таблицы, в которой хранится информация о нажатых клавишах.

3. Прочитать содержимое управляющего регистра из порта ввода/вывода 61h и выполнить над ним логическую операцию OR с числом 82h.

4. Записать полученный результат в порт регистра управления 61h.

5. Выполнить над содержимым управляющего регистра логическую операцию AND с числом 7Fh. Это сбрасывает состояние клавиатуры, давая ей понять что нажатие на клавишу обработано и мы готовы к считыванию информации о нажатии других клавиш.

6. Сбросить состояние контроллера прерываний 8259. (Без этого можно и обойтись, однако лучше подстраховаться). Для этого следует записать в порт 20h число 20h. Забавное совпадение, не правда ли?

7. Выйти из обработчика прерывания.

Листинг 12.7 содержит текст программы обработчика клавиатурного прерывания, позволяющего отслеживать состояние клавиш со стрелками. При работе этой программы вы можете использовать курсорные клавиши или их комбинации для перемещения маленькой точки в любом направлении по экрану.


Поделиться с друзьями:

mylektsii.su - Мои Лекции - 2015-2024 год. (0.01 сек.)Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав Пожаловаться на материал