Adding Manual Ball Control to your VPX Table

This script provides an easy way to take manual control of a ball using the arrow keys.  Ball control for testing or table demonstrations is an often requested feature.  This simple script should meet most of the needs for those requesting this functionality.  Suggestions or additions to this script are welcome!

Download the demo table and instructions here:

Steps to add manual ball control to your VPX table:

1) Add a new timer to your table in the editor. Name the timer BallControl, check Enabled, and set Timer Interval = 1.

2) Add a new trigger to the ball shooter lane called “StartControl” or copy the “StartControl” trigger from the demo table.

3) Add a new trigger just above the drain called “StopControl” or copy the “StopControl” trigger from the demo table.

4) Add the following code inside the Sub Table1_KeyDown subroutine:

if keycode = 46 then ' C Key
     If contball = 1 Then
          contball = 0
          contball = 1
     End If
End If
if keycode = 48 then 'B Key
     If bcboost = 1 Then
          bcboost = bcboostmulti
          bcboost = 1
     End If
End If
if keycode = 203 then bcleft = 1 ' Left Arrow
if keycode = 200 then bcup = 1 ' Up Arrow
if keycode = 208 then bcdown = 1 ' Down Arrow
if keycode = 205 then bcright = 1 ' Right Arrow

5) Add the following code inside the Sub Table1_KeyUp subroutine:

if keycode = 203 then bcleft = 0 ' Left Arrow
if keycode = 200 then bcup = 0 ' Up Arrow
if keycode = 208 then bcdown = 0 ' Down Arrow
if keycode = 205 then bcright = 0 ' Right Arrow

6) Add the following code outside of any other subroutine for function:

Sub StartControl_Hit()
     Set ControlBall = ActiveBall
     contballinplay = true
End Sub

Sub StopControl_Hit()
     contballinplay = false
End Sub

Dim bcup, bcdown, bcleft, bcright, contball, contballinplay, ControlBall, bcboost
Dim bcvel, bcyveloffset, bcboostmulti

bcboost = 1 'Do Not Change - default setting
bcvel = 4 'Controls the speed of the ball movement
bcyveloffset = -0.01 'Offsets the force of gravity to keep the ball from drifting vertically on the table, should be negative
bcboostmulti = 3 'Boost multiplier to ball veloctiy (toggled with the B key)

Sub BallControl_Timer()
     If Contball and ContBallInPlay then
          If bcright = 1 Then
               ControlBall.velx = bcvel*bcboost
          ElseIf bcleft = 1 Then
               ControlBall.velx = - bcvel*bcboost
          End If

         If bcup = 1 Then
              ControlBall.vely = -bcvel*bcboost
         ElseIf bcdown = 1 Then
              ControlBall.vely = bcvel*bcboost
              ControlBall.vely= bcyveloffset
         End If
     End If
End Sub

7) Usage:

  • The “C” key toggles ball control. Press once to capture the ball. Press again to release the ball.
  • The “B” key toggles speed boost. Press once to enable the speed boost. Press again to disable the speed boost.
  • Use the arrow keys to move the ball around the table.



  1. freelunch

    I’ll have to give this a go sometime. I figured out how to abuse tilting variables awhile back, but the downside was I had to reset the settings every time for normal tiliting behavior.

  2. TerryRed

    This works a treat! I’ve been using this to add DOF addressable leds MX commands to DOF Config Tool for some tables, and this makes it so much easier. While not the same as compared to say… FP’s Manual Ball Roller… (some things like Slings won’t trigger with this ON), it does make testing much much easier!

    I do notice that some tables might crash with this enabled at the same time as certain table actions occuring . Tron Legacy Arcade scoop crashes the table with this enabled as an example.


    • avatar
  3. TerryRed

    Best you can do is disable it before entering the scoop, and then drain the ball to Stop ball controller “should” allow it to work after Starting Ball Controller again.,

  4. rothbauerw Post author

    I’m assuming the ball is being destroyed in the scoop? This can cause issues with this script. I never create or destroy balls in my tables (except at start up). There really should no longer be a need to destroy a ball. Or you can follow Terry’s suggestion.

    • avatar
  5. fusionwerks

    That makes sense that i would get that error, but… I’m still new at coding so… what’s the alternative? I have a scoop that the ball goes in and comes out another. I use destroyball on one and create ball on the other.

  6. DJRobX

    The alternative would be to make the scoop with a fall-through kicker, and put in a real subway in that takes the ball to the other. WhoDunnit is a pretty simple table with an example of this.

    • avatar