В предыдущих статьях данного цикла* рассказывалось о том, как работать со спрайтами, однако для создания компьютерной игры этого недостаточно. В самом деле, должна же она чем-то отличаться от мультфильма! Теперь настал черед освоить мышь и клавиатуру. Элементарные процедуры работы с клавиатурой содержатся в стандартном модуле crt, так что лучше начнем с мыши. Существует множество разных типов этих устройств, и значит, нужно унифицировать работу с ними. Поэтому прикладная программа должна взаимодействовать не напрямую с мышью, а с ее драйвером, и если вы работаете в среде DOS, то проследите, чтобы загружался соответствующий драйвер, например mouse.com или аналогичный. В DOS-сессии Windows такой процедуры не требуется, там драйвер устанавливается автоматически.
Драйвер мыши поддерживает более десятка функций, доступных через прерывание $33. Мы же рассмотрим здесь только необходимый минимум.
InitMouse - функция, инициализирующая драйвер мыши. Она возвращает значение TRUE, если драйвер мыши установлен, и FALSE - если его нет. Следовательно, любая программа перед работой с мышью должна с помощью этой функции проверить ее наличие.
GetMouse(var x,y: word) - основная функция получения текущего состояния мыши. Она возвращает слово, два младших разряда которого (в трехкнопочных мышах, если имеется соответствующий драйвер, — три) сигнализируют о положении кнопок. Разряд, установленный в «1», означает нажатую кнопку, а в «0» — отпущенную. Первый разряд соответствует левой кнопке, второй -– правой, а третий - средней, если она есть. В переменных X и Y функция возвращает текущие координаты курсора мыши. Направления осей совпадают с имеющимися на экране, т. е. при движении вниз координата Y увеличивается.
SetMouse(x,y: word) - процедура, помещающая курсор мыши в точку с координатами X и Y.
SetMouseRange(x1,y1,x2,y2: word) - процедура, устанавливающая границы изменения координат курсора мыши от X1 до X2 по горизонтальной оси и от Y1 до Y2 - по вертикальной, причем второе значение должно быть больше первого.
Модуль, содержащий перечисленные функции, приведен в листинге 1.
Во времена первых ПК и дисплеев CGA число строк растра на экране было одинаковым во всех режимах и равнялось 200. Высота символа составляла 8 линий растра и, таким образом, на экране помещалось 25 строк текста. По горизонтали в графических режимах могло быть либо 320, либо 640 точек, а в текстовых - 40 или 80 символов. Ширина символа при этом также равнялась 8 точкам растра, так что можно было считать, что максимальное разрешение экрана составляло 640x200 точек, а «половинное» - 320x200. Разработчики первого драйвера для мыши решили, что одинаковым числовым значениям координат курсора должно соответствовать одно и то же его положение на экране. Таким образом, получилось, что нижнему правому углу соответствуют величины в районе x = 640 и y = 200, а середине экрана - x = 320 и y = 100. В текстовом режиме для получения номера строки и столбца возвращаемые драйвером координаты полагалось делить на восемь, а в графических режимах с «половинным» разрешением горизонтальную координату - на два. С тех пор графический режим 640x200 точек безвозвратно канул в прошлое, в текстовом режиме знакоместо стало иметь размер 9x16, но возвращаемый драйвером диапазон значений сохранился прежним. Поэтому, если не пользоваться функцией SetMouseRange, то пределы изменения горизонтальной координаты курсора будут равны 640, что не очень удобно.
Чтобы использовать мышь в нашей программе, нужно включить ссылку на модуль mouse в директиве uses, а также описать дополнительную переменную для хранения состояния кнопок мыши:
MouseStatus: word; {состояние кнопок мыши}
Фрагмент текста основной программы с внесенными в него изменениями показан в листинге 2. Прежде всего необходимо выяснить, подключена ли к компьютеру мышь и загружен ли ее драйвер. Если это не сделано, то программа завершается с выдачей сообщения на экран. После изменения видеорежима (обязательно после) устанавливаем границы движения мыши. Они, очевидно, должны равняться диапазону перемещения управляемого мышью объекта по экрану, т. е. разнице между размерами экрана и спрайта. Если планируется перемещать курсор, то целесообразнее задавать полные размеры экрана, чтобы можно было указать любую точку. В этом случае, скорее всего, придется подумать об отсечении изображения краями экрана. Далее помещаем курсор в центр экрана.
Теперь сделаем так, чтобы мышь управляла каким-нибудь из спрайтов, например первым, и чтобы сохранить анимацию, не будем исключать вызов процедуры CalcSpritePosition., а просто принудительно переопределим его координаты в соответствии с параметрами, возвращенными функцией GetMouseStatus. Затем проанализируем состояние кнопок, и для каждой из них назначим соответствующее сообщение.
Итак, запустите программу и посмотрите, как она отреагирует на перемещение и нажатие кнопок мыши.
Функции, поддерживаемые стандартным драйвером мыши, довольно разнообразны, среди них есть разрешение и запрещение отображения, а также изменение формы курсора мыши, настройка ее чувствительности и требование изменения координат, произошедшего с момента предыдущего запроса. Первые три возможности мы сознательно пропустили, поскольку в играх приняты красочные курсоры, тогда как драйвер допускает лишь черно-белый. Поэтому программе следует самой запрашивать координаты и рисовать курсор, не надеясь на то, что это сделает стандартный драйвер. Более того, как правило, в режимах с более высоким разрешением стандартный драйвер не способен отображать курсор на экране. Без такой функции, как настройка чувствительности, вообще можно обойтись. Запрос изменения координат — функция, которая бывает полезна в играх от первого лица, где пределы изменения координат при движении по большому лабиринту практически не ограничены. Однако ее не сложно реализовать с помощью пары GetMouse/ SetMouse, возвращая указатель в центр экрана после каждого запроса координат. Еще одно из соображений в пользу исключения этой функции из числа обязательных - проблемы с переносом на другую платформу, поскольку в ОС, отличных от DOS, зачастую отсутствуют ее прямые аналоги.
Если же вам по каким-то причинам все же понадобится ввести дополнительные функции, то посмотрите таблицу, где приведены некоторые из них.
* Cм. «Мир ПК» за 2001 г. — № 7, с. 87; № 10, с. 99; № 11, с. 100; № 12, с. 98; за 2002 г. — № 1, с. 117; № 2, с. 107; № 3, с. 100; № 5, с. 108; №6, с. 103.