Как написать игру для ZX Spectrum 1994 г.

Блок взаимодействия с играющим - управление спрайтами с помощью клавиатуры, джойстика.


5. БЛОК ВЗАИМОДЕЙСТВИЯ С ИГРАЮЩИМ

После того, как мы научились создавать спрайты самыми разными способами, настало время решить еще одну очень важную задачу - подчинить их своей воле и заставить двигаться по экрану. Вы уже хорошо знаете, что управлять движением объектов можно с помощью клавиатуры (keyboard) или используя различные типы джойстиков (Kempston, Sinclair, Cursor). Какой из этих способов выбрать, зависит в основном от сюжета игры и ваших пристрастий. При желании можно пользоваться тем и другим одновременно.

Познакомимся теперь со всеми перечисленными методами управления спрайтами и их особенностями с точки зрения программирования.

Управление спрайтами с помощью клавиатуры

Рассмотрим программу, формирующую изображения вертолета и позволяющую это изображение перемещать по экрану (см. рис. 3.3).

Программа 24. ВЕРТОЛЕТ.

10 BORDER 1: PAPER 1: INK 6 20 CLS

30 FOR N=0 TO 71 40 READ S

50 POKE USR "A"+N,S 60 NEXT N

70 DATA 0,0.135,0,120,127,15,39 80 DATA 0,0,255,2,127,201,201,255 90 DATA 0,0,255,0,192,112,24,12 100 DATA 3,1,0,0,0,0,0,0 110 DATA 255,255,127,63,4,255,0,0 120 DATA 254,254,252,248,34,252,0,0 130 DATA 0,0,32,0,120,127,15,135 140 DATA 0,0,7,2,127,201,201,255 150 DATA 0,0,0,0,192,112,24,12 200 REM __________

210 LET X=10: LET Y=10: LET X1=X: LET Y1=Y 220 LET W=0

230 IF INKEY$="0" THEN LET X=X-1: GO TO 300 235 IF INKEY$="c" THEN LET X=X-1: GO TO 300 240 IF INKEY$="P" THEN LET X=X+1: GO TO 300 245 IF INKEY$="p" THEN LET X=X+1: GO TO 300 250 IF INKEY$="Q" THEN LET Y=Y-1: GO TO 300 255 IF INKEY$="q" THEN LET Y=Y-1: GO TO 300 260 IF INKEY$="A" THEN LET Y=Y+1: GO TO 300 265 IF INKEY$="a" THEN LET Y=Y+1: GO TO 300 270 GO TO 320 300 PRINT AT Y1,X1;"ППП" 310 PRINT AT Y1+1,X1;"ППП"

320 IF W<3 THEN PRINT AT Y,X;"ABC"; AT Y+1.X;"DE£":GO TO 340

330 PRINT AT Y,X;"GHI";AT Y+1,X;"DEF"

340 LET W=W+1: IF W=5 THEN LET W=0

350 LET X1=X: LET Y1=Y

360 BEEP .002,0

370 GO TO 230

10... 150 - работа этой части программы должна быть вам понятна, поэтому мы лишь отметим, что здесь используются два спрайта с изображением вертолета. Несколько спрайтов для одного и того же объекта рисуются всякий раз, когда нужно создать эффект движения - как в мультфильмах. В нашем случае у вертолета должен вращаться винт, поэтому спрайты отличаются именно его положением. Каждая картинка состоит из шести полей. Для первой использованы графические символы, соответствующие клавишам А, В, С, D, Е и F, а для другой - G, Н, I, D, Е и F. Нижняя часть вертолета одинакова в обоих спрайтах, поэтому три последних символа повторяются. Всего использовано 9 символов, следовательно, количество вводимых в программу кодов должно быть равно 9x8 = 72;

210 - задание начальных координат вертолета. Координаты X и Y будем называть новыми, а X1 и Y1 - старыми. До начала движения новые и старые координаты совпадают;

220 - инициализация переменной W, которая в дальнейшем будет указывать компьютеру, какой из двух спрайтов вертолета выводить на экран.

Управляют положением вертолета на экране две части программы. Первая (строки 230...265) анализирует, какая клавиша нажата, а вторая (строки 300...350) строит изображение вертолета в новом месте экрана; 230...260 - в предыдущих главах мы уже упоминали функцию INKEY$, которая возвращает символ, соответствующий клавише, нажатой в момент ее выполнения. Для перемещения вертолета задействуем клавиши: О - влево, Р - вправо, Q - вверх и А вниз. Но, как вы знаете, с клавиатуры можно вводить и прописные, и строчные буквы. Все зависит от того, какой режим установлен клавишей Caps Lock. Поэтому в блоке опроса клавиатуры нужно предусмотреть все возможности и проверять как большие, так и маленькие буквы. Предположим, что нажата клавиша Q, тогда в строке 230 условие "Q" = "О" не выполняется. Также не выполняется и условие "Q" = "о". В результате программа переходит к строке 240. Но и здесь условия "Q" = "Р" и "Q" = "р" не выполняются, поэтому проверка продолжается. Так программа доходит до строки 250, где условие "Q" = "О" истинно. В этом случае начинают выполняться операторы, стоящие после THEN данной строки, то есть из значения координаты Y вычитается единица (на экране вертолет должен подняться вверх) и программа переходит к строке 300. Возникает вопрос: что будет, если нажать какую-либо клавишу, отличную от перечисленных? Ответ можно найти в строке, следующей за блоком опроса клавиатуры;

270 - после блока условий в большинстве случаев ставится строка с безусловным переходом, которая после каждого «неправильного» нажатия возвращает управление на начало блока. Это продолжается до тех пор, пока не будет нажата одна из разрешенных клавиш. Другой вариант (именно так мы поступили в нашей программе) передать управление в ту часть программы, которая выводит на экран изображение вертолета в соответствии с текущими координатами, то есть на строку 320;

300, 310 - но вот нажата одна из нужных букв, то есть вертолету предписано куда-то передвинуться, и операторы строк 300 и 310 стирают изображение на старом месте (координаты Х1 и Y1);

320, 330 - эти строки выводят на экран изображение в место, заданное новыми координатами. Причем в зависимости от значения переменной W на экран помещается тот или иной спрайт, что создает впечатление вращения винта;

340 - переменная W увеличивается на единицу, и если она становится равна 5, то обнуляется. Таким образом, если W равна О, 1 или 2, то вертолет изображается одним спрайтом, а при W, равной 3, 4 или 5 - другим. Спрайты сменяются через три цикла для того, чтобы вращение винта было не чересчур быстрым;

350 - новые координаты запоминаются и становятся для очередного цикла движений старыми;

360 -- звуковой сигнал, имитирующий стрекотание вертолета;

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

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

Забегая вперед, расскажем об одной замечательной возможности, позволяющей заметно уменьшить блок опроса клавиатуры и, соответственно, увеличить скорость его работы. Проверять строчные и прописные буквы нужно только в том случае, если неизвестно заранее, какой режим клавиатуры установлен до запуска программы, или если он мог измениться во время работы (например, в операторе INPUT). Однако режим ввода символов можно изменить не только с клавиатуры, но и из программы. Не вдаваясь пока в подробности, скажем только, что установить режим курсора [С] (заглавные буквы) можно, включив в программу оператор

РОКЕ 23658,8

вернуться к курсору [L] позволит оператор РОКЕ 23658,0

Вставьте в программу ВЕРТОЛЕТ строку 225 РОКЕ 23658,8

и тогда строки 235, 245, 255 и 265 можно смело убрать.

Управление спрайтами с помощью джойстика

Объектами игры часто удобнее управлять не с клавиатуры, а с помощью джойстика, поэтому посмотрим, как это можно сделать. Если для опроса клавиатуры мы пользовались функцией INKEY$, то узнать, в какую сторону повернута ручка Kempston-джойстика можно только с помощью функции IN. Эта функция возвращает числовое значение из порта, адрес которого записан в качестве ее аргумента. Возможно, вы еще не знаете, что собой представляют порты в компьютере, поэтому попробуем объяснить, что это такое.

В нашем мире порты существуют для сообщения с другими государствами, а для островных империй (вроде компьютера) это единственное средство связи с внешним миром. Но у маленького Speccy портов гораздо больше, чем у самой великой державы - целых 65536. Правда, практическое применение имеют далеко не все из них, а остальные простаивают без дела. Любой ввод и вывод информации (кроме вывода на рабочий экран) происходит именно через порты. С ними связаны и клавиатура, и джойстик, и магнитофон, и принтер, и динамик, причем каждому устройству соответствует порт с определенным адресом (не путайте с адресами ячеек памяти). Интересующий нас в данный момент джойстик типа , Kempston подключен к порту с адресом 31. Таким образом, узнать направление поворота ручки джойстика можно с помощью оператора LET joy=IN 31

Зная коды, соответствующие различным направлениям наклона джойстика, нетрудно написать и блок управления.

Казалось бы, все очень просто, однако есть одно «но»: компьютеры, изготовленные в России, практически все «страдают» неполной совместимостью с фирменным Speccy. B частности, значения, считываемые из порта 31, различны для разных моделей ZX Spectrum. На рис. 5.1 приведены два наиболее распространенных варианта кодов джойстика. Первый вариант (рис. 5.1, а, б)

характерен тем, что в нейтральном положении ручки из порта 31 считывается ноль (это соответствует фирменному Speccy). B другом варианте (рис. 5.1, в, г) в нейтральном положении считывается число 224.

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

10 PRINT AT 0,0;IN 31;" " 20 GO TO 10

Запустите ее оператором RUN и, поворачивая ручку джойстика в разные стороны, выпишите числа, которые будут появляться на экране.

Теперь давайте рассмотрим конкретный пример использования функции IN. Программу САМОЛЕТ уже вполне можно назвать мини-игрой, в которой имеется простейший пейзаж, состоящий из неба и земли,

Рис. 5.2. Игровое пространство игры САМОЛЕТ. самолет противника, передвигающийся по экрану случайным образом, и объект управления - прицел вашего самолета (рис. 5.2). Если самолет противника попал в прицел и вы успели нажать кнопку Огонь, то происходит взрыв, а самолет исчезает. Таков замысел этой игры.

Программа 25. САМОЛЕТ.

10 BORDER 0: PAPER 1: INK 0: CLS 20 FOR N=0 TO 55 30 READ S: POKE USR "A"+N,S 40 NEXT N

50 DATA 0,0,0,0,255,0,0,0

55 DATA 0,0,0,0,255,255,6,4

60 DATA 60,126,255,255,255,255,126,60

65 DATA 0,0,0,0,255,255,96,32 70 DATA 0,0,0,0,255,0,0,0 75 DATA 0,0,0,24,24,24,24,24 80 DATA 40,21,102,153,90,165,44,16

100 REM -------------------

110 LET XS=11: LET YS=10: LET XS1=XS: LET YS1=YS

120 FOR N=15 TO 21: PRINT AT N,0; PAPER 4;TAB 31;" ": NEXT N

140 REM _________

150 LET PRX=2*RND-1 160 LET PRY=2*RND-1 170 LET DLC=INT (RND*8+2) 180 LET CI=0

200 REM ----------

210 LET CI=CI+1

220 IF XS<2 THEN LET XS=XS+1: GO TO 150 230 IF XS>25 THEN LET XS=XS-1: GO TO 150 240 IF YS>19 THEN LET YS=YS-1: GO TO 150 250 IF YS<3 THEN LET YS=YS+1: GO TO 150 260 IF CI>=DLC THEN GO TO 150 270 LET XS=XS+PRX: LET XSN=INT XS 280 LET YS=YS+PRY: LET YSN=INT YS 290 LET JO=IN 31

300 IF JO=226 OR JO=242 THEN LET XS=XS+1: GO TO 400

310 IF JO=225 OR JO=241 THEN LET XS=XS-1: GO TO 400

320 IF JO=232 OR JO=248 THEN LET YS=YS-1: GO TO 400

330 IF JO=228 OR JO=244 THEN LET YS=YS+1: GO TO 400

340 IF JO=240 THEN LET FIRE=1: GO TO 400

350 IF JO=224 THEN LET FIRE=0: GO TO 400

360 IF JO=234 OR JO=250 THEN LET XS=XS+1: LET YS=YS-1:GO TO 400

370 IF JO=233 OR JO=249 THEN LET XS=XS-1: LET YS=YS-1:GO TO 400

380 IF JO=229 OR JO=245 THEN LET XS=XS-1: LET YS=YS+1:GO TO 400

390 IF JO=230 OR JO=246 THEN LET XS=XS+1: LET YS=YS+1

400 REM ________

410 PRINT AT YS1,XS1; PAPER 8;"ППППП";AT YS1-1,XS1+2;" "

420 PRINT AT YSN,XSN; PAPER 8; INK 0;"ABCDE";AT YSN-1,XSN+2; INK 0;"F"

430 LET XS1=XSN: LET YS1=YSN

440 INK 0

450 PLOT 120,91: DRAW 7,0 460 PLOT 136,91: DRAW 8,0 470 PLOT 132,103: DRAW 0,-7 480 PLOT 132,79: DRAW 0,8

490 IF FIRE=0 THEN PRINT AT 10,16; PAPER 1;" ": GO TO 200 500 PRINT AT 10,16; INK 2; PAPER 1;"G"

510 IF YSN=10 AND XSN>=12 AND XSN<=16 THEN GO SUB 1000: CLS: GO TO 100 520 GO TO 210 1000 REM -- WZRYW -1010 PRINT AT YSN-1,XSN+2; PAPER 8;" " 1020 BORDER 4: INPUT "" 1030 FOR I=1 TO 3

1040 PRINT AT YSN,XSN; INK 2;"ABCDE" 1050 PAUSE 3 1060 FOR N=0 TO 7

1070 PRINT AT YSN,XSN; INK N;"GGGGG"

1080 LET W2=0: LET BORD=INT (RND*8): IF RND<.5 THEN LET WZ=16

1090 OUT 254,WZ+BORD

1100 NEXT N

1110 NEXT I

1120 BORDER 0

1130 RETURN

Для удобства разбора программы ее функциональные части, как и во многих предыдущих, отделены друг от друга операторами REM.

10...80 - формирование спрайта самолета, состоящего из семи полей 8x8 точек. Этот фрагмент аналогичен соответствующим частям в программах 7 и 8, поэтому повторяться не будем;

110 - установка начальных координат изображения самолета на экране. Переменные XS и YS задают новые координаты самолета, a XS1 и YS1 - старые;

120 - нижняя часть экрана окрашивается в зеленый цвет, имитируя землю. Синий цвет неба задается в строке 10;

150, 160 - здесь формируются приращения координат самолета по горизонтали и вертикали при изменении его положения в пространстве на один шаг. Эти числа могут быть как положительными, так и отрицательными в диапазоне от -1 до +1, что позволяет самолету перемещаться во всех четырех направлениях;

170 - устанавливается длина пролета самолета до момента изменения направления, измеряемая в шагах (длина должна быть целым числом). Таким образом, в строках 150... 170 задается случайная траектория полета самолета по экрану;

210 - задается переменная CI - счетчик числа шагов;

220...250 - в этой группе строк проверяются текущие координаты самолета SX и SY, чтобы он не ушел за пределы игрового поля. Числа 2, 25, 19 и 3 взяты с учетом конфигурации самолета. Если одна из его координат вышла за пределы, то соответствующая строка увеличивает (уменьшает) нужную координату на единицу, и программа возвращается на строку 150 - к вычислению новых приращений и длины пролета;

260 - число уже выполненных шагов CI сравнивается с заданной длиной пролета DLC;

270, 280 - текущие координаты изображения самолета получают приращение, а затем округляются до меньшего целого - в строке 510 эти координаты (переменные XSN и YSN) будут использованы для проверки попадания вашего снаряда в самолет противника;

290 - переменной JO присваивается значение из порта джойстика;

300...390 - блок управления прицелом содержит 10 условных операторов. Предположим, что ручка отклонена вправо (на «восток»), тогда функция IN 31 возвратит код 225, который присвоится переменной JO. В строках 300...390 анализируется значение этой переменной и в зависимости от результата будут изменяться значения координат самолета. Условие JO = 225 проверяется в строке 310, следовательно, координата XS уменьшится на единицу, самолет отклонится влево, а прицел как бы передвинется на один шаг вправо. Аналогично действуют и операторы, управляющие перемещением прицела в другие стороны;

410 - стирается предыдущее изображение самолета. Включение оператора PAPER 8. позволяет не заботиться об изменении цвета фона при переходе самолета с синей части экрана на зеленую и обратно;

420 - изображение самолета появляется на новом месте с новыми координатами;

430 - новые координаты запоминаются в переменных XS1 и YS1, то есть становятся старыми;

440...480 - черным цветом рисуется перекрестье прицела;

490 - если кнопка Огонь не нажата, то в центре изображения прицела ставится пробел;

500 - при нажатой кнопке Огонь в перекрестии прицела появляется красный огонек;

510 - сравниваются координаты изображений прицела и самолета. Если они совпадают хотя бы в одной точке, программа с помощью оператора GO SUB 1000 обращается к подпрограмме WZRYU (взрыв). Затем экран очищается и начинается следующая игра;

520 - если ни одна из координат самолета не попадает в перекрестье прицела, программа переходит на строку 210, где счетчик шагов увеличивается на единицу, и можно вновь изменить положение ручки джойстика;

1000... 1130 - здесь располагается подпрограмма, имитирующая на экране взрыв;

1010 - в этой строке с экрана стирается хвост самолета, так как после взрыва он должен отвалиться;

1020 - оператор INPUT "" можно использовать, когда требуется просто очистить служебное окно без ввода данных. При этом цвет PAPER в нижних строках экрана станет таким же, как и цвет бордюра. Таким образом, в этой строке программы служебное окно закрашивается зеленым цветом;

1030 - начало цикла по переменной I. Цикл нужен для того, чтобы воспроизвести взрыв трижды;

1040 - окрашивание изображения самолета красным цветом;

1050 - небольшая пауза для фиксации изображения горящего самолета;

1060 - начало цикла по переменной N, которая управляет цветом осколков самолета;

1070 - вывод изображения осколков самолета;

1080 - переменная WZ служит для получения звука взрыва и может принимать значения 0 или 16, а переменная BORD задает случайный цвет бордюра;

1090 - оператор OUT производит действие, обратное функции IN, то есть записывает в указанный порт какое-то число. Порт с адресом 254 - один из наиболее важных в ZX Spectrum. K нему подключены клавиатура, магнитофон и динамик. Он же может управлять и цветом бордюра, если в него записать числа от 0 до 7. Если в него посылать числа 0 и 16, достаточно быстро чередуя их, то получится какой-нибудь звук. Сумма кодов бордюра и звука объединит оба эффекта и мы получим переливающийся всеми цветами бордюр в сопровождении треска из динамика;

1100...1110 - окончания циклов;

1120 - бордюру возвращается первоначальный черный цвет;

1130 - выход из подпрограммы.

Не правда ли, глядя на огромный размер блока управления, хочется как-то сократить и упростить его? К счастью, это вполне осуществимо. Но прежде, чем узнать, как это делается, необходимо понять, откуда берутся указанные числа. Ведь на первый взгляд в их расположении нет никакой видимой закономерности. Однако закономерность, очевидно, все же должна быть, и чтобы ее обнаружить, необходимо представить полученные коды в двоичном виде. Мы уже встречались с такими числами, когда кодировали изображение «гномика». Но тогда двоичные числа мы переводили в привычный десятичный формат, а теперь нам нужно поступить наоборот. О том, как это сделать, будет сказано чуть ниже, а пока посмотрим на коды джойстика в двоичном представлении:

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

Теперь посмотрим, как можно перевести числа из десятичной системы счисления в двоичную и «выловить» отдельные биты. К сожалению, в Spectrum-Бейсике не существует специальной функции, производящей такой перевод, поэтому придется написать небольшую программку:

Программа 26. Перевод чисел из десятичной системы счисления в двоичную. 10 DIM J(5) 20 LET JOY=IN 31 30 FOR N=1 TO 5 40 LET JOY=JOY/2

50 LET J(N)=(JOY<>INT JOY): LET JOY=INT JOY

60 NEXT N

70 PRINT AT 0,0;

80 FOR N=5 TO 1 STEP -1

90 PRINT J(N);

100 NEXT N

110 GO TO 20

Эта программка выполняет следующие действия:

10 - определение массива с размерностью, равной количеству интересующих нас битов;

20 - чтение числа из порта джойстика;

30...60 - в цикле проверяются отдельные биты, начиная с младшего и заносятся в элементы массива J (5). Если после деления числа на 2 результат получается дробным (то есть делимое было нечетным), то это говорит о том, что младший бит установлен. В этом случае нужно отбросить дробную часть результата, что и делает функция INT.

Возможно, у вас вызвала недоумение запись LET J(N) = (JOY<>INT JOY) в строке 50. Однако такой метод довольно часто применяется в программировании. Он позволяет обойтись без условного оператора IF... ТHEN, в результате чего программа не только сокращается, но и работает заметно быстрее. Если условие в скобках выполняется, то возвращается единица, иначе - ноль. Если вы хотите проверить этот метод, можете сначала выполнить оператор PRINT (2 = 2), а затем PRINT (5<>5). В первом случае на экране появится число 1, а во втором - 0;

70...100 - вывод двоичного числа на экран. В строке 70 текущая позиция печати устанавливается в левом верхнем углу экрана (не забудьте в конце оператора поставить точку с запятой, иначе позиция печати переместится). Затем в цикле выводятся значения отдельных битов от старшего к младшему;

110 - переход для считывания и обработки следующей порции информации.

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

условными операторами вместо 18 (по количеству возможных комбинаций).

Теперь можно видоизменить программу САМОЛЕТ. Вставьте в нее строку

15 DIM J(5)

а затем удалите строки 300...390 и поставьте на их место новый блок управления:

300 FOR N=1 TO 5

310 LET JO=JO/2: LET J(N)=JO<>INT JO: LET JO=INT JO 320 NEXT N

330 IF J(1)1 THEN1 LET XS=XS+1 340 IF J(2) THEN LET XS=XS-1 350 IF J(3) THEN LET YS=YS+1 360 IF J(4) THEN LET YS=YS-1 370 LET FIRE=0 380 IF J(5) THEN LET FIRE=1

B таком виде программа уже должна нормально работать на всех компьютерах, претендующих на совместимость с фирменным ZX Spectrum.




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Ассемблер - как вычислить скорость комманд процессора Z80.
Параллели - Блэксбург - рай для студентов и пенсионеров.
Обзор прессы - Generаtiоn Z#04, МSF#26, FullPull#2,#3, Bоdy #3F.
Глоссарий - кто есть кто на демосцене.
Обзор - В этом разделе, как обычно, я познаком лю с новинками программного обеспечения которые поступили в Чайковский в послед ние дни лета.

В этот день...   21 ноября