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

Системные переменные - клавиатура, экран, наборы символов. Подпрограммы ПЗУ.


7. СИСТЕМНЫЕ ПЕРЕМЕННЫЕ

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

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

С некоторыми из системных переменных мы уже встречались: вспомните, например, оператор РОКЕ 23658,8, который устанавливает режим ввода прописных букв. Все прочие системные переменные можно изменять точно так же, записывая в ячейки памяти с помощью оператора РОКЕ числа из определенного диапазона. Записываемые числа должны быть целыми и в пределах от 0 до 255.

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

Системные переменные были описаны в литературе достаточно подробно, поэтому мы не станем повторяться, а расскажем лишь о некоторых из них и о том, как их можно использовать в игровых программах. Если же вы захотите более подробно разобраться в этом вопросе, советуем обратиться к книге [1].

Клавиатура

Мы уже немало рассказали о способах управления программой и спрайтами, однако разговор этот можно продолжить. Ряд ячеек в области системных переменных имеет непосредственное отношение к клавиатуре, а значит и к теме нашей книги, поэтому рассказ о них не повредит. Вы прекрасно знаете, что если при наборе или редактировании строк программы понадобится ввести несколько одинаковых символов подряд (или удалить часть текста), то вовсе необязательно бешено колотить по одной и той же клавише, а достаточно слегка надавить на нее и подождать с полсекунды - нужный символ сам начнет быстро размножаться. В игровых программах также бывает полезно использовать принцип задержки перед повторением какого-либо действия: передвижения главного героя, перемещения курсора в меню и т. п. Для этого проще всего блок управления начинать оператором PAUSE 0, например: 100 PAUSE 0: LET K$=INKEY$ 110 IF K$="Q" THEN LET Y=Y-1 120 GO TO 100

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

РОКЕ 23561,N

где N - любое число от 0 до 255. Только не переборщите, иначе проще будет не дожидаться повторений, а упорно тыкать в клавиатуру. Полезно знать, что начальное значение, записанное в ячейке 23561, равно 35, а время задержки исчисляется в 50-х долях секунды. Частота повторений регулируется системной переменной, расположенной по адресу 23562. Здесь единица измерения времени такая же, как и для предыдущей переменной - 1/50 секунды, а начальное значение равно 5.

В длинных и продолжительных циклах, особенно если нельзя останавливать программу оператором PAUSE 0, бывает очень трудно определить нажатие какой-либо клавиши и возникает ситуация, когда жми, не жми - все впустую. Ведь компьютеру в этом случае нужно выполнить огромное количество разных операций, а когда очередь доходит до IF INKEY$, оказывается, что клавиша давно уже отпущена. Бороться с подобными ситуациями поможет системная переменная LAST_K, занимающая ячейку 23560. В этой ячейке хранится код последней нажатой клавиши, причем остается он там и при отпускании клавиши до тех пор, пока вы не нажмете другую или не выключите компьютер. Таким образом, для того чтобы определить, какая из клавиш была нажата, нужно сначала узнать код ячейки 23560, а затем перевести его в символ.

Читать значения ячеек памяти позволяет функция PEEK addr, где addr - адрес от 0 до 65535, а переводит числовые значения в символы функция CHR$ kod. Посему, строки типа

LET K$=INKEY$

в описываемых случаях можно заменять на LET K$ = CHR$ PEEK 23560

Помните только, что при таком способе опроса клавиатуры вам самим придется позаботиться о своевременном сбросе переменной LAST_K в конце блока управления, вставив в программу оператор РОКЕ 23560,0.

Говоря о клавиатуре, необходимо упомянуть и о системной переменной PIP (адрес 23609), изменяя которую, можно установить желаемую длительность звука, издаваемого компьютером при нажатии клавиш. В программах это бывает полезно, если используется оператор INPUT. Для разнообразия можно даже вводить различные данные с разным «звуковым сопровождением». Например, наберите и «послушайте» такую программку:

10 INPUT "0..255-->";P: LET P=INT P 20 IF P<0 OR P>255 THEN GO TO 10 30 POKE 23609,P 40 GO TO 10

Комментировать эту программку, наверное, нет особой нужды, скажем только, что после ввода целого числа от 0 до 255 оно записывается в системную переменную PIP и следующий ввод сопровождается уже другим звуком.

Экран

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

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

ATTR=INK+PAPER x 8+BRIGHT х 64+FLASH х128

То есть если мы хотим делать надписи в служебном окне желтыми «чернилами» на синем фоне с повышенной яркостью, нам нужно в ячейку 23624 записать число 6+1x8+1 х 64+0x128=78

выполнив оператор РОКЕ 23624,78. Но помните, что выполнять эти действия надо после оператора BORDER, иначе все моментально вернется на круги своя.

Не лишне будет знать, что и с основным экраном можно поступать аналогичным образом, и вместо цепочки операторов INK, PAPER, BRIGHT и FLASH записывать код атрибутов, рассчитанный по приведенной формуле, в системную переменную ATTR_P (адрес 23693). Конечно, текст программы при этом будет читаться труднее, но зато вы достигнете большего быстродействия и сократите объем самой программы.

Вы, наверное, еще помните трудности, связанные в выводом текстов в две нижние строки экрана. Но существование такого понятия как служебное окно вовсе не означает, что вы обречены пожизненно довольствоваться таким положением вещей. Оказывается, служебное окно при желании можно и вовсе убрать с экрана. Для этого достаточно записать в ячейку 23659 ноль (обычно там «сидит» двойка). Но будьте осторожны! Перед остановкой или завершением программы, а также при использовании оператора INPUT значение этой системной переменной обязательно нужно восстановить, включив в программу оператор РОКЕ 23659,2. Если этого не сделать, то при попытке выдачи любого сообщения (даже если это сообщение ОК) компьютер, не обнаружив служебного окна, очень огорчится, и, скорее всего, огорчит и вас. Попробуйте ввести с клавиатуры РОКЕ 23659,0 (только если в памяти нет какой-нибудь ценной программы, чтобы нечего было терять) и посмотрите на результат. Надо сказать, что этот оператор программисты часто включают в свои творения с целью защитить их от несанкционированного доступа к тексту программы. Но это между прочим, а в основном использование ячейки 23659 подразумевает именно изменение размеров служебного окна. Приведем такой пример: 10 РОКЕ 23659,0

20 PRINT AT 22,5;"LINE 22"'TAB 5;"LINE 23" 30 POKE 23659,2 40 PAUSE 0

Выполнение этой программки приведет к выключению служебного окна и появлению в строке 22 экрана, начиная с пятой позиции, сообщения LINE 22. Апостроф переместит позицию печати на следующую строку, в которой также в пятой позиции появится надпись LINE 23. Затем служебное окно восстановится и программа будет ожидать нажатия любой клавиши. Несмотря на то, что после удаления служебного окна основной экран займет все 24 строки, выполнять оператор PRINT AT 23,0 ни в коем случае нельзя, так как это приведет к выдаче сообщения Integer out of range со всеми вытекающими отсюда последствиями. Именно поэтому в строке 20 приведенного примера для перевода позиции печати в нижнюю строку экрана используется апостроф.

И еще об одной системной переменной, касающейся экрана. Представим себе такую ситуацию, когда нужно нарисовать что-нибудь (скажем, рамку) в режиме наложения (OVER 1) Напишем фрагмент программы, выполняющий это задание:

100 OVER 1 110 PLOT 80,88 120 DRAW 80,0: DRAW 0,40 130 DRAW -80,0: DRAW 0,-40 140 OVER 0

Казалось бы, все очень просто, о чем тут можно говорить? Однако это не так. Присмотритесь повнимательнее к тому, что получилось на экране. Нижний левый угол прямоугольника оказался ущербным исчезла одна точка, та самая, которая ставится вначале оператором PLOT Каким же образом исправить дефект? Можно, конечно исхитриться и не доводить последнюю линию до конца, написав DRAW 0,39 вместо DRAW 0,-40. Но это не всегда удобно, и тут-то вам на помощь придет системная переменная COORDS, хранящаяся в двух ячейках 23677 и 23678. Она содержит координаты последней поставленной точки. Замените в примере строку 110 на

110 РОКЕ 23677,80: РОКЕ 23678,88 - и дефект исчезнет: ведь точка на самом деле не ставится, а просто перемещается PLOT-позиция!

Наборы символов

Не менее важны в игровых программах вопросы, касающиеся наборов символов, ибо именно в дополнительных наборах символов хранятся созданные вами спрайты. В третьей главе мы уже упоминали о системной переменной CHARS. Тогда для смены набора символов мы изменяли одну ячейку памяти 23607. На самом же деле эта переменная занимает два байта - 23606 и 23607, в которых хранится адрес, на 256 меньше адреса текущего набора. Вы можете создать не один, а несколько дополнительных наборов символов: один, к примеру, будет содержать русский шрифт, а другие - спрайты, причем для каждого уровня спрайты могут быть свои. Затем, меняя значение переменной CHARS, можно подключать к работе любой из дополнительных наборов. Если пользоваться только ячейкой 23607, то альтернативные фонты могут быть расположены по строго определенным адресам с шагом в 256 байт, использование же и второй половинки переменной CHARS позволит не заботиться о местоположении фонта и загружать его в любое удобное место памяти. Если, например, новый набор загрузить по адресу 60000, то включаться он будет таким фрагментом программы: 1000 LET AD=60000-256 1010 POKE 23607,INT (AD/256) 1020 POKE 23606,AD-256*PEEK 23607 Вернуться к стандартному знакогенератору можно с помощью строки:

9990 РОКЕ 23606,0: РОКЕ 23607,60 С помощью системной переменной CHARS могут быть получены довольно интересные эффекты. Рассмотрим один из них на примере такой программки: 10 INK 2: PAPER 0: BRIGHT 1: BORDER 0: CLEAR 59999 20 FOR N=0 TO 7: POKE 60000+N,2"N: POKE 60008+N,2"N: NEXT N 30 PRINT AT 10,11; INK 4;"G A M E" 40 POKE 23607,233 50 FOR 1=0 TO 7 60 POKE 23606,96+1

70 PRINT AT 8,8;"nnnnnnnnnnnnn";AT 12,8;"nnnnnnnnnnnnn"

80 FOR N=9 TO 11: PRINT AT N,8;" ";AT N,20;" ": NEXT N

85 IF INKEY$<>"" THEN GO TO 100

90 NEXT I: GO TO 50

100 POKE 23606,0: POKE 23607,60

10 - установка атрибутов экрана и бордюра, а затем выделение свободной области памяти «над» бейсик-программой, начиная с адреса 60000. Кроме всего прочего оператор CLEAR попутно очищает экран, поэтому нет надобности в операторе CLS;

20 - в реальной программе эта строка может отсутствовать, если в памяти уже загружен дополнительный набор символов. Здесь же два соседних символа в цикле заполняются фактурой, плавно переходящей одна в другую. На самом деле можно использовать не два символа, а сколь угодно много; главное, чтобы каждый следующий продолжал предыдущий, а последний повторял первый, как показано на рис. 7.1;

30 - на экране появляется слово GAME зеленого цвета; 40 - заносим в старший байт системной переменной CHARS заранее рассчитанное значение: INT((60000-256)/256)=233

Далее в цикле (строки 50...90) адрес символьного набора постепенно смешается, и на экран вокруг слова GAME пробелами (которые в измененном виде выглядят как наклонные черточки) выводится рамка. Так как адрес набора смещается, то и символы начинают видоизменяться, что создает иллюзию прокручивания рамки;

60 - изменяется младший байт переменной CHARS. Поскольку в данном случае его значение не превышает 255, то старший байт остается без изменений;

70, 80 - рисуется рамка;

85 - если нажата любая клавиша, программа переходит на строку 100;

90 - конец цикла и после его завершения -- переход для повторения;

100 - восстанавливается стандартный символьный набор.

Операционная система ZX Spectrum позволяет менять не только адрес полного набора символов, но также и местоположение символов определяемых пользователем (UDG), начальный адрес которых хранится в ячейках 23675 и 23676. Известная вам функция USR "А" возвращает число, записанное именно в этих ячейках и равноценна выражению РЕЕК 23675+ 256*РЕЕК 23676. Попробуйте самостоятельно изменить приведенную выше программку таким образом, чтобы задействовать в ней вместо полного набора символы UDG. Помните, что в этом случае адрес символов уменьшать на 256 уже не нужно.

Разное

Системная переменная SEED, занимающая адреса 23670 и 23671, хранит значение, используемое функцией RND для расчета очередного псевдослучайного числа. В ней не было бы ничего примечательного, если бы не одна особенность, делающая ее в некотором смысле уникальной. В Spectrum-Бейсике оператор RANDOMIZE задает начальное значение для функции RND. Этот оператор выполняет одно-единственное действие - заносит в переменную SEED указанное число. В этом легко убедиться, если ввести строку: RANDOMIZE 12345: PRINT PEEK 23670+256*PEEK 23671

В результате вы увидите на экране число 12345, то есть число, заданное оператором RANDOMIZE. Это обстоятельство можно с успехом использовать вместо расчетов младшего и старшего байтов адреса нового набора символов или для других целей. Во всяком случае, запись

RANDOMIZE AD: POKE 23606,PEEK 23670: POKE 23607,PEEK 23671 равнозначна записи

POKE 23607,INT(AD/256): POKE 23606,AD-256*PEEK 23607 но в первом случае мы обходимся без лишних расчетов. Правда, такой способ допустим только в тех случаях, когда число AD (или любое другое) заведомо не равно нулю, потому что оператор RANDOMIZE 0 или просто RANDOMIZE действует несколько по-иному. В этом случае в системную переменную SEED переписывается число из другой переменной - FRAMES которую можно назвать системным таймером. Располагается она в трех ячейках памяти: 23672, 23673 и 23674. После включения компьютера в ней содержится ноль, но как только система заработает, она начинает увеличиваться на единицу через каждые 1/50 секунды. Таким образом, прочитав значение из FRAMES можно узнать сколько времени прошло с момента включения компьютера. Это позволяет при желании встраивать с игровые программы часы, а также сопоставлять любые игровые моменты с реальным временем. Представим программку электронных часов, которую вполне можно использовать и в играх (см. программу МАКСИТ в приложении 1): 10 INPUT "h: ";h;"nnm: ";m;"ППэ: ";s 20 LET tim=(h*3600+m*60+s)*50

30 LET t3=INT (tim/65536): LET t2=INT ((tim-t3*65536)/256): LET t1=(tim-t2*256-t3*65536)

40 POKE 23672,t1: POKE 23673,t2: POKE 23674,t3

100 LET tim=(PEEK 23672+256*PEEK 23673+65536*PEEK 23674)/50: LET h=INT (tim/3600): LET m=INT ((tim-h*3600)/60):LET s=tim-h*3600-m*60 110 IF h>=24 THEN POKE 23672,0: POKE 23673,0: POKE 23674,0: GO TO 100 120 LET s1=INT s: LET s=s-s1: LET t$=":": IF s>.7 THEN LET t$=" " 130 PRINT AT 0,20;("0" AND h<10);h;t$;("0" AND m<10);m;t$;("0" AND s1<10);s1 140 IF INKEY$="" THEN GO TO 100 Прокомментируем строки этой программы: 10 - ввод текущего времени; h - часы, m - минуты и s - секунды; 20 - перевод введенного времени в 50-е доли секунды;

30 - переменная tim раскладывается на три байта для занесения ее в системную переменную FRAMES в строке 40;

100 - из системной переменной FRAMES берется значение текущего времени и переводится в часы, минуты и секунды;

110 - проверяется, не прошло ли 24 часа. Если да, то системный таймер обнуляется;

120 - значение секунд разделяется на целую (s1) и дробную (s) части. Если дробная часть не больше 0.7 секунды, то между цифрами часов, минут и секунд будет ставиться двоеточие, а если больше - пробел. В результате разделяющие двоеточия будут мигать в такт секундам, что «оживит» вид часов;

130 - вывод значений часов, минут и секунд, причем если какое-то значение получилось меньше 10 (то есть состоит из одной цифры), то перед ним допечатывается ноль, в результате чего числа всегда получаются двузначными; 140 - переход для расчета следующего момента времени.

Используя в своих программах системный таймер, нужно помнить также о том, что на момент извлечения звука с помощью оператора ВЕЕР (включая и писк клавиатуры при вводе строк программы или данных в операторе INPUT), а также при загрузке и сохранении программ на магнитной ленте время для компьютера останавливается, и переменная FRAMES не изменяется. То же самое происходит и в некоторых других случаях, связанных, в основном, с обращением к подпрограммам в машинных кодах, речь о которых пойдет в следующем разделе.

Подпрограммы ПЗУ

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

Обращение к кодовой подпрограмме осуществляет известная вам (правда, в другом качестве) функция USR. Как вы знаете, любое выражение Бейсика должно начинаться с оператора, поэтому для вызова кодовых подпрограмм чаще всего используют конструкции типа RANDOMIZE USR addr, где addr - адрес подпрограммы. Например, RANDOMIZE USR 3435 выполнит те же действия, что и оператор CLS.

Часто в меню игровых программ можно встретить пункт КОНЕЦ ИГРЫ, при выборе которого память очищается и на экране появляется надпись © 1982 Sinclair Research Ltd. Обычно это достигается включением в программу оператора NEW, который удаляет се и обнуляет память вплоть до адреса, указанного в операторе CLEAR. Более кардинально очистить память можно с помощью оператора RANDOMIZE USR 0. В этом случае произойдет то же, что и при нажатии кнопки Reset.

В игре САМОЛЕТ у нас возникала необходимость очистить служебное окно экрана. Там мы воспользовались для этого оператором INPUT. Однако программисты часто поступают по-другому, вставляя в программу оператор RANDOMIZE USR 3438.

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

При переходе от заставки к игре мы всегда очищали экран командой CLS, но в некоторых играх удаление заставки происходит другими способами. Пожалуй, самый распространенный из них - скроллинг. Заставка не сразу исчезает с экрана, а постепенно «уползает» в сторону.

Вертикальное движение изображения достигается использованием оператора RANDOMIZE USR 3582, который перемещает весь экран на одну строку вверх. Попробуйте в любую из приведенных ранее заставок включить строку FOR N=1 TO 24: RANDOMIZE USR 3582: ВЕЕР .01,N: NEXT N

и вам наверняка захочется использовать этот фрагмент и в своих собственных программах.




СОДЕРЖАНИЕ:


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

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



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

Похожие статьи:
Happy 2 - законы невезения и юмористическая реклама.
Реклама - реклама и обьявления от и для спектрумистов.
Интерфейс - Описание игры "Смагли-2".
SUPА-ГАMZ - SUPER CАRS.
Ликбез - полноый дизассемблер ПЗУ (часть 14).

В этот день...   20 апреля