Глава 3.2

По моим заметкам в исходном коде, непосредственной разработкой R-Type я занялся 28 февраля 1988 года, это вероятно означало, что я только что разгреб бардак в исходном коде Rampage и вытащил подпрограммы, которые мог бы использовать повторно, если честно — их было немного. Пока я тестировал несколько способов реализации игры, мне Catalyst прислала по почте видео кассету с восемью уровнями игры, снятыми с игрового автомата, в данном случае камера была направлена на монитор, производя запись, пока кто-то проходил целую игру. Игра была настроена на неуязвимость, к счастью, корабль был похож на призрак, проникающий всюду и оставляя все целым и невредимым, это было лучше, чем неуязвимость, похожая на летящий кирпич, уничтожающий все при прикосновении к нему. Это давало возможность просмотреть полностью шаблоны перемещения/полета/атаки каждого чужого в игре без прерывания в середине полета при столкновении с вашим кораблем с последующим взрывом.

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

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

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

* * *

Дома в Суонси я начал работать над игрой, а точнее над инструментальными программами. Мне нужно было написать: игру, очевидно некое подобие редактора уровней, необходимого для создания и разметки уровней, а также редактор спрайтов для спрайтов и графики. Тогда в ходу уже были несколько подобных программ, но все они были разработаны кодерами для создания конкретных игр или были очень обобщенного характера. В первом случае вам придется иметь дело с нестандартными выходными данными, или же вы нашли бы программу, выглядящую многообещающе, но принуждающую вас работать с плиткой или символами (под символом имеется ввиду его представление в виде матрицы 8*8 точек (8 байтов) и 1 байт атрибутов цвета, под плиткой — спрайт, состоящий из n*m символов), способ, который просто не будет работать в вашей игре, и позднее в общем случае вы обычно заканчиваете со слишком большим количеством данных.

Это означало, что у меня просто не было выбора, кроме как написать свои редакторы, которые хоть и отнимут какое-то время, но создадут графику в совершенно правильном макете, так, как хотел я, а не пытаться конвертировать чей-либо формат. Когда я сказал "Я", то в действительности имел ввиду Марка Джонса (Mark Jones), который должен был заниматься разметкой уровней, дизайном спрайтов, и всей остальной графикой для игры.

Марк сделал большую часть графики для всех форматов игры Rampage и все знали, что он более чем способен сделать ту же самую работу для R-Type, но главным фактором, определяющим, насколько успешным получится игра позднее, будет точность проведенной им конвертации к оригинальной графике и полученному качеству. Марк спросил меня, чего я хочу и что он должен сделать, и я просто ответил, чтобы он дал мне все готовое сразу, и я попробую вложить это все в игру. Это сработало действительно очень хорошо, так как он сначала должен был сделать графику для версии Atati ST с ее великолепными шестнадцатью цветами на пиксель, а затем взял ту же самую графику и немного пощипал ее, и она вышла отлично выглядящей на Спектруме с его цветовыми ограничениями. Я думаю, что если бы ему пришлось создавать графику только для Спектрума, то она бы получилась намного другой, но создание графики сначала для ST, которая была наиболее идентичной в деталях с версией аркадного автомата, а затем доработав цвета, все получилось намного аккуратнее в финальном счете. Этот подход принесет дивиденды Rare в будущем для версии игры Donkey Kong Country для SNES, так что Марк определенно что-то привнес.

Я, положа руку на сердце, должен откровенно признаться, что немного схитрил при создании инструментов TileD и ED209 (имена данные мною для редактора уровней R-Type и спрайтового редактора для Спектрума), которые имели внедренные копии частей коммерческого пакета графики Melbourne Draw, отвечающие за создание персонажей и функции рисования. Отсутствие необходимости создавать базовые графические функции с нуля сохранили так необходимое в дальнейшем время для настройки.

* * *

Я должен отметить, что с самого начала не было какого-то определенного плана как будет создаваться игра, я имею ввиду, что я не садился и не обдумывал все этапы. Это не было тем случаем "о да, все идет к тому, чтобы было минимальное расслоение цветов (на экране ZX Spectrum цвет определяется для статического знакоместа размером 8*8, из-за этого, например, при перемещении спрайта размером в два знакоместа, но с разными цветами, невозможно правильно отобразить цвет на экране) и плавное прокручивание, а способ которым я буду это делать…", все что я хотел — это получить оптимально выбранный размер экрана для его прокручивания, оптимально быстрое вытаскивание данных из карты уровня и прикрутить спрайтовый движок на все это сверху, и я не хотел копаться с цветовыми коллизиями и сделал бы приятную, безопасную монохромную версию которую, казалось, все одобрили бы. Я знал, что такой подход сработает, играя в Light Force для Спектрума от компании FTL, я мог понять, что это определенно возможно: все что мне нужно было сделать так это найти какой-то аналогично работающий подход, фон, перемещающийся попиксельно, спрайты игрока и врагов, двигающихся посимвольно (имеется ввиду перемещение по статическим знакоместам, то есть через 8 точек). У меня было преимущество по сравнению с Light Force в том, что спрайты никогда не перемещались над фоном, так что мне не пришлось заниматься маскированием или затемнением фона черным цветом всех знакомест спрайта (как в более поздней игре Karnov от Electric Dreams) или на изменение цвета фона на цвет спрайта, чтобы в итоге они не торчали, как больной перевязанный палец (снова как в Karnov или в последних частях Light Force).

Я наткнулся на решение проблемы случайно, все потому, что я не умею рисовать, иначе мне пришлось бы потратить на это всю жизнь. Я решил для хранения карты уровня использовать плитку размером 4*4 символа, что лучше, чем просто посимвольно, так что к примеру, вместо секции размером 32*20 символов на карте, занимающей 640 байт, мой подход потребует только 40 байт — 32/4 * 20/4 каждый один из тех байтов, ссылающихся на плитку, сделанную из шестнадцати символов, что безусловно сохранило огромное количество памяти.

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

Конечно, там были большие промежутки между формами в плитке — это и был "секрет" отсутствия конфликта цветов, так происходит, когда есть промежуток величиной в один символ между двумя перемещающимся символами с различными цветами, когда невозможно переместить цветовой атрибут с одного знакоместа в другое. Ах, и конечно, это работает, если все ваши символы имеют общий атрибут "БУМАГИ" (включая и тот что является разделяющим буфером), сразу отбросив идею параллельно дублирующей фоновой прокрутки, отлично работающей в оригинале, в пользу черного цвета.

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

Японский рекламный материал IREM для R-Type, верхняя сторона


Задняя сторона, объясняющая основы системы управления


Реальным сердцем R-Type является попиксельно перемещающийся фон, а большинство спрайтов: корабли, чужие, пули, оружие и т. д. перемещаются на восемь пикселей через знакоместо (вернее атрибут) по его границе, чтобы спрайт был окрашен, используя атрибут ЧЕРНИЛА и черный цвет для атрибута БУМАГА, сливаясь со всем черным фоном.

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

Всё, что мне нужно было сделать дальше, так это предотвратить наложение спрайтов на фоновую графику и найти способ увеличить скорость работы, даже на этой первой стадии все работало очень медленно.

* * *

Оборудование, которое я использовал в этот раз, было таким же, как и для Rampage: стандартный Спектрум 48K с Интерфейсом 1 и микродрайвами и всеми любимое устройство для копирования или создания резервных копий: Romantic Robot’s Multiface 1. У меня была копия OCP Редактора\Ассемблера на микродрайве вместе с моим исходным кодом, и, нажимая на кнопку на Multiface, я мог получить из пустого Спектрума готовый к ассемблированию за несколько секунд, однако недостатком этого метода было то, что ассемблер был резидентной программой в памяти Спектрума, занимающий ценную оперативную память, которую я не мог использовать.

С приобретением немного большего опыта работы с Z80, полагаю, я мог бы работать с дополнительным, около 8K, ОЗУ, которое находилось в Multiface или методом соединения бинарных файлов, но ограничения памяти определенно вызвали уменьшения тех дополнительных возможностей, которые я хотел добавить в Rampage и я понял, что то же самое произойдет с R-Type.

Когда я заканчивал Rampage, то программисты Activision Зари (Zari) (ник ZZKJ) и Крис Вуд (Chris Wood) работали там над версиями Super Hang On используя Amstrad PCW 8256 с кросс-ассемблером для кодирования игры. Я кратко пообщался с ними: как все это в целом работает. Я помню, что читал статью в журнале, где Мэтью Смит (Matthew Smith) сказал, что использовал TRS-80 для разработки Manic Miner и некоторые части кода Tandy включили в финальную версию кода для Спектрума, но я никак не мог взять в толк, я имею ввиду в TRS-80 не было ничего похожего на Спектрум, как он просто отображал правильно экран? Разговаривая с Крисом и все прояснив, я понял, что мне нужно что-то похожее для R-Type и, поговорив с Кайтли, я получил Amstrad 6128, но он стоял долгое время без дела, пока я ждал прибытия дополнительного серийного интерфейса, прежде чем я смог бы на нем что-нибудь сделать.

В конце концов все утряслось и сейчас я мог ассемблировать на 6128 и посылать готовый код напрямую в Спектрум через разъем RS232C в Interface 1. Все, что для этого было нужно — это небольшой загрузчик в Спектруме, загружающий код. Но пока я ждал, когда же все оборудование приедет ко мне, я написал простые графические подпрограммы для игры.

* * *

Никто из нас даже предположительно не знал, как называют виды чужих, так что я сам присвоил им имена. Это позволило их легче идентифицировать, когда я снова натыкался на них позднее в уровнях и обычно имя точно описывало, какими они были: Красные Крутилки, Бабочки, Ходуны, Голубые Трансформеры, Кивающие Чужаки, Личинки, Ходуны с ракетами, Головастики, Мозг в Футляре. Это также все делало более легким при разговоре с Марком по телефону, например, упоминая Ползущих Детенышей было легче разобраться, чем "большие красные головастики, появляющиеся на восьмом уровне" и вскоре мы с ним общались и думали очень похоже.

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

У меня была простая система сжатия, которую я использовал для спрайтовых данных, и которая подбирала пустые байты и выбрасывала их, затем используя битовый флаг, чтобы восстановить отсутствующие данные, это не было грандиозно, но работало очень быстро, когда дело дошло до декомпрессии данных и это освободило немного так крайне необходимого места. Конечно, игра с восьмью индивидуальными уровнями должна была быть мультизагрузочной, так как без вариантов ее не уместить в 48К памяти (в реальности 40К за вычетом экранной области), а первый уровень, являющимся самым большим из восьми, был тем пределом, определяющим, сколько памяти я могу использовать для кода, а сколько для уровня.

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

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

Я нарисовал кучу прямоугольников где-то 3*2 дюйма на листе бумаги и, используя фотокопировальную машину, сделал дюжину копий. Я включил воспроизведение и ждал, пока чужой появится на экране, после чего ставил магнитофон на паузу, делал грубый набросок в одном прямоугольнике: как здесь выглядит фон, делал пометку маркером, откуда чужой появлялся и запускал видео. Затем я игнорировал все вокруг и просто наблюдал за шаблоном, который сделает чужой и пытался продублировать это на прямоугольнике пока он не вышел с экрана. В большинстве случаев чужой появлялся справа, летел по экрану и выходил слева, но иногда были некоторые взаимодействия с фоном, в этом случае я попытался записать все это максимально аккуратно и обычно использовал другой прямоугольник, чтобы пометить, в какой именно позиции был чужой и где в конце вышел за пределы экрана и таким образом правильно отмечал временные интервалы.

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


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


Телевидение Великобритании установило отображение экрана с частотой 50 кадров в секунду (в действительности это переплетение двух черезстрочных полей, создающее частоту в 25 кадров в секунду), для того, чтобы хоть что-то увидеть на ТВ, Спектрум имеет выходной видеосигнал с частотой в 50 кадров. Актуальная механика, промежутки времени, управление ULA и т. д. чрезвычайно сложны, и я никогда не понимал это тогда и не хочу понимать сейчас, поэтому я не собираюсь раскрывать тонкости обратного хода луча и падение скорости из-за "состязательной" памяти (когда видео подсистема компьютера и центральный процессор хотят прочесть ее одновременно), просто придерживайтесь идеи, что 50 раз в секунду Спектрум из "шприца" разбрызгивает экран, который телевизор может отобразить.

Спектрум имеет байт в памяти, который увеличивается на единицу при отображении экрана, 50 раз в секунду, чтобы ни случилось. Благодаря этому счетному байту мы имеем небольшое карманное устройство, которое позволяет нам сделать две вещи. Мы можем ждать, когда экран начнет отображаться, установив счетчик в ноль, можно выполнить некоторый код, просто прочитав значение счетчика снова и определив в значениях 1/50 секунды сколько времени это заняло, или мы можем подождать пока экран отобразится, установить счетчик в ноль, выполнить некоторый код, прочитать значение счетчика и ждать… и ждать… и ждать… пока мы достигнем нужного значения и затем мы знаем, что не имеет значения, как быстро или медленно выполняется код, этот и следующий: ИГРОВОЙ кадр будет занимать столько же времени.

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

В аркадной версии R-Type прокрутка одного экрана занимает чуть больше 12 секунд (время необходимое, чтобы переместить целый экран слева направо) и так как мой экран имел 240 точек с двумя пустыми полосками отступами по 8 пикселей слева и справа, чтобы скрыть края при прокручивании, простая математика дает нам результат: (12.5 секунд * 50 кадров в секунду) / 240 пикселей = 2.6 округляя вверх до 3. Поэтому, чтобы сделать похожую версию для Спектрума нужно успеть сделать все за 3/50 секунды, тогда скорость прокрутки и игры будут приблизительно такими же, как и у аркадной версии.

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

1. Очистить задний экран.

2. Декодировать данные плиток в соответствии со сдвигом пикселей, так что у вас уже есть движение.

3. Записать все данные о спрайтах на задний экран.

4. Переместить все содержимое из заднего экрана в основной так быстро, как это возможно, предпочтительно при кадровом обратном ходе луча ЭЛТ.

Это просто ужасно большой объем данных перемещаемых туда-сюда за несколько 1/50 секунд и, к сожалению, я не мог позволить себе роскошь работать с оригинальной концепцией, где я бы мог изменить такие вещи как: максимальное количество отображаемых спрайтов, разрешение экрана или сложность фона, просто, чтобы «пооткусывать» некоторое процессорное время. Вы можете обойти несколько из этих шагов и записывать непосредственно в главный экран, но вы обнаружите, что если вы не синхронизируете все по вертикальному обратному ходу луча, то ваша графика начинает бешено разрываться, вы также увидите неприятное мерцание экрана, когда графические данные будут стираться и перезаписываться у вас перед глазами.

Вы можете гнаться за сигналом укладываемым электронной пушкой ЭЛТ (или он будет гнаться за вами) и вы закончите наложение графики в середине, без разницы до или после того как она была записана, вызывая буквально разделение — вы можете хотеть установить строгую вертикальную линию на экране, но это будет иметь вид разрушенной палочки!

Каждый программист пытается найти способ, чтобы обойти эти четыре шага или минимизировать время, которое они занимают. Методы и техники, которые я в начале тщательно пробовал в процессе тестирования, чтобы поднять скорость работы, были далеко не уникальными, но все еще забирали много времени. При достаточном количестве времени вы можете совместить шаги 1 и 2 используя второй (!) задний экран, который хранит просто графику фона, готовую к прокрутке и когда вы обрабатываете прокрутку, вы перемещаете его на первый задний экран, автоматически перезаписывая и очищая от того, что здесь было ранее, но такое изобилие памяти было роскошью, которую я не мог себе позволить.

Я знал, что в общем будет происходить: там была БОЛЬШАЯ МАССА спрайтов, двигающихся повсюду, для проверки пришлось записывать довольно много фиктивных данных, когда я тестировал различные вещи и находил, что необходимо все больше и больше времени. Обычно вам сходят с рук некоторые задержки в игре, когда экран начинает заполняться (это было даже в версии аркадного автомата), но здесь все было почти наоборот, игра будет работать медленно большую часть времени из-за обилия спрайтов и ускоряться, когда ничего не происходит (имеется ввиду уменьшение количества спрайтов в данной игровой ситуации)!

Прокручивание целого экрана по одному пикселю при скорости 3/50 секунды на игровой кадр означает, что это займет 14 секунд, чтобы прокрутить целый экран, тогда как 4/50 займет 19 секунд, 5/50 24 секунды, 6/50 29 секунд и т. д. Вы должны придерживаться этого времени, так как это единственный способ получить регулярный ритм игры, в другом случае это приведет вас к увеличению или уменьшению скорости в зависимости от того, что происходит на экране и вы не сможете практически ничего с этим поделать. 29 секунд на прокрутку экрана — это просто смешно, 14 секунд были недостижимыми в принципе, что означает, что у меня практически не было выбора 4/50 или 5/50 в секунду на игровой кадр.

Подводя итог: вы можете писать все в задний экран в ОЗУ, а затем пытаться копировать на экран дисплея так быстро, как только возможно и вы получите прекрасный гладкий экран (при условии, что вы победите электронную пушку телевизора), но выполнение этого всего в два прохода съедает процессорное время и используемую память, что вы не можете себе позволить. Или вы можете писать непосредственно в память "скрестив пальцы", чтобы не получить глючный/мерцающий экран, но послушайте, это же быстро и тот кусок памяти, который вы собирались использовать под задний экран может быть использован для чего-то более важного, похожего на игровой код.

Я уточню последний абзац говоря, что для подавляющего большинства случаев задний экран — это идеальный способ реализации, подумайте о Pac-Man со статическим экраном и всего четырьмя спрайтами или игру, которая использует маскирующие спрайты, похожую на Rampage. В одном случае у вас много процессорного времени сделать то, что вы хотите, в другом это единственный способ получить желаемый эффект. В игре как R-Type, где экран постоянно прокручивается и содержит множество спрайтов, пуль и оружия, летающего по всему экрану практически безостановочно — это не тот случай, в котором есть выбор, здесь нет альтернативы, все должно напрямую писаться в главный экран, но даже используя этот метод, он работал слишком медленно. Я нацелился на 4/50-ых секунды на игровой кадр и, если бы я не смог придумать что-то радикальное, я был никогда не смог этого добиться.

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

Сердцем всего были два блока ОЗУ длиной в 640 байт, которые по сути являются картой обнаружения столкновения для игры, а 640 байт потому, что если вы посмотрите на главный экран дисплея размером 256*160 пикселей (и я имею ввиду область только для игровой прокрутки, не Очки/Лазер/Счетчик кораблей, линии под ним) тогда у вас будет актуальное атрибутное или разрешение по знакоместам 32*20, для простоты я назову ее "Карта столкновений 1". Есть еще и задний экран величиной 6912 байт, дублирующий главный экран, полностью включающий область атрибутов цвета, даже большую на 1 Кб чем мне было нужно, делающий адресацию экрана намного проще и представляющий удобный черновик при необходимости что-нибудь нацарапать в памяти. В течение моего тестирования с фиктивными данными я пришел к трем идеям, которые казались очевидными:


1. Какой смысл был в прокрутке пустых символов?

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

3. Если части двух спрайтов совмещаются в одних в тех же знакоместах, зачем тратить время на рисование того, что вы все равно не видите?


Перед стартом уровня плитки размером 4*4 символа, которые создают фон для одного укомплектованного экрана декодируются, а символы записываются в Карту Столкновений 1. Чтобы нарисовать укомплектованный экран, все, что мне нужно было сделать — это шагать по всей карте, побайтно за один раз, получать восемь байтов данных, которые соответствуют значению символа карты и записать их в корректную позицию на главный экран дисплея.

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

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

На данном этапе состояние игрового кадра от предварительно к окончательному:

* Фоновая графика есть только на главном экране дисплея Спектрума и больше нигде;

* Карта Столкновений 1 хранит фон, составленный как набор байтов, соответствующих позиции знакомест на главном экране. Если это ноль, значит нет фона в этом знакоместе.

* Карта Столкновений 2 содержит все спрайты, составленные аналогично Карте 1, но вместо главного экрана дисплея она указывает на данные, существующие во втором экране.

* Задний экран содержит все спрайтовые данные, которые будут перенесены в следующем кадре игры.

Как только спрайтовые данные были скопированы в главный экран, тогда и запускается игра и (обычно) для каждого нового кадра происходит следующее:

1) Фон прокручивается на один пиксель влево. Если ячейка прокручивается полностью, тогда атрибуты прокручиваются на одно знакоместо, Карта Столкновений 1 прокручивается на одну ячейку влево, новые значения вытаскиваются из плиток и записываются в крайне правую позицию, будучи готовым представить новый кадр. Просто, чтобы раскрыть процесс прокрутки: Карта Столкновений 1 сканируется построчно как горизонтальная полоса из продолжительных не нулевых ячеек и если находятся не пустые, то только они и прокручиваются. Как вы можете представить, это происходит довольно много раз за целый экран, но поскольку вы прокручиваете не пустые ячейки, это изрядно увеличивает скорость. Нормальная полноэкранная прокрутка просто потратит множество пустого времени перемещая пустые ячейки без причины.

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

3) Спрайты чужих перемещаются, их графические данные записываются в задний экран по одному символу, и соответствующая запись делается в Карте Столкновений 2 для каждого не нулевого символа в этом спрайте. Но, прежде чем это делать, происходит проверка с Картой 1, чтобы выяснить «если символ переместился над частью фона» и с Картой 2 «если символ уже был нарисован в этой позиции». Если после этих проверок возвращается ненулевое значение значит ничего не записывается, это предотвращает рисование спрайта над фоном или пустой траты времени на прорисовку данных, которые уже были нарисованы на заднем экране.

4) Игрок перемещает свой корабль и стреляет из своего оружия. Используя Карту Столкновения 1, мы можем проверить не столкнулся ли игрок с фоном, тогда как используя Карту Столкновения 2 мы можем проверить попал ли игрок или его оружие в спрайт и соответственно обработать это.

5) Карта Столкновения 2 сканируется вся побайтно за один раз, если значение равно нулю, то соответствующие знакоместа главного экрана заполняются нулём, перезаписывая любую графику из предыдущего кадра, ненулевое значение сигнализирует, что данные из заднего экрана должны быть использованы, снова перезаписывая графику.

Вот и все.

(Примечание переводчика: если я не ошибаюсь, то в пункте 5 должна учитываться также Карта 1, иначе фон сотрется в первом же кадре.)


Стартовый экран Спектрум версии. Все пристегнулись и готовы лететь?


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

Загрузка...