PORTCLUB
Cabecera de JumpyBall
Port nativo

JumpyBall

Port nativo de JumpyBall para PC.

JumpyBall

Port nativo basado en su ficha de origen.

README del repositorio

jumpyball-decomp

Порт игры JumpyBall (Windows Mobile / Pocket PC, экран 240x320) на C89. Хост-слой сменный: SDL2 (Windows, Linux, Android) или нативный Win32 API (Windows и Windows CE, GDI + waveOut, вообще без SDL2).

Логика восстановлена реверс-инжинирингом оригинальных JumpyBall.exe и hss.dll. Код порта - собственный; из оригинальной поставки в репозиторий входят только ассеты (BITMAP, Sounds, Musics), без бинарников и декомпилированных исходников.

Что реализовано

  • Псевдо-3D трасса с построчной проекцией, пять тем оформления
  • Физика мяча, прыжок (в том числе автопрыжок), респавн
  • Уровни, разблокировка, таймер и HUD оригинальным шрифтом
  • Меню: главное, выбор уровня, настройки, «о программе»
  • Настройка управления: мастер переназначения шести клавиш с сохранением в keys.cfg
  • Звук: WAV-эффекты и музыка .tkm (4-канальный ProTracker M.K.) собственным плеером в jb_mod.c / jb_mod_effects.c

Сборка

Код - ANSI C (C89). Нужен компилятор C и, для бэкенда по умолчанию, SDL2.

CMake (Windows, Linux, куда угодно)

cmake -S . -B build-cmake -DCMAKE_BUILD_TYPE=Release
cmake --build build-cmake

SDL2 ищется тремя способами по очереди: find_package(SDL2 CONFIG), find_package(SDL2), затем pkg-config sdl2. Если SDL2 лежит в нестандартном месте, передайте -DCMAKE_PREFIX_PATH=<префикс sdl2>; для vcpkg - -DCMAKE_TOOLCHAIN_FILE=<vcpkg>/scripts/buildsystems/vcpkg.cmake. BITMAP, Sounds и Musics копируются рядом с бинарником после сборки (отключается -DJUMPYBALL_COPY_ASSETS=OFF).

На этой машине конфигурация с готовыми путями лежит в build-cmake.cmd.

Проверка на строгий C89

tools\c89check.cmd прогоняет все .c через clang (тот, что идёт с Visual Studio Build Tools) с -std=c89 -pedantic-errors -Wall. Компоновки нет - это проверка того, что код не опирается на расширения MSVC и соберётся другим компилятором, в том числе gcc/clang под Linux.

jb_platform_win32.c и jb_audio_win32.c из этой проверки исключены: они тянут windows.h, а заголовки SDK сами по себе не C89 (inline, long long, безымянные union), так что -pedantic-errors срабатывает внутри SDK, не доходя до нашего кода. Сам код этих двух файлов - тот же C89.

MSVC напрямую

Пути к MSVC и SDL2 заданы в начале build.cmd:

set VCVARS=D:\VS\BuildTools\VC\Auxiliary\Build\vcvars32.bat
set SDL=D:\vcpkg\installed\x86-windows

Поправьте их под свою машину и запустите:

build.cmd

Результат - build\jumpyball.exe вместе с SDL2.dll и ассетами.

Нативный Windows / Windows CE (без SDL2)

Весь платформенно-зависимый код сходится в одном заголовке jb_platform.h, поэтому кроме SDL2-бэкенда есть второй, нативный: jb_platform_win32.c (окно, ввод и вывод кадра через GDI) и jb_audio_win32.c (звук через waveOut). SDL2 при этом не нужен вообще - линкуются только gdi32, user32 и winmm. Выбирается опцией -DJUMPYBALL_BACKEND=win32 (по умолчанию sdl2):

cmake -S . -B build-win32 -DCMAKE_BUILD_TYPE=Release -DJUMPYBALL_BACKEND=win32
cmake --build build-win32 --config Release

Кадр рисуется в DIB-секцию 16bpp RGB565 (CreateDIBSection с BI_BITFIELDS, сверху вниз) и выводится в окно через BitBlt, а при масштабе больше 1 - StretchBlt. Это тот же путь, что у оригинала через GAPI, только буфер отдаёт GDI, а не драйвер экрана. Звук - четыре голоса WAV и музыка .tkm, смешанные своим микшером и отданные в waveOut отдельным потоком-кормильцем; свой разбор RIFF заменяет SDL_LoadWAV.

Кросс-сборка с Linux - mingw-w64:

sudo apt-get install gcc-mingw-w64-i686
sh tools/build_win32.sh

Для 64 бит - MINGW_PREFIX=x86_64-w64-mingw32 sh tools/build_win32.sh. Скрипт зовёт CMake с tools/toolchain-mingw-w64.cmake; результат - build-win32/jumpyball.exe, запускается и под Wine.

Windows CE

Для Windows CE нативный бэкенд - единственный вариант: SDL2 под CE нет. Собирается cegcc / mingw32ce:

CEGCC=/opt/mingw32ce TARGET=arm-mingw32ce sh tools/build_wince.sh

TARGET - arm-mingw32ce или i386-mingw32ce. Готовый каталог build-wince/ копируется на устройство целиком (например в \Program Files\JumpyBall): игра ищет BITMAP / Sounds / Musics рядом с собой. Из зависимостей у неё только coredll.dll.

Отличия ветки CE собраны под макросом JB_WINCE (jb_platform.h):

  • окно всегда во весь экран (WS_POPUP), масштаб подбирается автоматически; панель задач и кнопка SIP убираются через SHFullScreen, который берётся из aygshell.dll динамически - на образах без неё игра просто работает как есть
  • у CE только широкий API, поэтому все вызовы в бэкенде - ...W, а узкие строки расширяются на входе; в путях / заменяется на \
  • у CE нет окружения процесса и getenv в coredll, поэтому переменная JUMPYBALL_ASSETS там не читается
  • собирается как gnu89, а не строгий c89: inline используется в kfuncs.h самой cegcc

Android (APK)

tools/android_prepare.sh собирает дерево Gradle в build-android/: скачивает исходники SDL2 release-2.32.10, раскладывает шаблон android-project, копирует в него jb_*.c / jb_*.h и ассеты в app/src/main/assets. Нужны JDK 17 и Android SDK с NDK (путь берётся из ANDROID_NDK_HOME / ANDROID_NDK_ROOT).

sh tools/android_prepare.sh
cd build-android && ./gradlew assembleDebug

Готовый APK - build-android/app/build/outputs/apk/debug/app-debug.apk, универсальный: в одном файле лежат ABI armeabi-v7a, arm64-v8a, x86, x86_64; minSdk 21, ориентация портретная. Ассеты читаются прямо из APK через SDL_RWops, а keys.cfg пишется во внутреннюю память приложения.

Game Boy Advance

У GBA нет ни SDL2, ни файловой системы, поэтому здесь свой нативный бэкенд (jb_platform_gba.c) и ассеты всегда вшиты в ROM (JB_EMBED, tools/gen_embed.py -> jb_embed_data.c). Собирается devkitARM:

sh tools/build_gba.sh

Результат - build-gba/jumpyball.gba, самодостаточный: грузится в эмулятор (mGBA) или прошивается на картридж. По умолчанию тулчейн ищется в /opt/devkitpro; переопределяется через DEVKITARM / DEVKITPRO.

Экран GBA - 240x160, а игра портретная 240x320, поэтому кадр рисуется в режиме Mode 3 (линейный BGR555-фреймбуфер) с уменьшением x0.5 по обеим осям в центр экрана; по бокам остаются чёрные поля. Время идёт от каскада Timer2/Timer3 (16384 Гц). Управление: крестовина - движение, A - прыжок, START - меню.

Звук на этом этапе выключен: jb_audio_gba.c - честная заглушка (Platform_AudioInit возвращает 0, дальше Audio_Init сам не грузит сэмплы). Настоящий звук через DirectSound (DMA-FIFO по таймеру) - следующая веха.

Сборки в CI

.github/workflows/build.yml собирает и прогоняет игру на семи конфигурациях: Linux x86_64 и arm64 (плюс проверка на строгий C89), Windows x86 и ARM64 (обоими бэкендами - SDL2 и нативным), кросс-сборка нативного бэкенда mingw-w64 с прогоном под Wine, Android APK, Windows CE (cegcc) и GBA ROM через devkitARM. Настольные сборки проверяются выгрузкой кадра в headless-режиме - файл обязан быть ровно 2403202 байта, - APK проверяется на наличие libmain.so / libSDL2.so для всех четырёх ABI и ассетов внутри архива, а .gba - на штамп заголовка (логотип Nintendo на смещении 0x04) и размер (вшитые ассеты дают большой ROM).

Управление

По умолчанию: стрелки - движение, Space - прыжок, Escape - меню. Переназначить можно в «Настройки» -> «Управление»: мастер по очереди просит нажать клавишу для «влево», «вправо», «вверх», «вниз», «прыжок» и «меню»; уже занятая клавиша не принимается.

На Android управление сенсорное: под кадром игры рисуется панель с крестовиной, кнопкой прыжка и кнопкой меню, работает мультитач (например «вправо» и «прыжок» одновременно). Размер кнопок считается от размера экрана, поэтому панель одинаково умещается и на маленьком, и на большом устройстве. Аппаратная кнопка «Назад» выходит из игры. Ту же панель можно посмотреть на десктопе - переменная окружения JUMPYBALL_TOUCH=1.

Раскладка пишется в keys.cfg рядом с исполняемым файлом - шесть десятичных кодов клавиш SDL, по одному на строку, в том же порядке. Это сознательное отступление от оригинала: тот хранил keys.dat / keys2.dat с кодами VK в кодировке «база 1000 + смещение 100», а коды VK не совпадают с кодами SDL, так что переносить оригинальный формат было бы бессмысленно. Файл с непривязанной или повторяющейся клавишей отбрасывается, и берутся значения по умолчанию.

В нативном бэкенде формат keys.cfg тот же, но коды в нём - VK (VK_LEFT, VK_SPACE и так далее), как в оригинале, а не коды SDL. Два файла между бэкендами не переносятся. Сенсорной панели в нативном бэкенде нет: она нарисована через SDL_Renderer в jb_touch_sdl2.c, а у КПК под управление есть свои аппаратные клавиши.

Чекпоинты

Чекпоинты берутся из битмапов уровней: чисто красный пиксель (RGB 255,0,0) в BITMAP/309.bmp, 333.bmp, 334.bmp - это чекпоинт. Загрузчик карты пишет их столбец и строку в таблицы, начиная с индекса 1, а респавн после падения ставит мяч в последний чекпоинт, пройденный раньше текущей позиции камеры.

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

Ассеты

BITMAP, Sounds и Musics лежат в репозитории и копируются в build\ при сборке. Игра ищет их рядом с исполняемым файлом; путь можно переопределить переменной окружения JUMPYBALL_ASSETS.

Аргументы командной строки

АргументЗначение
--level=Nстартовать сразу в уровне N
--screen=Nстартовый экран меню
--index=Nстартовая позиция в меню
--unlocked=Nсколько уровней открыто
N (число)масштаб окна
путьвыгрузить кадр (RAW 16bpp) и выйти

tools/

modtest.c - офлайн-проверка музыкального плеера: рендерит .tkm в WAV и печатает peak/RMS и длительность, без звуковой карты. Сборка - tools\modtest.cmd, запуск - modtest.exe <in.tkm> <out.wav> [volume] [loop].

c89check.cmd - проверка на строгий C89 (см. раздел «Сборка»).

build_win32.sh - кросс-сборка нативного (без SDL2) jumpyball.exe через mingw-w64, build_wince.sh - то же для Windows CE через cegcc, build_gba.sh - сборка GBA ROM через devkitARM, toolchain-mingw-w64.cmake - файл тулчейна CMake, которым пользуется первый из них.

android_prepare.sh - сборка дерева Gradle для APK (см. раздел «Сборка»).

Модификация уровней.

В игре есть всего три уровня в котором используются разные BITMAP. Так вот можно сами уровни редактировать используя Paint или другие редакторы. В основном уровни редактируются легко, 309.bmp, 333.bmp, 334.bmp это первый, второй, третий уровень. Их значения: черный - место где можно катать шарик, белый - вода, трава, по которому нельзя катать, красный - чекпоинт

Comentarios (0)

Inicia sesión para dejar un comentario.

Sé el primero en comentar sobre este juego.