Pull to refresh

Реверс-инжиниринг арканоида DX-ball, или Новая жизнь старой игры

Reading time4 min
Views34K
Поздравить всех хабравчан с неофициальным днем компьютерной графики! В этот день я хочу рассказать вам о том как я сделал онлайн версию старой игры.

Возможно многим знакома игра DX-Ball, Я играл в нее еще в дошкольном возрасте, а уже в школе коротал за ней уроки информатики. Поэтому мне было интересно делать ее на HTML5.



Немного о работе

Я не буду приводить здоровые куски кода, и объяснять как что работает, я расскажу о там, как я разбирал эту игру, а о самой игре скажу лишь, то, что она сделана только на canvas'е. Я хотел сделать ее максимально похожей на оригинальную, и оставить как можно больше файлов без изменения, единственное что изменилось, так это список рекорд — он стал «бесконечным».
В начале задумывалось перерисовывать только те элементы котором изменяются, но из за большого количества багов, которые возникали в связи с этим, я остановился на варианте полной перерисовки кадра. И несмотря на то что игра может растягивается на весь экран, ее разрешение всегда остается 640x480px, впрочем как и в оригинале.

Разберем состав игры:

фалы *.pcx — это растровые фоны игры такие как начальная заставка с описанием бонусов, и финальный «High Score». я не стал их разбирать, но об устройстве PCX можно почитать в интересной серии статей, тут же на хабре.
*.mds — MIDI файлы музыки, сконвертировать их в *.mp3 мне помог savex.
В файле Default.bds хранится информация о расположении кирпичей на всех 50 уровнях
На одном уровне 202 кирпичей, которые записываются побайтно в этот файл.
От этого и получается 202×50 = 20 КБ
*.sbk — файлы растровых шрифтов, и остальной графики (кирпичи, ракетки и др.)
Информации о том как устроен этот файл я негде не нашел, поэтому пришлось разбираться самому, и вот что я выяснил:
Файлы этого типа содержат в себе что то вроде этого:

Графическое отображение Sysfont.sbk
изображение кликабельно.
Структура этого файла немного сложнее чем Default.bds, в нем по очереди описываются символы,
Первые 4 байта файла — это заголовок файла, он содержат в себе информацию о том сколько символов (изображений) содержит в себе файл.

После заголовка идет последовательное описание символов (изображений), как показано на скриншоте файл Sysfont.sbk содержит 94 символа. Ширина и высота первого символа указанны в 4'ом и 8'ом байтах. 12'ый байт — это номер символа из таблицы ASCII, 0x41 = A, если он равен 0x00, то это не символ, а какая то картинка. Далее идут еще несколько байтов, в нашем случае 130 (13×10), начиная с 17'ого байта — это и есть растр символа (на рисунке обозначено зеленым). Затем все это повторяется еще 93 раза (начиная с байта означающего ширину символа).

Изображения (символы) отрисовываются снизу вверх, слева направо 1 байт = 1 пиксель, значение байта — это номер цвета.
Как я понял, в игре используется 2 цветовых режима, первый используется в самой игре, а второй только в заставке.
вот 2 схемы, каждый цвет имеет 2 номера, верхний — это номер цвета в Dec, а нижний в Hex:


Вот пример первых 3-х символов файла Sysfont.sbk с использованием первой схемы:


Ах да, ноль в обоих таблицах это прозрачный цвет, а цвета в первой схеме начиная с 224 по 231 — динамические, то есть смещаются на один цвет каждый кадр, что бы образовать вот такую анимацию image

Но тут возникает проблема, некоторые символы, такие как qypgj должны находится ниже остальных а апострофы и другие знаки должны быть выше, но так, как все символы имеют разный размер, они выравниваются по низу.



Для решения этой проблемы существует специальный байт, идущие после обозначения символа, (на первом скриншоте он подчеркнут синем).
У символов gj этот байт равен 0xFD = 253. а у ^' этот байт равен 0x08 = 8. Это как раз и есть смещение символа относительно остальным, но почему же вместо отрицательного смещения такие большие числа? Дело в том, что таков вид записи отрицательных чисел, в одном байте 128 отрицательных и 128 положительных чисел. Если наш байт меньше 128, то мы его не трогаем, а если больше, мы просто вычитаем из него 256.
И получаем превосходный результат:


Перед запуском игры все изображения (символы) отрисовываются в том же канвасе, что и игра, я сохраняю их как картинки,
то есть: char[...].img.src = canvas.toDataURL("image/png");
Так как putImageData() гараздо медленнее чем drawImage() и это не единственный минус.
putImageData, не накладывает изображение сверху, а заменяет его полностью.
image
В процессе разбора игры я обнаружил два секретных бонуса, которые не используются в оригинальной игре :-)

не используемые бонусы

Вся анимация в игре оптимизирована с помощью requestAnimationFrame, но разные устройства выдают разные показатели FPS. Для того чтобы мяч летал с одинаковой скоростью не в зависимости от fps я умножил скорость мяча на коэффициент delta который рассчитывался по следующей формуле: delta = 1000/fps/60;, мой ноутбук успевал отрисовывать около 55 кадров в секунду, но периодически зависал, и проглатывал более 30 кадров за раз, из за этого зависания коэффициент delta рассчитывался не верно и мяч приобретал не контролируемую скорость, чтобы от от этого избавится я решил усреднять fps за 4 секунды, поэтому он так редко обновляется.

В предыдущей игре Doodle Jump я дал пользователям возможность вставить ее iframe на любой сайт, в результате чего свыше 7000 пользователей ежедневно играли в эту игру на сторонних сайтах совершенно разной тематики, от личных блогов до звукозаписывающих студий.
Поэтому и в DX-ball я не отнимаю такой возможности, более того игра гибко настраивается для вставки на сайт.

Вроде все, если на ваш взгляд я что нибудь не до рассказал, задавайте вопросы, я обязательно отвечу.

Ссылка на игру: DX-Ball.ru

P.S. Игра еще сыровата, в ней возможны баги и зависания, так что буду благодарен, если вы напишите о недочетах в комментариях.
Tags:
Hubs:
Total votes 75: ↑68 and ↓7+61
Comments65

Articles