СЛУЧАЙНАЯ ГРАФИКА
( Глава из книги "Дизайн Ваших программ")
Продолжая разговор о графике "Спектрума", мы представляем отрывок из готовящейся сейчас к изданию книги "Персональный компьютер СПЕКТРУМ. Дизайн ваших программ. " Это заключительный (четвертый) том готовящейся к выпуску серии, посвященной графике.
По мере окончания подготовки, книга будет предложена к изданию по регионам. Следите за нашей информацией.
СЛУЧАЙНАЯ ГРАФИКА
Есть один аспект, связанный с 48-килобайтными "Спектрумами", в котором проявляется ограниченность их ресурсов оперативной памяти - это графика. Здесь ограничения более, чем очевидны. Графические изображения могут чудовищно расходовать память Вашей машины.
Вам никогда не приходилось задумываться, почему одни программы имеют богатую графику, а другие - выглядят серыми и невыразительными? Что, может быть в первом случае работал хороший художник, а во втором - плохой? Да, конечно, для любительских программ это вполне справедливо, но если речь идет о крупной фирме, способной привлечь к работе и оплатить труд первоклассных дизайнеров, то ясно, что не в художнике дело. Он бы Вам изобразил все, что хотите, а вот как разместить все его идеи в ограниченном объеме памяти?!
Итак, графический дизайн программы оказывается тесно увязан с программными возможностями, с общей концепцией проекта, и насколько хороша будет программа, зависит в конечном итоге не только от художника, а от совместных усилий всей команды в целом, начиная с руководителя проекта и кончая самым последним программистом. Вот почему так важно еще на этапе предварительной проработки концепции будущей программы четко определиться с потребностями в графике и наметить для себя те программистские приемы и методы, которыми эти потребности будут обеспечиваться.
Сегодня мы Вас и познакомим с одним из таких приемов. Он состоит в том, чтобы предоставить генерацию графики самому компьютеру по некоторому заданному алгоритму, поставив тем самым производство графических изображений "на поток". У этого метода есть существенный недостаток, состоящий в том, что многие изображения могут оказаться "похожими" друг на друга и различаться лишь в деталях, но это уже вопрос баланса программы. Вы ведь можете использовать полученную таким образом графику только в качестве фоновой, накладывая на нее незначительные по размерам и по объемам расходуемой памяти графические объекты.
Такая техника применяется, как правило, в адвентюрных программах, поскольку именно в них приходится иметь дело с огромным количеством иллюстраций (например 32000 - в программах фирмы BEYOND - "Sorderon's Shadow" или, скажем, "Lords of Midnight", хотя есть и много более внушительные примеры). По всей видимости, первой применила такую технику фирма LEGEND в своей знаменитой программе "Valhalla".
Теперь давайте перейдем к конкретной задаче и посмотрим, как используя "спектрумовский" генератор случайных чисел, можно получить образцы такой "фоновой" графики (ее еще называют ландшафтной графикой) для Ваших программ.
Мы сразу должны оговориться, что полное исследование всех возможностей предлагаемого метода может занять у вас не один месяц и полностью осветить все варианты в рамках одной книги нет никакой возможности. Мы будем просто руководствоваться генеральным принципом "ИНФОРКОМа" - научить приемам и методикам, а скрупулезное исследование оставляем читателю на самостоятельную проработку.
Рассмотрим в качестве примера следующую Бейсик-программу. Не обращайте пока внимания на то, что она очень медленно работает, сейчас для понимания самой сути идеи нам это не так важно (Листинг 1).
ЛИСТИНГ 1.
1 DEF FN r(x)=INT(RND*x)
2 BORDER 0: INK 0: LET n=1: GO TO 1000
7 REM
8 REM ** Рисуем рамку и наносим фоновые цвета **
9 REM
10 CLS: PLOT 0,95: DRAW 128, 0: DRAW 0,80: PRINT AT 1, 17; "Рисунок номер..."; AT 3, 24; n;
AT 0,0;
15 PRINT PAPER 5,,,,,,,V PAPER 1, ',' PAPER 6, ',',': RETURN
17 REM
18 REM ** Рисуем горы **
19 REM
20 INK 0:LET ht =FN r(24): LET mx=23: LET mn=0: LET p=FN r(2) 25 FOR i=0 TO 127: PLOT i,136: DRAW 0, 7+ht
30 IF p THEN LET ht=ht+FN r(2):IF ht>= mx THEN LET P=0: LET ht=mx: LET mn=1+FN r(7) : GO TO 50
40 IF NOT p THEN LET ht=ht-FN r(2): IF ht<=mn THEN LET p=1: LET ht=mn:LET mx=8+FN r(16) 50 NEXT i: RETURN
77 REM
78 REM ** Рисуем озеро **
79 REM
80 INK 7: FOR i=0 TO 49
90 LET x = FN r(125): LET y=128+ FN r(8): PLOT x,y 100 DRAW FN r(4),0: NEXT i: RETURN
137 REM
138 REM ** Рисуем тростник **
139 REM
140 INK 4: FOR i=0 TO 127: LET mn=FN r(2): LET mx=1 +FN r (7) 150 PLOT i,119+mn: DRAW 0, mx-mn: NEXT i : RETURN
177 REM
178 REM ** Рисуем каменистую равнину **
179 REM
180 INK 0: FOR i=0 TO 49
190 LET x=FN r(128): LET y=104+FN r(8):PLOT x,y: NEXT i: RETURN
237 REM
238 REM ** Рисуем траву на переднем плане **
239 REM
240 INK 4: FOR i=0 TO 127: PLOT i,96: DRAW 0, FN r(8): NEXT i: RETURN
997 REM
998 REM ** Главный цикл рисования картинки **
999 REM
1000 CLS: RANDOMIZE n: GO SUB 10: REM ** Очистка картинки ** 1005 GO SUB 20: REM ** Рисуем горы **
1010 GO SUB 80: REM ** Рисуем озеро **
1015 GO SUB 140: REM ** Рисуем ТРОСТНИК **
1020 GO SUB 160: REM ** Рисуем почву **
1025 GO SUB 240: REM ** рисуем траву **
1030 INK 0: PRINT #1; AT 1,9; FLASH 1; "Еще рисунок?"
1040 PAUSE 0: LET n=n+1: GO TO 1000
Как Вы видите, эта небольшая программа использует функцию генерации случайных чисел компьютера RND, с помощью которой случайным образом задаются параметры графических операторов БЕЙСИКа DRAW и PLOT. Программа довольно эффектно рисует пейзажи, содержащие горы, воду, почву и т. п. Но что самое интересное для программиста -так это то, что функция RND, как Вы должно быть знаете, вовсе не выдает случайные числа, а только лишь псевдо-случайные. То есть, имеется некоторая заранее предопределенная последовательность, из которой эти псевдослучайные числа и выбираются. Эта последовательность рассчитывается с помощью небольшой процедуры, имеющейся в ПЗУ
компьютера.
В качестве исходного параметра при работе этой процедуры используется значение системной переменной SEED, содержащейся в двух байтах по адресам 23670, 23671 (5C76^. Изменить содержимое этой системной переменной и начать генерацию новой псевдослучайной последовательности можно оператором RANDOMIZE n, что вы и видите в программе в строке 1000. В качестве параметра n может быть любое число от 0 до 65535, т.е. таким образом, Ваш генератор случайных чисел может выдать псевдослучайную последовательность из 65536-ти чисел, после чего они начнут повторяться (последовательность вырождается).
Если Вы зададите в операторе RANDOMIZE в качестве параметра n например номер картинки, то Вы всегда для одного и того же, номера будете иметь один и тот же пейзаж, но для разных n они будут различны.
Конечно, можно пойти еще дальше и, в зависимости от n, вызывать те или иные процедуры, которые внесут дополнительное разнообразие в Ваш рисунок, например, можно наложить какие-то небольшие рисунки на Ваш фоновый пейзаж.
Несложной заменой параметра цвета INK озеро, изображаемое на среднем плане, может быть преобразовано в болото, в снежный покров, в песчаную пустыню.
Проблемы скорости работы.
К сожалению, перед нами по-прежнему стоит проблема, связанная с медленной работой вышеприведенной программы. На первый взгляд, все это не так сложно, надо только заменить медленно работающие операторы PLOT, DRAW и RND на вызов из машинного кода тех процедур ПЗУ, которые им соответствуют, но результат будет ненамного лучше. Дело в том, что стандартная процедура ПЗУ, выполнявшая функцию RND, работает настолько медленно, что от того, что вы ускорите обращение к ней применением машинного кода, Вы мало чего достигнете. Надо искать другое решение.
Во-первых, честно говоря, нам и не нужна очень случайная последовательность для нашей задачи и нет смысла проходить все те манипуляции с числами, которые выполняет процедура ПЗУ.
Во-вторых, зачем нам 65536 случайных чисел? Может быть, на первый случай будет достаточно и 256-ти?
Ну, и если это все так, то мы сами можем создать где-то в памяти небольшую таблицу из 256 чисел, предварительно заполнить случайными числами, а затем брать их оттуда в готовом виде, не привлекая для этого обращение к ПЗУ.
Резервируем для этого область памяти, начиная с адреса 64744: FOR i = 64744 TO 64799: POKE i, INT(RND*255)): NEXT i
Теперь представьте, что у Вас есть некий указатель, который указывает на какой-то пункт в этой таблице. Предположим, вам понадобилось некоторое случайное число - Вы возьмете его из того пункта, на который указывает указатель, а сам указатель передвинете на следующую позицию для последующего использования. Когда указатель дойдет до конца таблицы, его совсем несложно опять перегнать в ее начало, так мы сможем обеспечить 256 различных картинок в своей программе, различающихся начальной позицией указателя. Конечно, при рисовании только одной картинки, указатель может много раз пробежать по таблице, но в этом нет никакой беды, потому что если например при рисовании травы и возникнет некое подобие регулярности, то оно не будет выглядеть неестественно, а графика, с помощью которой изображены горы, достаточно сложна, чтобы заметить в ней некоторые внутренние повторения. Для проведения математических или статистических исследований, такой подход был бы совершенно неприемлем, но для графики он вполне годится.
Трансляция БЕЙСИКа в машинный код.
Читатель, который интересуется только идеями, приемами и методами, мог бы на этом и завершить чтение данной главы и приступить к самостоятельным исследованиям по созданию образцов случайной машинной графики. Те же, кому необходим инструмент с достойными рабочими характеристиками, получат ниже рекомендации о том, как значительно ускорить работу алгоритма, подключив в дело машинный код.
Прежде всего, для работы нам необходимы четыре процедуры:
- рисования точки (аналог PLOT);
- рисования линии (аналог DRAW);
- генерации случайных чисел (аналог RND);
- процедура для подготовки экрана (очистка экрана, рисование рамки, предварительное окрашивание фона в цвета PAPER) - назовем ее BCGRND от слова BackGround - фон, задний план.
PLOT.
С этой процедурой все просто. Ее даже не надо делать, вполне можно использовать процедуру, имеющуюся в ПЗУ по адресу 22Е5Н (8933), вызвав ее командой процессора CALL 22E5H.
Надо только предварительно перед вызовом этой процедуры выставить ее параметры в регистрах B и C микропроцессора. Так, если Вам надо выполнить PLOT x,y, то в регистр C должно быть загружено число "x", а в регистр B - число "у".
DRAW.
Здесь мы поступим аналогично, воспользовавшись процедурой ПЗУ, служащей для рисования линий и расположенной по адресу 24ВАН (9403). Параметры "х" и "у" оператора DRAW x,y выставляются предварительно в регистрах C и B совершенно аналогично, но надо еще выставить в регистрах D и Е знаки "y" и "х", соответственно. Во время своей работы, процедура "портит" содержимое регистровой пары HL регистров альтернативного набора. Поэтому, чтобы не было никаких коллизий с прочими процедурами, необходимо в общем случае запоминать содержимое этой пары на стеке процессора, а после окончания работы процедуры - восстанавливать его.
RND.
Работа этой процедуры представляет для нас несколько больший интерес. Нам надо, чтобы после ее вызова, она выдавала бы эквивалент того, что выдает оператор INT(RND*x), где "х" - число, предварительно загруженное в аккумулятор процессора. Результат работы процедуры при выходе из нее остается там же - в аккумуляторе. Одним словом, эта процедура должна делать то же самое, что и функция FN r(), определенная нами ранее в строке 1 вышеприведенной БЕЙСИК-программы.
Для работы этой процедуры Вам надо также предварительно заполнить 256-байтную таблицу псевдослучайных чисел, как это было показано выше. Сделайте это сами, а впоследствии мы сможем отгружать таблицу вместе с машинным кодом наших процедур единым блоком.
Обеспечивать задание начальной точки нашей псевдослучайной последовательности мы сможем, изменяя при помощи POKE значение переменной POINT, находящейся по адресу 65057. Так, заслав сюда номер Вашего рисунка, Вы получите его на экране.
BCGRND
Процедура служит для подготовки левой верхней четверти экрана к рисованию вашей картинки. Это оставляет еще достаточно места для текстовых сообщений, если Вы пишете адвентюрную или обучающую программу.
Процедура достаточно проста для тех, кто хоть немного знаком с машинным кодом. Для тех же, кто делает первые шаги, укажем только, что сначала она вызывает из ПЗУ процедуры PLOT и DRAW для рисования рамки, а затем приступает к закрашиванию фона цветами PAPER. Для неба - это 5 рядов цвета РАР_1 (в нашем случае это голубой), для озера - 2 ряда РАР_2 (синий), а для почвы - три ряда РАР_3 (желтый). Закрашивание выполняется командой процессора RST 16, служащей для вывода информации на экран, закрашивание рядов выполняется в цикле, окончание цикла задано командами процессора DJNZ.
Возможно, стоит пояснить, как происходит закрашивание каждого ряда, в принципе, чтобы окрасить ряд из 16-ти знакомест в цвет PAPER, надо напечатать 16 пробелов, но это расточительная операция. Здесь все сделано изящнее с помощью кода управления печатью
CHR 6 (строки 730, 830, 930). Этот управляющий символ называется PRINT COMMA -"Запятая Оператора PRINT". Его действие эквивалентно действию оператора TAB 16, т.е. он выводит на экран те самые нужные нам 16 пробелов.
Окончание заполнения ряда и переход к новому ряду выполняются печатью 13-го символа (CHR 13 = "ENTER") - строки 759, 850, 950.
Процедура организована таким образом, что Вы всегда имеете возможность поменять значения фоновых цветов PAP_1, РАР_2, РАР_3. Они заданы директивой АССЕМБЛЕРа DEFB в ячейках памяти 65137, 65138, 65139.
Распечатка этих четырех вспомогательных процедур приведена в Листинге_2. Наберите их с помощью любого доступного Вам АССЕМБЛЕРа и откомпилируйте в машинный код, начиная с адреса 65000 по 65139. Если Вы не забыли предварительно составить таблицу псевдослучайных чисел в адресах с 64744 по 64799, то можете выгрузить их совместно.
Листинг 2.
|
10 |
Распечатка |
четырех |
|
|
20 |
вспомогательных процедур |
|
|
30 |
DRAW, PLOT |
, RND и BCGRND |
|
65000 |
40 |
|
ORG 65000 |
|
|
50 DRAW |
|
|
|
60 |
Процедура |
эквивалентна DRAW |
C, B |
65000 |
70 |
|
EXX |
|
65001 |
80 |
|
PUSH HL |
|
65002 |
90 |
|
ЕХХ |
|
65003 |
100 |
|
LD DE,010^ |
|
65006 |
110 |
|
CALL 24BAH |
|
65009 |
120 |
|
EXX |
|
65010 |
130 |
|
POP HL |
|
65011 |
140 |
|
EXX |
|
65012 |
150 |
|
RET |
|
|
160 |
|
|
|
|
170
180 |
|
|
|
|
180 190 |
процедура |
эквивалентна PLOT |
C, B |
|
200 PLOT |
EQU 22E5H |
|
|
210 |
|
|
|
|
220 |
|
|
|
|
230 RAND |
|
|
|
240 |
Процедура |
принимает из аккумулятора число |
|
250 |
и замещает |
его на результат |
вычисления |
|
260 |
INT (RND*A). Таблица случайных чисел в |
|
265 |
адресах 64741...64999 должна |
быть заполнена. |
65013 |
270 |
|
LD (VALUE),A |
; Запомнили содержимое аккумулятора в |
|
|
|
|
; с меткой VALUE. |
65016 |
280 |
|
LD HL,64744 |
; Начало таблицы случайных чисел. |
65019 |
290 |
|
LD DE,(POINT) |
; Ввели текущее значение указателя. |
65023 |
300 |
|
LD D,0 |
|
65023 |
310 |
|
ADD HL, DE |
; Встали на позицию указателя. |
65026 |
330 |
|
LD A,E |
; Ввели значение указателя. |
65027 |
330 |
|
INC A |
; Передвинули указатель, |
65028 |
340 |
|
LD (POINT),A |
; Запомнили новое положение указателя |
65031 |
350 |
|
LD A, (HL) |
, Приняли случайное число. |
65032 |
360 |
|
CALL 2D28H |
; Эта процедура ПЗУ выполняет |
|
|
|
|
; сразу две полезные функции - |
|
|
|
|
; переводит число в действительную |
|
|
|
|
; форму (с плавающей точкой) |
|
|
|
|
; и помещает его на стек калькулятора |
65055 |
370 |
|
LD A,255Н |
|
65037 |
380 |
|
CALL 2D28H |
; Поместили на стек 255, |
65О40 |
390 |
|
RST 40 |
; Включение калькулятора, |
65041 |
400 |
|
DEFB 5 |
; Команда калькулятора |
"деление". На стеке
65042 410
65043 420 66046 430
65049 440
65050 450
DEFB 39 DEFB 56 CALL 2DD5H
65051 460
65052 470 66053 480
65050 490
65057 500
65058 510 520 530 540 550 560
65059 570 65061 580
DEFB 56 LD A,(VALUE) CALL 2D28H
RST 40 DEFB 4
65062 |
590 |
|
LD B, |
95 |
65064 |
600 |
|
LD C, |
0 |
65068 |
610 |
|
CALL |
PLOT |
65071 |
620 |
|
LD B, |
0 |
65073 |
630 |
|
LD C, |
128 |
65075 |
640 |
|
CALL |
DRAW |
65078 |
650 |
|
LD B, |
80 |
65080 |
660 |
|
LD C, |
0 |
65082 |
670 |
|
CALL |
DRAW |
66085 |
680 |
|
LD A, |
17 |
65087 |
690 |
|
RST 1 |
6 |
65088 |
700 |
|
LD A, |
(PAP 1) |
65091 |
710 |
|
RST 1 |
6 |
65092 |
720 |
|
LD B, |
5 |
65094 |
730 |
LOOP1 |
LD A, |
6 |
65096 |
740 |
|
RST 1 |
6 |
66097 |
750 |
|
LD A, |
13 |
65099 |
760 |
|
RST 1 |
6 |
66100 |
770 |
|
DJNZ |
LOOP1 |
65102 |
780 |
|
LD A, |
17 |
65104 |
790 |
|
RST 1 |
6 |
65105 |
800 |
|
LD A, |
(PAP 2) |
65108 |
810 |
|
RST 1 |
6 |
65109 |
820 |
|
LD B, |
2 |
65111 |
830 |
LOOP2 |
LD A, |
6 |
65113 |
840 |
|
RST 1 |
6 |
65114 |
850 |
|
LD A, |
13 |
66116 |
860 |
|
RST 1 |
6 |
65117 |
870 |
|
DJNZ |
LOOP2 |
65119 |
880 |
|
LD A, |
17 |
65521 |
890 |
|
RST 1 |
6 |
65122 |
900 |
|
LD A, |
(РАР 3) |
65125 |
910 |
|
RST 1 |
6 |
65126 |
920 |
|
LD B, |
3 |
осталось "RND". Выключение калькулятора.
Поместили на стек значение VALUE.
Включение калькулятора, Команда калькулятора "умножение". На стеке получено RND*VALUE. Команда калькулятора INT. Выключение калькулятора. очень важная процедура ПЗУ. Снимает число с вершины стека калькулятора и пересылает его в регистр A микропроцессора.
переменная POINT. Переменная VALUE.
Процедура рисует рамку и фоновые полосы в цвете PAPER, заданном в РАР_1, РАР_2, РАР_3.
Вызовом этой процедуры выбирается устройство вывода информации. Поскольку в аккумуляторе установлено число 2, вывод будет идти на экран.
Код PAPER.
Установка цвета PAPER.
5 рядов - небо. Управляющий код CHR 6.
Управляющий код ENTER.
2 ряда - озеро
3 ряда - земля
LD A,6 RST 16 LD A,13 RST 16
65137 990 PAP_1
65138 1000 PAP_2
65139 1010 РАР 3
Изменив значение по адресу 65137 на 1, Вы вместо голубого неба получите синее и день превратится в ночь. А замена числа 1 на 4 по адресу 65138 превратит озеро в болото. Это ваши дополнительные резервы по созданию графики несложной по исполнению, малоемкой по расходуемой памяти, но способной внести своеобразную атмосферу в любую программу.
Теперь нам осталось воспользоваться созданными процедурами и довести дело до конца, написав программу, которая будет нам генерировать такие картинки в огромных количествах в доли секунды.
Распечатка представлена в Листинге_3. Он не снабжен подробными комментариями, поскольку в нем сделано все возможное, чтобы максимально следовать той БЕЙСИК-программе, с которой мы начинали. Она фактически и является комментарием этой процедуры.
Листинг 3.
LD A,13 ORG 65140
; Горы. CALL INIT LD A,24 CALL RAND LD (HT),A LD A,23 LD (MX),A XOR A LD (MN),A LD A,2 CALL RAND LD (PP),A LD A,(II) LD C,A LD B,136 CALL PLOT XOR A LD ^А LD A,(HT) ADD A,7 LD B, А CALL DRAW LD A,(PP) CP 0
JP NZ,UP LD A,2 CALL RAND LD B^ LD A,(HT) SUB B LD (HT),A LD B^ LD A,(MN) CP B
CALL NC,SWAP2
LD A,(II) INC A CP 128 RET Z LD (II),A JP LOOP4 LD A,2 CALL RAND LD B^ LD A,(HT) ADD A,B LD (HT),A LD A,(MX) LD B,А LD A,(HT) CP B
CALL NC,SWAP1 JP CONT LD A,В LD (HT),A LD A,7 CALL RAND ADD A,1 LD (MN),A XOR A LD (PP),A RET
LD (NT),A LD A,16 CALL RAND ADD A,8 LD (MX),A LD A,1 LD (PP),A RET
DEFB 0 DEFB 0 DEFB 0 DEFB 0 DEFB 0
; Озеро. CALL INIT LD A,125 CALL RAND LD C,A LD A,8 PUSH ВС CALL RAND POP ВС ADD A,128 LD B,A CALL PLOT LD A,4 CALL RAND LD C,A LD B,0 CALL DRAW LD A,(II) INC A CP 50 RET Z LD (II),A JP LOOP5
; Тростник CALL INIT LD A,2 CALL RAND LD (MN),A LD A,7 CALL RAND ADD A,1 LD (MX),A LD A,(II) LD C,A LD A, (MN) ADD A,119 LD B,A CALL PLOT XOR A LD C,A LD A,(MN) LD B,A LD A,(MX) SUB B LD B,А CALL DRAW LD A,(II) INC A CP 128 RET Z LD (II),A JP LOOP6
; Земля. CALL INIT LD A,128 CALL RAND LD C,А LD A,8 PUSH ВС CALL RAND POP BC ADD A,104 LD B^ CALL PLOT LD A,(II) INC A CP 50 RET Z LD (II),A JP LOOP7
; Трава. CALL INIT LD A,(II) LD C,A LD B,96 CALL PLOT LD A,8 CALL RAND LD B,А LD C,0 CALL DRAW LD A,(II)
65468 |
268O |
|
INC A |
65469 |
2690 |
|
CP 128 |
65471 |
2700 |
|
RET Z |
65472 |
2710 |
|
LD (II),A |
65475 |
2720 |
|
JP LOOP8 |
|
2730 |
|
|
|
2740 |
|
|
|
2750 |
INIT |
; процедура инициализации. |
|
2760 |
|
: Устанавливаем цвет PAPER |
|
|
|
; равный transparent - |
|
|
|
; то же самое, что |
|
|
|
; и PAPER 8. |
65478 |
2770 |
|
LD A,248 |
65480 |
2780 |
|
LD (MASKT),A |
|
2790 |
|
; Обнуление счетчика. |
65483 |
2800 |
|
XOR A |
65484 |
2810 |
|
LD (II),A |
65487 |
2820 |
|
RET |
|
2830 |
|
|
|
2840 |
MASKT |
EQU 23696 |
|
2850 |
PLOT |
EQU 8933 |
|
2850 |
DRAW |
EQU 65000 |
Пример применения случайной графики.
Замок на переднем плане наложен более поздно.
После того, как Вы ассемблируете процедуры, приведенные в листингах, не забыв, конечно и о таблице случайных чисел, Вы принципе уже готовы к тому, чтобы начать рисовать. Дело осталось только совсем за малым: нужна программа-драйвер, которая объединит все части в единое целое и будет ими управлять. Ее можно сделать и на БЕЙСИКе (См. Листинг_4). Приведенный пример обеспечит Вам генерацию 256 различных картинок и прокрутку их одну за другой по нажатию клавиши.
Попробуйте, и Вы увидите, что скорость воспроизведения графики вполне достаточна для того, чтобы использовать ее в реальных программах и уж совсем несравнима с тем, что мы имели в БЕЙСИКе.
Практически мы с Вами затратили на генерацию 256-ти картинок около 800 байтов (вместе с таблицей случайных чисел), т.е. примерно по 3 байта на картинку. Это нормальное соотношение, но его можно было бы еще улучшить в несколько раз.
Во-первых, ясно, что если бы мы делали большее количество рисунков, то оно было бы лучше.
Во-вторых, хранение в памяти таблиц - это наиболее простой в смысле понятности способ и годится только для демонстрации вследствие своей расточительности. Профессионалы же пишут сами краткие и устойчивые алгоритмы генерации псевдослучайных последовательностей.
В третьих, если Вы проанализируете листинг 2, то увидите, насколько же мало байтов уходит на то, чтобы смоделировать тот или иной графический объект (горы, озеро, луг, грунт и т.п.). Пользуясь предложенной идеей, Вы всегда сможете развить число этих объектов (крепостная стена, изгородь, заросли кустарника, лес, море, скалы, звездное небо, космические тела и многое другое).
Ну и, наконец, в четвертых, мы уже говорили о том, что большое разнообразие при смысловой содержании и сохранении духа и атмосферы программы Вы сможете получить, накладывая на полученные пейзажи некрупные графические объекты, не занимающие большого места в памяти. Одним из рациональных приемов при этом является формирование их на основе блочной графики UDG.
ЛИСТИНГ_4.
1 REM ** БЕЙСИК-драйвер **
2 REM
3 BORDER 0: CLEAR 64743: LOAD ""CODE 65000
4 REM **Заполнение псевдослучайной таблицы**
5 REM
6 FOR i=64744 TO 64999: POKE i, INT(255*RND): NEXT i
7 LET n=0: REM **Инициализация счетчика**
8 REM **Главный цикл**
9 REM
10 LET n=n+1: POKE 65057, n
15 INK 0: CLS: RANDOMIZE USR 65059
20 PRINT AT 1, 17; "Номер рисунка..." AT 3,24; n
30 INK 0: RANDOMIZE USR 65140: REM **Горы**
35 INK 0: RANDOMIZE USR 65300: REM **Озеро**
40 INK 0: RANDOMIZE USR 65346: REM **Тростник**
45 INK 0: RANDOMIZE USR 65407; REM **Земля**
50 INK 0: RANDOMIZE USR 65442: REM **Трава**
60 PRINT #1; AT 1,9; FLASH 1: "Еще рисунок?": PAUSE 0
70 GO TO 10
Может быть, Вам потребуется не один набор UDG и Вы организуете эти наборы в банки. Впрочем, об этом речь еще впереди.
По мере готовности книги мы оповестим всех, кто готов заняться ее изданием и распространением в своих регионах. Следите за нашей информацией!
(С) ИНФОРКОМ, 1992