Skip to content

Add on-screen touch controls - #25

Open
epic-ship-it wants to merge 1 commit into
ogdanimal:mainfrom
epic-ship-it:feature/touch-controls
Open

epic-ship-it wants to merge 1 commit into
ogdanimal:mainfrom
epic-ship-it:feature/touch-controls

Conversation

@epic-ship-it

Copy link
Copy Markdown

On-screen touch controls

The app is controller-only today, so a phone without a gamepad can't play it. This
adds a full N64 pad on the touchscreen: analog stick, A/B, the C diamond, L/Z/R,
Start, and a settings handle.

With a gamepad nothing changes, and the new Off mode is the existing behaviour.

How it works

The overlay presents itself as an extra SDL game controller: a button mask and an
axis array, merged inside controller_button_state() and controller_axis_state(),
the two functions every physical pad already goes through. That's 28 added lines in
input.cpp and nothing removed.

So every binding in Settings → Controls applies to the on-screen buttons, a rebind
can't detach them, they combine with a physical pad the way two pads do, and analog
camera, C-button masking and mods don't need changes.

  • The C cluster emits D-pad. Of C's three stock bindings it's the only one that
    covers all four directions (C-Right has no face button) and still works in
    analog-camera mode.
  • The menu toggle is event-driven while gameplay is polled, so the handle queues a
    real controller event. It opens and closes the menu and follows a rebind of
    Toggle Menu.
  • It's an Android View over SDL's SurfaceView, drawn as vectors, so the APK
    doesn't grow and the native build isn't involved in layout changes.

Settings

A new Touch tab, gated on touch_supported like the GPU Driver tab:

  • On-Screen Controls — Auto / On / Off. Auto shows the pad until a gamepad is
    used, brings it back on the next touch, and starts hidden if a gamepad is already
    attached.
  • Stick Sensitivity — the stick is about 9 mm across on a 450 dpi phone, so a
    linear response fits the whole walking range into about 4.5 mm. The magnitude is
    raised to a gamma (default 50 → 1.75). Full tilt is still reached at the rim.
  • Edit Layout — drag controls over the running game; tap one and use −/+ to
    resize it.

It's a separate tab because this menu's option list doesn't scroll by drag, so rows
below the fold on General can't be reached without a gamepad. Long-pressing the
handle opens size, opacity and vibration.

Tested

On an Adreno 650 device running Android 13, with Framebuffer Effects off per the
README's Adreno note:

  • buttons and stick drive the game; the default stick sensitivity allows walking
  • the handle opens and closes the menu, and the overlay hides while the menu is open
  • Off removes the overlay, Edit Layout works with Off selected, and layout changes
    persist
  • with no gamepad attached, the overlay starts visible

Not tested:

  • with a physical gamepad attached (auto-hide, starting hidden, touch and pad
    together)
  • other GPUs or Android versions
  • desktop builds (the tab is gated off and the input.cpp merge is Android-only)

The app has been controller-only, so a phone without a gamepad could not play
it. This draws a full N64 pad on the touchscreen: analog stick, A/B, the C
diamond, L/Z/R, Start, and a settings handle. With a gamepad nothing changes, and
the new Off mode is the existing behaviour.

Input. The overlay presents itself as an extra SDL game controller: a button
mask and an axis array, pushed over JNI and merged inside
controller_button_state() and controller_axis_state(), the two functions every
physical pad already goes through (28 added lines in input.cpp, nothing removed).
Every binding in Settings -> Controls therefore applies to the on-screen buttons,
a rebind cannot detach them, they combine with a physical pad the way two pads
do, and analog camera, C masking and mods need no changes. The SDL enum values
the Java side uses are static-asserted in android_touch.cpp, so an SDL
renumbering breaks the build instead of silently remapping buttons.

The C cluster emits D-pad: of C's three stock bindings it is the only one that
covers all four directions (C-Right has no face button) and survives analog
camera mode, which suppresses the right stick. The menu toggle is the exception
to the merge -- it is event-driven while gameplay is polled -- so the handle
queues a real controller event, which opens and closes the menu and follows a
rebind of Toggle Menu.

Drawing. A transparent Android View over SDL's SurfaceView, drawn as vectors, so
the APK does not grow and the native build is untouched by layout changes.

Settings. A Touch tab, gated on touch_supported like the GPU Driver tab:

- On-Screen Controls: Auto / On / Off. Auto shows the pad until a gamepad is
  used and brings it back on the next touch, and starts hidden if a gamepad is
  already attached at launch.
- Stick Sensitivity. On a 450 dpi phone the stick is about 9 mm across, so a
  linear response puts the whole walking range in roughly 4.5 mm of travel. The
  magnitude is raised to a gamma (default 50, i.e. 1.75); the rim still maps to
  full tilt at every setting, and only magnitude is shaped, not direction.
- Edit Layout: drag controls over the running game; tap one and use -/+ to size
  it. The C buttons move and size together.

It is a tab rather than more rows on General because the option list does not
scroll by drag, so rows below the fold cannot be reached without a gamepad.
Mode and sensitivity are stored in the game config; the layout, size, opacity
and vibration (long-press the handle) are stored per device.

Adds the VIBRATE permission; without it the first haptic press throws.

Verified on an Adreno 650 device running Android 13, with Framebuffer Effects
off per the README's Adreno note: buttons and stick drive the game, the handle
opens and closes the menu, the overlay hides while the menu is open, Off removes
it, Edit Layout works with Off selected, and layout changes persist. Not yet
verified with a physical gamepad attached.
@epic-ship-it

Copy link
Copy Markdown
Author

@ogdanimal hey man, love your android fork, i added on-screen touch controls so i could play on my phone

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant