Gavit Dev Diary #16: Basic pinball

My first prototype project to be made with Gavit is about exploring variations of the classic pinball mechanics. Thanks to the relative simplicity of the moving components on the table it’s also been a good testcase for debugging Gavit’s machine and control systems.

The first iteration of the pinball table was just a bunch of random stuff thrown together:

The focus was on laying the foundation of the most basic functions such as machine setup, ball movement, scaling and so on.

Instead of trying to build a tilted table (a level designer’s nightmare) I decided to simulate the effect  with a thruster attached to the ball. Later I switched to an all encompassing NxGenericForceFieldBox which is a more intuitive approach and seemed to produce less collision issues for some reason.

Another takeaway was that the size of the physics driven objects matter a lot. Too small and object interpenetration becomes a big problem: even moderately fast moving meshes start to pass through walls. Partially sunk actors are automatically corrected but the forces applied during the fix can spectacularly throw off the small and therefore light objects.
However too big stuff is not good either: great volume means great mass which will need great forces to move around resulting in great momentum which seem to make constraints unstable. So I ended up with a ball which is 45 cm (~18 inch) in diameter and scaled the table accordingly.

After the basic mechanics were sorted out the next step was building an sensible layout:

It’s roughly based on one of my favorite tables, although it changed a lot during this playtesting phase. The standard elements (flipper, slingshot, drop target, etc) were modeled as static meshes while the more organic pieces (curvy side walls, islands) were build using BSP brushes.

The main lesson learned in this round was that this particular PhysX implementation sucks big time when it comes to collisions. A ball with a parametric, thus “perfect”, sphere collision jumps every time it reaches the edge of a collision primitive or colliding polygon, making it very difficult to create proper ramps or rails.
I dug into the PhysX SDK, all available documentations and the related parameters in UEd but so far failed to find a fix for it. According to the manual the problem is indeed addressed in PhysX ( NX_MESH_SMOOTH_SPHERE_COLLISIONS ) but it apparently doesn’t work in Unreal.
http://www.zspline.net/blog/wp-content/gallery/gavit/AirPinball04.jpgSimilarly, high speed pass-through doesn’t happen in SDK demos, even at ridiculous velocities, while in UDK the flippers often skip the ball altogether. If I slow them down then the collision is registered all the time but they don’t propel the ball far enough… -*sigh*-
After a week of adjusting Physics Delta Times, SubStep numbers, physics materials and collision primitives, I started using per polygon collisions everywhere because they allow slightly smoother movements. Their main downside is that they are more prone to object interpenetration but as it turns out running the game at half speed helps a lot. Since everything will be recorded eventually and can be replayed at any rate, it won’t be too much of a problem.

Right now I’m in the middle of the third stage, creating slightly more polished art assets:

The “art direction” is a clean, functional look which can be produced in reasonable time. There are a few more things I’d like to add to make the table visually more interesting but I’m happy with the basic style.

Hopefully the development of the machines and input handling will be finished soon so the really fun part of this pinball experiment can be started: riffing on alternate pinball control mechanics which will involve an air hockey mallet  or some magnets.

Speaking of inputs: we managed to link UDK to the Razer Hydra controller. A small background service (we call it “HydraBridge”) polls the hardware and sends the raw data to UDK using TCP. So far Gavit machines can only use the buttons of Hydra but we’re close to be able to utilize all analog input.
And that’s when sh.t gets real. :)