Skip to content

Menu and controls

Владислав edited this page Sep 5, 2026 · 1 revision

Меню и управление

Меню - это не отдельная программа и не «состояние конечного автомата» в современном смысле. В оригинале это две глобальные переменные: g_appMode (0x00026340, 0 - игра, 1 - меню) и g_screen, номер экрана. Порт держит их в jb_mode и jb_menu.screen_id.

Четыре экрана и дырка в нумерации

Экран screen_id Пункты
главный 0 Play · Settings · About · Exit
выбор уровня 1 Level 1 · Level 2 · Level 3 · Back
About 2 нет кнопок, десять строк текста
настройки 4 Sound · Auto-Jump · Controls · Back

Тройки в нумерации нет, а настройки - четвёрка: так было в оригинале (Menu_DrawFrame 0x0001a7d0), и порт не «нормализует» это. Пунктов на каждом экране ровно четыре, индекс крутится по кругу 0..3.

Что рисуется всегда

DrawChrome собирает раму из пяти блитов, и порядок важен:

  1. фон меню (g_backdropMenu 0x00061b48) без ключа;
  2. тонкая полоска, размноженная по всей высоте 0x140 шагом 10;
  3. заголовок - в раскладке 176x220 берётся из src (0x32, 0x14) высотой 0x3c, иначе целиком высотой 0x4d;
  4. панель-градиент по низу, view_h - 0x30;
  5. логотип PocketNew - маской, тинтом 0xff,0xff,0xff в точке view_center_x - 0x57, 0x11e.

Кнопки (DrawButtons) - узкая для каждого пункта шириной 0xa0 - (layout_mode >> 1) и широкая для выбранного шириной 200 - layout_mode со сдвигом src_x 10. На экране About не рисуются вообще. Выбранный пункт дополнительно сдвигается по X: (index == i) * 0x10 + 0x23.

Замок на уровнях - это цвет, а не запрет

Заблокированный уровень нарисован, выбираем его свободно, просто он тусклый:

n[0] = 1;
n[1] = (max < 1) ? max : 1;
n[2] = ((max < 0) ? max + 1 : max) >> 1;
n[3] = 1;
/* цвет: r = (n + 1) * 0x7f, g = b = (n + 1) * 0x7d */

При max_unlocked 0 второй и третий уровни получают n = 0, то есть цвет (0x7f, 0x7d, 0x7d) вместо (0xfe, 0xfa, 0xfa) - ровно вдвое темнее. Запрет живёт отдельно, в Confirm: index <= max_unlocked. Странная арифметика с max < 0 - это >> над знаковым числом в оригинале; порт повторяет её буквально, хотя отрицательным max_unlocked быть не может.

Настройки

  • Sound - «подтвердить» на этом пункте прибавляет громкость, «влево» убавляет (Audio_VolumeStep(±1)), см. Audio-and-TKM. Полоска рисуется шириной vol * 2, при этом src_x равен (0x20 - vol) * 2 - полоска не растягивается, а выезжает из спрайта.
  • Auto-Jump - текст пункта меняется на месте: Auto-Jump [ ] / Auto-Jump [X], значение 1 - auto_jump. Это тот самый флаг, из-за которого мяч на краю трассы либо подпрыгивает, либо падает - см. Physics.
  • Controls - запускает мастер переназначения (ниже).
  • Back - на главный экран.

About

Десять строк с жёстко прошитыми координатами и выравниванием, цвет (0,0,0). Здесь же авторство оригинала: Coder : Osaris, using Hekkus Sound System, Graphics : Team PocketNew, тестеры Kisswert, FMARC, и www.pocketnew.net. Кнопок нет, поэтому Step() принудительно держит index = 3, а любое «подтвердить» уводит на главный экран.

Шесть действий

Игра знает не клавиши, а шесть действий (jb_platform.h), и порядок этого перечисления - контракт: по нему пишется и читается keys.cfg.

# Действие По умолчанию В меню В игре
0 LEFT SDLK_LEFT назад / убавить громкость разгон влево
1 RIGHT SDLK_RIGHT подтвердить разгон вправо
2 UP SDLK_UP пункт выше вперёд
3 DOWN SDLK_DOWN пункт ниже тормоз
4 JUMP SDLK_SPACE подтвердить прыжок
5 MENU SDLK_RETURN - выход в меню

«Подтвердить» - это и RIGHT, и JUMP: оригинал считал подтверждением g_gxKeyStart, g_keyRight, g_gxKeyRight, g_gxKeyA, g_gxKeyB, g_gxKeyC и g_keyJump сразу, то есть все аппаратные кнопки КПК плюс «вправо». «Отмены» как таковой нет: её роль играет LEFT на вложенных экранах.

Опрос - по фронтам, не по состоянию (PumpKeys в jb_main.c): нажатие обрабатывается только когда held != jb_key_prev[k]. В меню отпускания игнорируются целиком, в игре они идут в Player_KeyUp - именно там ставятся флаги *_released, на которых висит торможение (см. Physics).

Мастер переназначения

KeyConfig_Begin обнуляет все шесть привязок и включает режим, в котором кадровый цикл больше ничего не делает - все нажатия уходят в KeyConfig_KeyDown, шаг за шагом. Проверка одна: код, уже занятый другим действием, отбрасывается и шаг не двигается. Дошли до шести - привязки сохраняются в keys.cfg.

Экран мастера рисуется тремя блитами из одного спрайта-полосы:

x = (view_w - 0xb0) / 2;                         /* с поправкой на отрицательное */
Blit(..., x, 0xf,            0xb0, 0x2a, panel, 0,               0);
Blit(..., x, view_center_x + 0x14, 0xb0, 0x19, panel, step * 0x19 + 0x2f);
Blit(..., x, view_h - 0x14,  0xb0, 0x14, panel, 0xde);

Средняя полоса - подсказка текущего шага: шесть кусков по 0x19 = 25 пикселей, начиная с 0x2f = 47. Обратите внимание на view_center_x + 0x14 в координате Y - это не опечатка вики, а буквальный перенос оригинала.

keys.cfg

Шесть десятичных кодов SDL, по одному в строке, в порядке таблицы выше. Файл лежит рядом с Platform_PrefPath(). Загрузка недоверчивая: если любой код равен нулю (не привязан) или совпадает с другим, файл отбрасывается целиком и остаются значения по умолчанию. Частично применённой раскладки не бывает - это защита от файла, после которого игрой нельзя управлять.

1073741904
1073741903
1073741906
1073741905
32
13

Сенсор

Сенсорная панель - добавление порта, в оригинале её нет (там КПК с аппаратными кнопками). Живёт в jb_touch_sdl2.c и знает только те же шесть действий.

Раскладка считается от размеров окна, а не от жёстких координат:

cell   = min(win_w, win_h) / 7;
if (cell > win_h / 9) cell = win_h / 9;
margin = cell / 4;
side   = cell + cell / 2;      /* кнопка прыжка в 1.5 раза больше */
pad_h  = 3 * cell + 2 * margin;
view_h = win_h - pad_h;

Кадр игры вписывается в остаток по высоте с сохранением пропорции 240x320: сначала по ширине окна, и если не влезло - по высоте. Крестовина слева внизу, прыжок справа, меню - маленькая кнопка над прыжком.

Мультитач честный: до восьми пальцев, каждый помнит свой SDL_FingerID и свою кнопку, SDL_FINGERMOTION переназначает кнопку под пальцем (можно проскользить с «влево» на «вправо» не отрывая палец), а состояние кнопок пересобирается из списка пальцев целиком, а не инкрементально - поэтому потерять «залипшую» кнопку невозможно.

Рисуется панель уже после копирования кадра в окно, средствами SDL_Renderer: прямоугольник, рамка, и шеврон из трёх точек (у меню - три полоски). Нажатая кнопка подсвечивается 0x60,0x90,0xd0. Из-за этого порядка панель не попадает в дампы кадров - см. Build-and-CI.

Clone this wiki locally