Технические аспекты сотворения мира. Часть 3

Posted by Anuriel on декабря 30, 2000 - 00:00

Использование клавиатуры, мыши и джойстика

Рассматривая решения различных проблем, возникающих в процессе разработки компьютерных игр, обязательно следует уделить внимание реализации управления. Не секрет, что неудобное управление способно загубить любую игру, какой бы интересной и красивой она ни была. Стандартные модули Turbo Pascal 7.0 предоставляют очень скудные возможности реализации управления в играх. В этой части статьи будут рассмотрены подпрограммы, позволяющие не только использовать мышь и джойстик, поддержка которых в Turbo Pascal 7.0 отсутствует вообще, но также значительно расширить возможности использования клавиатуры.

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

uses Dos;
var pInterrupt09hVector: Pointer;
		bKeys: array[1..127] of Byte;
p
rocedure KeyboardDriver; interrupt; assembler;
	asm
		mov ah,1
		
in al,60h
		test al,80h
		jz @1
		xor ax,180h
	@1:
		mov bl,al
		mov bh,0
		mov [(offset bKeys)-1+bx],ah
	mov dx,61h
		in al,dx
		mov ah,al
		or al,80h
	out dx,al
		xchg al,ah
		out dx,al
		mov al,20h
<
tab>	out 20h,al
	end;
procedure InitializeKeyboardDriver;
	var b1: Byte;<
r>
	begin
		for b1:=1 to 127 do bKeys[b1]:=0;
		GetIntVec(9, pInterr
upt09hVector);
		SetIntVec(9, @KeyboardDriver)
	end;
procedure Uninitiali
zeKeyboardDriver;
	begin
		SetIntVec(9, pInterrupt09hVector)
	end;

Процедура KeyboardDriver является "драйвером", который вызывается всякий раз, когда на клавиатуре нажимается или отжимается какая-нибудь клавиша. Эта процедура определяет скан-код клавиши и отображает полученную информацию в массиве bKeys. Для запуска "драйвера" необходимо вызвать процедуру InitializeKeyboard-Driver. 
Для завершения работы "драйвера" предназначена процедура UninitializeKey-boardDriver. Методика использования рассмотренных подпрограмм такова: сначала вызывается InitializeKeyboardDriver; после этого в любой момент времени можно определять, какие клавиши нажаты, а какие нет; когда необходимость в определении нажатых клавиш отпадет или же программа должна будет завершить свою работу, вызывается UninitializeKeyboardDriver. Статус клавиш (нажата/отжата) определяется следующим образом: если значение bKeys[bScanCode] равно единице, то клавиша со скан-кодом bScanCode нажата, если нулю - то отжата. 

Каждая клавиша имеет свой собственный скан-код. Для того чтобы определить, какой код соответствует некоторой клавише, можно воспользоваться справочниками или же написать небольшую программу, отображающую скан-коды нажатых клавиш. Следует отметить одну особенность использования приведенных выше подпрограмм. 

Если в процессе работы программы необходимо вызвать такие функции и процедуры, как KeyPressed, ReadKey, Read и Readln, то следует либо разработать их аналоги, использующие возможности, предоставляемые "драйвером", либо отключить "драйвер" процедурой UninitializeKeyboard-Driver, а затем, когда отработают стандартные подпрограммы Pascal'я, опять вызвать InitializeKeyboardDriver. Завершая обсуждение использования клавиатуры, рассмотрим еще несколько небольших процедур, которые могут пригодиться при разработке игр или другого программного обеспечения.

procedure LockKeyboard; assembler;
	asm
		in al,21h
		or al,2
<
n>		out 21h,al
	end;
procedure UnlockKeyboard; assembler;
	asm
<
tab>	in al,21h
		and al,253
		out 21h,al
	end;
procedure
 ClearKeyboardBuffer; assembler;
	asm
		mov ax,0C00h
		int 21h
	end;
procedure SwitchWindowsKeysOn; assembler;
	asm
		mov ax,1681
h
		int 2Fh
	end;
procedure SwitchWindowsKeysOff; assembler;
	as
m
		mov ax,1682h
		int 2Fh
	end;

Процедура LockKeyboard блокирует клавиатуру, не позволяя фиксировать нажатия/отжатия клавиш. UnlockKeyboard выполняет противоположное действие. Процедура ClearKeyboardBuffer очищает буфер клавиатуры, в котором сохраняются необработанные нажатия клавиш. Она предназначена для очистки буфера перед запросом ввода данных с клавиатуры. 
Процедуры SwitchWindowsKeysOn и SwitchWindows-KeysOff соответственно разрешают или запрещают прерывание выполнения программы, выполняемой в эмуляции DOS, посредством нажатия специальных Windows-клавиш. Вообще-то, назначение этих двух подпрограмм несколько иное, но они подойдут и для использования так, как было сказано. 

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

const LeftButton=1; RightButton=2; CenterButton=4;
function MouseSupportPresence: Boolean; asse
mbler;
	asm
		xor ax,ax
		int 33h
		cmp ax,0FFFFh
		mov al,0
		jne @1
		inc ax
	@1:
	end;
procedure ShowMousePointer; assembler;
	asm
		mov ax,1
		int 33h<
r>
	end;
procedure HideMousePointer; assembler;
	asm
		mov ax,2
<
n>		int 33h
	end;
function MouseButtonsStatus: Word; assembler;
	asm<
r>
		mov ax,3
		int 33h
		mov ax,bx
	end;
procedur
e GetMousePointerPositions(var wX, wY: Word); assembler;
	asm
		mov ax,3
		int 33h
		push ds
		lds si,wX
		mov [si],cx
	lds si,wY
		mov [si],dx
		pop ds
	end;
procedure Set
MousePointerPosition(wX, wY: Word); assembler;
	asm
		mov ax,4
		
mov cx,wX
		mov dx,wY
		int 33h
	end;

Первым шагом, который следует сделать перед тем, как работать с мышью, является проверка присутствия поддержки этого устройства. Функция MouseSupportPresence кроме определения наличия поддержки проводит инициализацию мыши, что вызывает перемещение указателя мыши в центр экрана, причем указатель делается невидимым. 
Процедуры ShowMousePointer и HideMousePointer соответственно показывают и прячут указатель мыши. После инициализации следует вызвать первую процедуру. Если необходимо осуществить вывод на экран какой-либо информации, то указатель следует предварительно спрятать, а затем показать вновь. Эта последовательность действий необходима для того, чтобы, если вывод осуществляется в ту область, где в данный момент находится указатель мыши, не происходили коллизии выводимого изображения и изображения указателя. Для определения того, какие клавиши мыши нажаты, предназначена функция MouseButtonsStatus. 

В возвращаемом ею значении нулевой бит показывает, нажата ли левая клавиша (1 - нажата, 0 - не нажата). Первый бит закреплен за правой, а второй - за центральной клавишами мыши. Если, к примеру, необходимо определить, нажата ли правая клавиша, то для этого следует проанализировать значение выражения (MouseButtonsStatus and RightButton). Если оно равно нулю, то клавиша не нажата, если оно больше нуля, то клавиша нажата. 

Аналогично проверяются другие клавиши. Последние две процедуры определяют (GetMousePointerPosition) или устанавливают (SetMousePointerPosition) текущее положение указателя мыши, которое сохраняется в переменных wX и wY. В графическом режиме положение указателя задается с шагом равном 1, в текстовом - равном 8. В завершение этой части статьи рассмотрим использование джойстика. Для работы с этим устройством вполне достаточно двух подпрограмм, которые позволяют получать данные от двух джойстиков сразу.

const A1Button=16; A2Button=32; B1Button=64; B2Button=128;
function JoysticksButtonsStatus: Byt
e; assembler;
	asm
		mov ah,84h
		xor dx,dx
		int 15
h
	end;
procedure GetJoysticksCoordinates(var wAX, wAY, wBX, wBY: Word); assembler;
	asm
		mov ah,84h
		mov dx,1
		int 15h
		
push ds
		lds si,wAX
		mov [si],ax
		lds si,wAY
	mov [si],bx
		lds si,wBX
		mov [si],cx
		lds si,wBY
	mov [si],dx
		pop ds
	end;

Первая подпрограмма - JoysticksButtonsStatus - определяет, какие клавиши нажаты. 
Для этого анализируется выражение (JoysticksButtonsStatus and xyButton), где "x" задает джойстик ("A" или "B" ), а "y" - клавишу выбранного джойстика ("1" или "2"). В отличие от того, как это производилось с определением статуса клавиш мыши, для клавиш джойстика нулевое значение выражения означает, что клавиша нажата. Другая подпрограмма - GetJoysticksCoordinates - возвращает координаты джойстиков. Переменные wAX и wAY сохраняют координаты джойстика "A", а wBX и wBY - джойстика "B". 

Несколько слов по поводу того, как определить наличие джойстиков. Для этой цели следует вызвать процедуру GetJoysticksCoordinates, и если все переменные (wAX, wAY, wBX и wBY) равны нулю, значит джойстики не подключены. Итак, в этой части были рассмотрены вопросы использования различных устройств управления компьютерными играми. Информации, представленной здесь, а также в предыдущих частях статьи, достаточно для того, чтобы приступить к программной реализации игры. 

Когда игра будет практически готова, в нее можно будет добавить воспроизведение звуков через Sound Blaster. Как это сделать - тема следующей части статьи. Продолжение следует

Сергей Иванчегло

№ 12
Яндекс.Метрика