Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Листинг 12.5. Перепрограммируем системные часы (OUTATIME.C).
// ВКЛЮЧАЕМЫЕ ФАЙЛЫ ///////////////////////////////////// #include< stdio.h> #include< conio.h> // ОПРЕДЕЛЕНИЯ ////////////////////////////////////////// #define CONTROL_8253 0х43 // управляющий регистр 6253 #define CONTROL_WORD 0хЗС // управляющее слово, задающее режим 2, // двоичный подсчет, запись // младший/старший байт #define COUNTERED 0х40 // счетчик 0 #define TIMER_60HZ 0x4DAE // 60Гц #define TIMER_30HZ 0x965C // 30Гц #define TIMER_20HZ 0xE90B // 20Гц #define TIMER_18HZ 0xFFFF // 18.2Гц (стандартная частота) // МАКРОСЫ ////////////////////////////////////////////// #define LOW_BYTE(n) (n & 0x00ff) #define HI_BYTE(n) ((n> > 8) & 0x00ff} // ФУНКЦИИ ////////////////////////////////////////////// void Change Time(unsigned int new count) { // послать управляющее слово, задающее режим 2, двоичный подсчет, // запись младший/старший'байт
_outp(CONTROL_8253, CONTROL_WORD); // теперь запишем младший значащий байт в регистр счетчика _outp(COUNTER_0, LOW_BYTE(new_count)); //я теперь запишем старший байт в регистр счетчика _outp(COUNTER_0, HI_BYTE(new_count)); } // конец Change_Time // ОСНОВНАЯ ПРОГРАММА /////////////////////////////////// main() { // перепрограммирование таймера с частоты 18.2Гц на частоту 60Гц Change_Time (TIMER_60HZ); } // конец, функции main После окончания этой программы системный таймер будет работать слишком быстро для внутренних часов DOS. Для того чтобы это поправить, вы можете: § Перезагрузить компьютер; § Запустить программу еще раз, изменив константу, передаваемую функции Change_Time (), на TIMER_18HZ. Собираем все вместе Итак, мы рассмотрели основы работы с прерываниями, многозадачность и некоторые приемы программирования, которые несколько облегчают реализацию архитектуры компьютерной игры. Причем представленная здесь коллекция приемов программирования далеко не самая полная и лучшая. Мы просто обсудили эти вопросы для того, чтобы вы смогли представить себе различные способы организации игры. Впрочем, вскоре вы, наверняка, придумаете и свои Методы и трюки. Главная цель этой главы состоит в том, чтобы дать вам некую Справную точку и направление для ваших размышлений. Теперь я хочу просуммировать все полученные вами знания и разобрать несколько примеров применения рассмотренных нами методов. После этого для окончательного закрепления материала я приведу еще два примера программ. В этой главе мы узнали о реализации многозадачности на персональных компыотерах с помощью прерываний. Прерывание — это всего-навсего мгновенная передача управления от выполняющейся программы к процедуре обслуживания прерывания (ISR), которая выполняет все действия, относящиеся к событию, вызвавшему прерывание. Прерывания полезны тем, что они позволяют реализовать на персональном компьютере некое подобие многозадачности. Более того, они могут быть использованы для управления задачами, зависящими от времени и событий, контролировать которые главной программе крайне затруднительно именно в силу самой природы этих задач. Обычно процедуры обслуживания прерываний используются для таких вещей как обработка ввода с клавиатуры или передача данных через последовательный порт. Однако мы можем использовать их и для других задач (работа со звуком, система ввода/вывода, обслуживающие функции и так далее). Управление задачами, зависящими от времени и событий, осуществляется за счет подпрограмм обработки тех прерываний, которые происходят по наступлению определенного момента времени или в результате какого-либо события. В этом смысле очень полезным оказывается прерывание системного таймера 0х1С. Мы можем поместить адрес нашего обработчика в таблицу векторов по адресу, соответствующему прерыванию, которое генерируется при каждом системном «тике» (то есть 18.2 раза в секунду). Это гарантирует нам, что независимо от загруженности системы, наша подпрограмма обработки прерываний будет вызываться всегда с неизменной частотой. Кроме того, мы знаем, что системный таймер можно запрограммировать и на другую частоту, например, 20Гц, 30Гц, 60Гц и так далее. Нам это может понадобиться, если мы собираемся использовать прерывание для чего-то, что требует более частого выполнения. И, наконец, мы узнали, как использовать прерывания для изменения глобальных переменных, являющихся, по сути, сообщениями, на которые могут реагировать другие функции той же программы. Это может пригодиться в тех случаях, когда в игре надо выполнять критичные по времени исполнения операции, синхронизацию событий и тому подобные задачи. Кроме того, мы обсудили как построить цикл игры. На самом деле это просто один из методов организации программы и входящих в нее функций таким образом, что все действия выполняются в определенной последовательности и в соответствии с определенной логикой. Мы узнали, что программа игры должна иметь раздел инициализации, за которым следует главный цикл событий. Внутри этого цикла осуществляется стирание графического изображения, получение входных данных от пользователя, выполнение необходимых графических преобразований, формирование и вывод на экран графического изображения. Конечно, порядок действий может быть несколько иным, как, впрочем, и входящие в него элементы, однако нам всегда следует создавать цикл событии, внутри которого эффективно и логически обоснованно делается все, что должно быть сделано. Рассмотрев цикл игры, мы перешли к обсуждению достаточно отвлеченных на первый взгляд вопросов, относящихся к приемам программирования. Мы изучили два тесно связанных между собой типа функций, которые назвали автономными функциями, и функциями ответа. Эти приемы программирования были приведены в качестве иллюстрации, как много действий и процессов в компьютерной игре могут быть организованы независимо друг от друга и иметь свои собственные данные. Компьютерные игры настолько сложны, что нам часто приходится писать функции, работающие без постоянного контроля со стороны главной программы. В этом нам помогают автономные функции. Кроме того мы рассмотрели еще и функции ответа. Эти функции «откликаются» на определенные события соответствующими действиями. Обсуждение всех этих вопросов призвано помочь вам осознать, как писать программы, работающие в «реальном режиме времени». Иными словами, как организовать выполнение нужных действий таким образом, чтобы создать впечатление одновременности происходящего. В компьютерных играх без этого не обойтись. Напоследок мы узнали, как перепрограммировать системные часы, реализованные микросхемой таймера 8253. Мы узнали, что в счетчике 0 хранится 16-разрядное значение, которое рассматривается как делитель поступающего сигнала с частотой 1.19318МГц. Результирующий сигнал используется для генерации «тиков», своего рода пульса, который инициирует прерывание по времени. Это прерывание может быть перехвачено с помощью вектора прерывания 0х1С. В ста процентах игр этот таймер перепрограммируется на более подходящую частоту вроде 30Гц или 60Гц. Таким образом, работа программы синхронизируется по новой базовой частоте. Помимо этого, входящая в состав игры подсистема вывода звуковых эффектов и подсистема ввода/вывода реа лизуются в виде фоновых задач, которые реализованы в виде процедур обслуживания таймерного прерывания 0х1С. Благодаря этому ввод/вывод и музыка исполняются с неизменной скоростью даже тогда, когда сама игра несколько замедляется вследствие выполнения вычислений или сложных графических эффектов. Писать эту главу было непросто, поскольку в ней мне пришлось изложить вам очень много новых вещей. На самом деле, следует иметь в виду, что только опыт поможет вам разобраться с миллионами тонкостей, которые приходится учитывать при программировании компьютерных игр. Тем не менее, перед вами уже открылись новые возможности. Сейчас вы готовы мыслить по-новому и это Уже неплохо. Как я и обещал, сейчас мы напишем еще несколько подпрограмм обслуживания прерываний и сделаем с их помощью несколько потрясающих вещей. Пример обработчика прерывания № 1 - Там полно звезд... Чтобы продемонстрировать вам, насколько полезными могут оказаться многозадачность и прерывания, я написал в виде обработчика прерывания программу, которая рисует трехмерное звездное небо. Как вам уже известно, при каждом приращении счетчика внутреннего таймера, генерируется прерывание. При помощи вектора 0х1С я сопоставил этому прерыванию свою процедуру обслуживания, которая и создает трехмерное звездное небо. Поскольку обращение к моему обработчику происходит 18.2 раза в секунду, значит и картина звездного неба обновляется с этой же частотой. Нечто подобное мы могли бы использовать при написании игры, работающей на одном экране (игры типа «перестреляй их всех»). Наше звездное небо будет изменяться независимо от того, что будет происходить на переднем плане. Обратите внимание на то, что процедура обслуживания прерывания сделана автономной. Это означает, что она инициализирует свои данные при первом обращении к ней (в этот момент она создает базу данных с информацией о звездах), а при последующих вызовах просто видоизменяет картинку. И напоследок еще одно маленькое замечание: завершая программу, вы можете оставить ее резидентной в памяти, нажав клавишу Е. Сделав это, вы увидите, что звездное небо присутствует в строке приглашения DOS, что выглядит несколько странно! Причина такого поведения программы кроется в том, что когда вы завершаете ее нажатием клавиши Е, она не восстанавливает прежний обработчик прерывания. Компьютер продолжает вызывать по прерыванию от таймера наш обработчик. Вы наверняка даже и представить себе не могли, что это сработает! И, тем не менее, завершаясь, программа оставляет в оперативной памяти большую часть своего кода неизменным, в результате чего обработчику прерывания удается пережить окончание работы породившей его программы. Если вы попытаетесь запустить еще какую-нибудь программу, компьютер, скорее всего, «зависнет». Поэтому для написания настоящих резидентных программ такой метод применять не стоит. (На самом деле для этих целей предназначена специальная функция DOS, которая называется dos keep, но сейчас мы не будем подробно рассматривать резидентные программы. Мы просто случайно создали одну из них). Если система «зависнет», вам придется перезагрузиться. Текст программы, изображающей трехмерное звездное небо, представлен в Листинге 12.6.
|