NAME
Physics::Balls - balls on a table with friction, walls and pockets
VERSION
Version 0.01
SYNOPSIS
use Physics::Balls;
my $table = Physics::Balls::Table->new(
L => 2.540, W => 1.270, R => 0.028575,
corner => { mouth => 0.1175, jaw_deg => 142, shelf => 0.041 },
side => { mouth => 0.1302, jaw_deg => 104, shelf => 0.008 },
);
my $world = Physics::Balls::World->from_table($table,
mu => { s => 0.2, r => 0.02, sp => 0.044 },
e => { bb => 0.95, c => 0.8, cf => 0.2, rc => 0.7 },
vmax => 8, g => 9.81,
);
my $out = Physics::Balls->strike($world,
layout => [ [0, 63500, 63500], [1, 190500, 63500] ],
ball => 0, dx => 1_000_000, dy => 0, power => 520, sx => 0, sy => 0,
);
if ($out->error) { die $out->message }
print $out->t, " seconds, ", scalar @{ $out->events }, " events\n";
my $payload = $out->to_payload; # what a game stores and a client plays back
DESCRIPTION
An engine for round balls of one size on a flat surface: sliding and rolling friction, side spin, walls a ball bounces off, nose points it can rattle against, and gates it drops through. It knows nothing about any game. A pool or snooker adapter describes its table, sends a strike, and reads the outcome: the contacts in order, where every ball came to rest, which balls dropped and where, and the trajectory as segments a client can play back without simulating anything itself.
The simulation is event-based and analytic. A sliding ball is a parabola under constant deceleration, a rolling ball a straight line, and every contact time is the first downward zero of a polynomial found by a fixed number of bisections in a fixed order. The same inputs give the same outcome, bit for bit, on every platform that keeps IEEE doubles honest, which is why the inputs are integers and the build refuses fused multiply-adds.
Units
A description is in metres, seconds and metres per second. A layout and a rest position are integers in hundredths of a millimetre. A shot is integers: a direction dx, dy in plus or minus 1,000,000, power 0 to 1000, and a tip offset sx, sy in thousandths of the radius from -500 to 500. Segments are doubles in metres and seconds.
METHODS
strike
my $out = Physics::Balls->strike($world, layout => \@layout, %shot);
Builds a Physics::Balls::Strike from %shot, validates it against the layout, and plays it on the world. Returns a Physics::Balls::Outcome, or a Physics::Balls::Error when the shot or the layout is refused; both answer error, so $out->error is the one test a caller needs.
abi_version
The version of the C table in pb_abi.h.
THE C INTERFACE
include/pb_abi.h is installed with the module and describes a versioned function-pointer table, resolved at runtime through Physics::Balls::Engine::_abi_ptr, so another module can roll balls with no Perl frame in between. The engine itself is perl-free and the same C compiles alone.
SEE ALSO
Physics::Balls::World, Physics::Balls::Table, Physics::Balls::Strike, Physics::Balls::Outcome, Physics::Balls::Error.
AUTHOR
LNATION, <email at lnation.org>
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)