Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
290162d
physics: add cabinet oscillator primitives
freezy Jul 4, 2026
b9808c6
physics: wire keyboard nudge
freezy Jul 4, 2026
e964ae2
physics: add plumb tilt simulation
freezy Jul 4, 2026
3745ac8
input: expose native axis mappings
freezy Jul 4, 2026
1fcc38a
physics: add nudge sensor models
freezy Jul 4, 2026
7cd5b29
physics: expose nudge telemetry
freezy Jul 4, 2026
3052bd2
physics: add visual nudge offset
freezy Jul 4, 2026
d8dafff
physics: fix nudge review findings
freezy Jul 4, 2026
e376b48
input: default tables to simulation thread
freezy Jul 4, 2026
dbdfe89
physics: damp keyboard cabinet nudge
freezy Jul 4, 2026
670cef5
simulation: add nudge sensor calibration inspector
freezy Jul 4, 2026
24fb574
game: avoid direct play startup errors
freezy Jul 4, 2026
293248a
simulation: plot native input axes
freezy Jul 4, 2026
6173385
simulation: graph calibrated nudge axes
freezy Jul 4, 2026
a4ac289
simulation: add nudge sensor mount orientation
freezy Jul 4, 2026
a084f04
input: refresh device cache on native hotplug events
freezy Jul 4, 2026
6a69d20
physics: address nudge review comments
freezy Jul 4, 2026
f0369c5
input: update native input package
freezy Jul 4, 2026
01b1a94
doc: document nudge implementation
freezy Jul 4, 2026
1beea6a
editor: Expose nudge settings in physics and table inspectors.
freezy Jul 5, 2026
fc42eda
physics: Route nudge config through shared settings objects.
freezy Jul 5, 2026
22c0bd7
physics: Add table-owned tilt-bob switch device.
freezy Jul 5, 2026
bfa1cb4
tilt-bob: Author damping and threshold on the component.
freezy Jul 5, 2026
d05408f
tilt-bob: Rename Mapped mode to Physical and add inspector.
freezy Jul 5, 2026
680def4
editor: Don't pre-clamp raw value in mapped graph calculation.
freezy Jul 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions VisualPinball.Engine/Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,15 @@ public static class PhysicsConstants
public const float DefaultTableMaxSlope = 6.0f; // DEFAULT_TABLE_MAX_SLOPE
public const float DefaultTableGravity = 0.97f; // DEFAULT_TABLE_GRAVITY

public const float GravityConst = 1.81751f; // GRAVITYCONST

/// <summary>
/// trigger/kicker boundary crossing hysterisis
/// </summary>
public const float GravityConst = 1.81751f; // GRAVITYCONST

public const float MToVpu = 50f / (0.0254f * 1.0625f); // MTOVPU
public const float VpuToM = 1f / MToVpu; // VPUTOM
public const float Ms2ToVpuVpt2 = MToVpu * 1e-4f; // MS2TOVPUVPT2

/// <summary>
/// trigger/kicker boundary crossing hysterisis
/// </summary>
public const float StaticTime = 0.02f; // STATICTIME
public const float StaticCnts = 10f; // STATICCNTS

Expand Down Expand Up @@ -167,7 +171,11 @@ public static class InputConstants
public const string ActionCoinDoorUpDown = "Coin Door Up/Down";
public const string ActionSlamTilt = "Slam Tilt";
public const string ActionSelfTest = "Self Test";
public const string ActionLeftAdvance = "Left Advance";
public const string ActionRightAdvance = "Right Advance";
}
}
public const string ActionLeftAdvance = "Left Advance";
public const string ActionRightAdvance = "Right Advance";
public const string ActionLeftNudge = "Left Nudge";
public const string ActionRightNudge = "Right Nudge";
public const string ActionCenterNudge = "Center Nudge";
public const string ActionTilt = "Tilt";
}
}
2 changes: 1 addition & 1 deletion VisualPinball.Engine/VisualPinball.Engine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<PackageProjectUrl>https://visualpinball.org</PackageProjectUrl>
<PackageIcon>icon.png</PackageIcon>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<VisualPinballNativeInputVersion>0.0.4</VisualPinballNativeInputVersion>
<VisualPinballNativeInputVersion>0.0.5</VisualPinballNativeInputVersion>
</PropertyGroup>
<!-- Give an initial value based on the operating system where it's currently running on -->
<PropertyGroup Condition="'$(RuntimeIdentifier)' == ''">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
uid: tilt_bobs
title: Tilt Bobs
description: VPE can route tilt switch events from a simulated plumb bob or a real cabinet tilt bob.
---

# Tilt Bobs

A tilt bob is the table's tilt switch route. Add a `TiltBobComponent` when the
table should have a tilt switch that can be driven either by VPE's simulated
plumb bob or by a real cabinet tilt bob wired into the player's cabinet
controller.

VPX imports add a `TiltBobComponent` to the table root by default. Remove it if
the table should not have a tilt bob route.

## Setup

To add a tilt bob manually, select the table object or another object under the
table, click *Add Component*, and select *Pinball -> Mechs -> Tilt Bob*.

Use the [Switch Manager](xref:switch_manager) to map the game logic tilt switch
to the component's `Tilt Bob` switch item.

If a table does not have a `TiltBobComponent`, VPE does not simulate a plumb bob
for that table and does not pull the player's physical cabinet tilt switch. This
lets tables opt out by omission instead of by a hidden setting.

## Source

The player chooses the plumb source in cabinet/player settings:

| Source | What happens |
| --- | --- |
| `Simulated` | Cabinet acceleration swings VPE's simulated plumb bob. When it crosses the threshold, the `TiltBobComponent` sends its mapped switch. |
| `Physical` | The player's physical cabinet `Tilt` input drives the `TiltBobComponent`. Use this for a real tilt bob wired into a cabinet controller. |

This source is a player setting, not a table setting. The table only decides
whether a tilt-bob switch route exists and which game logic switch receives the
signal.

## Simulated Plumb Bob

For the simulated source, these `TiltBobComponent` fields shape how easily the
bob trips:

| Field | Lower value | Higher value |
| --- | --- | --- |
| `Plumb Threshold Angle` | Easier to tilt. | Harder to tilt. |
| `Plumb Damping` | Bob rings longer. | Bob settles faster. |

Test tilt with the same keyboard and sensor defaults you expect players to use.
Very strong nudging plus a low threshold can make a table tilt too easily. For a
real cabinet bob, test the physical source with the actual cabinet input binding.
126 changes: 126 additions & 0 deletions VisualPinball.Unity/Documentation~/creators-guide/manual/nudging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
---
uid: nudging
title: Nudging
description: How table authors configure nudge behavior and cabinet input defaults.
---

# Nudging

Nudging in VPE moves the virtual cabinet, not the ball directly. When the player
nudges, VPE computes cabinet acceleration and cabinet offset. The ball reacts to
that acceleration through physics, the camera/table can move visually, and the
table's plumb tilt component can tilt from the same movement when the table
author adds one.

As a table author, think about nudging in two layers:

- Table feel: how strong keyboard nudges are, how quickly the cabinet settles,
how much visual motion is shown, and whether the table has a tilt bob route.
- Player hardware: which real device and axes are mapped for a specific
cabinet.

The first layer belongs in your table defaults. The second layer usually belongs
to the player's cabinet or player app configuration.

## Table Defaults

The main table-level nudge settings live on the `PhysicsEngine` component.

| Setting | What it affects |
| --- | --- |
| `Keyboard Nudge Mode` | How keyboard/button nudges are converted into cabinet motion. |
| `Keyboard Nudge Strength` | Strength multiplier for keyboard/button nudges. |
| `Keyboard Cabinet Damping` | How firmly the cabinet settles after `CabModel` keyboard nudges. |
| `Visual Nudge Strength` | How much of the cabinet offset is shown visually. This is cosmetic. |

The `Keyboard Nudge Mode` setting has three choices:

| Mode | What it does | When to use it |
| --- | --- | --- |
| `PushRetract` | Applies the older VP-style push/retract pulse. It gives the ball a sharp kick, then quickly retracts the cabinet offset. | Use it only when a table was tuned around this older keyboard nudge feel. |
| `BoxModel` | Treats the table as a displaced box with a spring pulling it back to rest. It can visibly ring if the timing is long. | Use it when matching legacy VP behavior for a table that depends on that spring-style response. |
| `CabModel` | Applies a short cabinet impulse and lets the cabinet oscillator settle it. This is meant to feel like a sturdy cabinet shove rather than a long bounce. | Use it for new tables and for tables where keyboard nudging should resemble cabinet nudging. |

The `TableComponent` also has `NudgeTime`, imported from VPX table data. In VPE
this is used by the legacy `BoxModel` keyboard nudge path to set the spring
timing.

Use `CabModel` for new work unless you are matching an existing table's VP
behavior. It models a cabinet shove and a short return rather than a long visible
spring bounce. `PushRetract` and `BoxModel` are available for legacy VP-style
compatibility.

Higher keyboard cabinet damping makes the cabinet feel sturdier and settle
faster. Lower damping makes it ring more. If the table visibly bounces too many
times after one keyboard nudge, raise the damping or lower the visual strength.

## Visual Nudging

Visual nudge is only presentation. It moves the rendered table/cabinet in
response to the same cabinet offset used by the nudge model, but it does not add
extra physical force.

Keep visual strength modest. A little movement helps the player feel the nudge;
too much looks like camera shake and can make a physically reasonable nudge feel
wrong.

## Tilt

Tilt-bob routing and simulated plumb-bob tuning live on the
[`Tilt Bob`](xref:tilt_bobs) mechanism.

## Hardware Sensors

Hardware sensor mapping is handled by the `SimulationThreadComponent` nudge
sensor list and by the player app's cabinet input settings. These mappings are
specific to a cabinet, so avoid baking your personal KL25Z/Pinscape device ID
into a distributable table unless you are intentionally building a cabinet
profile for that setup.

Sensor types mean:

| Type | Use it for |
| --- | --- |
| `GamepadIntent` | Gamepad sticks or other analog controls where the player expresses "nudge this way". |
| `CabinetIntent` | A real cabinet sensor where motion should be interpreted as a nudge attempt. |
| `CabinetDirect` | A real cabinet sensor where measured motion should drive cabinet physics directly. |

Most Xbox-style controllers do not provide accelerometer data for nudging. Map
their sticks as `GamepadIntent`.

KL25Z/Pinscape boards are cabinet sensors. Map their acceleration axes, then use
mount rotation and mirror to match how the board is installed in the cabinet.
The available rotations are 0, 90, 180, and 270 degrees. Mirror flips the board X
axis before rotation.

## Editor Calibration

For direct play in the editor, use the `SimulationThreadComponent` inspector:

1. Enter Play Mode with the cabinet sensor connected.
2. Use auto-configuration if the first device should be mapped as the cabinet
sensor.
3. Set mount rotation and mirror until graph movement matches cabinet movement.
4. Keep the cabinet still and calibrate sensor centers.
5. Nudge the cabinet lightly and watch the input graph.

Calibration captures the current resting raw value as zero. It does not remove
spikes, pick better axes, or tune the overall gain. If the graph spikes while the
cabinet is still, check the mapped axes, increase dead zone, reduce scale, or
inspect the physical board/device signal.

## Shipping Tables

Ship table defaults that feel good without special hardware. A player should be
able to play with keyboard nudging alone, and cabinet owners should be able to
override sensor mappings from their own configuration.

Good release checks:

- Test keyboard nudging with the intended `Keyboard Nudge Mode`.
- Verify visual nudge is noticeable but not distracting.
- If the table has a tilt bob, keep or add a `TiltBobComponent`, map the tilt switch to
it, and verify it can tilt the table without tilting from ordinary play.
- If you include sensor defaults, confirm the table remains playable when those
devices are absent.
- Do not rely on a specific personal device ID for public tables.
12 changes: 8 additions & 4 deletions VisualPinball.Unity/Documentation~/creators-guide/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@
href: manual/displays.md
- name: Sound
href: manual/sound.md
- name: Nudging
href: manual/nudging.md
- name: Pinball Mechanisms
items:
- name: Troughs / Ball Drains
Expand All @@ -117,7 +119,9 @@
href: manual/mechanisms/score-reels.md
- name: Score Motors
href: manual/mechanisms/score-motors.md
- name: Collision Switches
href: manual/mechanisms/collision-switches.md
- name: Lifting Gates
href: manual/mechanisms/lifting-gates.md
- name: Collision Switches
href: manual/mechanisms/collision-switches.md
- name: Tilt Bobs
href: manual/mechanisms/tilt-bobs.md
- name: Lifting Gates
href: manual/mechanisms/lifting-gates.md
7 changes: 4 additions & 3 deletions VisualPinball.Unity/Documentation~/developer-guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,12 @@ This is the shared asset library. It keeps reusable content out of the engine re
Use it for reusable art content rather than engine or gameplay code.


## Future integrations
The developer guide also tracks design work for integrations that are not yet fully implemented in VPE. These pages are intended to capture architectural direction early, so implementation work across native input, runtime systems, and tooling can converge on the same design.
## Runtime architecture and future integrations

The developer guide also tracks runtime systems and design work for integrations that are not yet fully implemented in VPE. These pages are intended to capture architectural direction early, so implementation work across native input, runtime systems, and tooling can converge on the same design.

- [Packaging](xref:developer-guide-packaging-overview) documents the `.vpe` format, the export/import split, the renderer-agnostic material vocabulary, and the benchmarked optimization work around package loading.
- [Nudge System](xref:developer-guide-nudge-system) explains the current keyboard, sensor, visual nudge, and simulated plumb-bob runtime architecture.
- [Accelerometer Input Design](xref:developer-guide-accelerometer-input-design) covers analog nudge input, Open Pinball Device support, calibration, and how a future player app should participate in initial setup.
- [B2S Integration Design](xref:developer-guide-b2s-integration-design) proposes modernizing the upstream B2S runtime into a shared cross-platform core with a Windows COM shim, a native second-monitor host, and a Unity texture output for VR backglasses.
- [DOF Integration Design](xref:developer-guide-dof-integration-design) covers a Windows-first `DirectOutput` integration for the future player app and the later hybrid path toward a `libdof` backend.
Loading
Loading