Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

physics source pure

Package physics is a 2D rolling-ball engine: it answers where a ball goes, never what that means.

Overview

Package physics is a 2D rolling-ball engine: it answers where a ball goes, never what that means.

+X is right, +Y is down, 1.0 is one board unit, angles are in radians. Deterministic: float64 only, no map iteration, no clock, no randomness.

Inputs must be finite: a NaN or an infinity gives no panic and no endless loop, but no meaningful answer either. Callers check them.

Constants 12

const RollSpeed, RollDrag, keepBonus, maxKeep

1const (
2	RollSpeed = 1.8
3	RollDrag  = 0.08
4	keepBonus = 0.05
5	maxKeep   = 0.98
6)
source

The calibration of Rolling, fitted by least squares to the course's strokes: keep = min((Friction+keepBonus)·Scale, maxKeep), then Crr = ((1−keep)·RollSpeed + RollDrag/Scale) / G.

const WallFriction, TangentMass, RestSpeed, MaxBounce, MaxKick

 1const (
 2	// WallFriction is the Coulomb µ between the ball and a wall or post:
 3	// the tangential impulse is at most µ times the normal one.
 4	WallFriction = 0.05
 5	// TangentMass caps the tangential impulse, per unit mass and speed:
 6	// 2/7 is what stops a solid ball's contact point from slipping.
 7	TangentMass = 2.0 / 7
 8	// RestSpeed is the speed into a surface, per substep, under which a
 9	// contact is resting: no restitution, no bounce counted. At least what
10	// the steepest hill adds in a substep, so a ball a hill presses into a
11	// rail slides along it instead of jittering.
12	RestSpeed = 0.35
13	// MaxBounce is the most restitution a passive piece plays: a Bounce
14	// above it is played at it.
15	MaxBounce = 0.75
16	// MaxKick is the most restitution a bumper (a Bounce above 1 on a skin
17	// that Kicks) plays, and the most course.Decode accepts. The ball stays
18	// under SpeedCap.
19	MaxKick = 1.5
20)
source

The contact rules for walls and posts.

const CrestRadius, MinRamp, GroundBounce, LandFriction, HopSpeed, MaxSin

 1const (
 2	// CrestRadius is the radius of a hill's lip, in board units: a ball
 3	// needs sqrt(G·CrestRadius), 0.71 per substep, to take off.
 4	CrestRadius = 0.5
 5	// MinRamp is the gentlest hill (|Vec|) that launches.
 6	MinRamp = 0.12
 7	// GroundBounce is the restitution of the ground when a ball lands.
 8	GroundBounce = 0.4
 9	// LandFriction is the Coulomb µ between a landing ball and the ground.
10	LandFriction = 0.3
11	// HopSpeed is the vertical speed, per substep, under which a landing
12	// ball stays down.
13	HopSpeed = 0.25
14	// MaxSin is the steepest grade a hill plays, sin θ (about 72°), so tan θ
15	// and a flight stay bounded; course.Decode holds |Vec| to G·MaxSin.
16	MaxSin = 0.95
17)
source

The flight rules: a ball takes off over a hill's crest (its uphill edge) when v² > G·CrestRadius, v its speed up the hill, flies a ballistic arc and lands at the height it took off from.

const G

1const G = 1.0
source

G is gravity, in board units per substep squared: a hill's Vec is G·sin θ.

const JumpRun

1const JumpRun = 0.5
source

JumpRun is the share of a hill's depth a ball must have climbed to take off at its top: one that only clipped the hill near its crest has not ridden it.

const LoopKeep

1const LoopKeep = 0.8
source

LoopKeep is the share of its speed a ball keeps once round a loop.

const MaxMove

1const MaxMove = 1.5
source

MaxMove is the longest single move inside a substep. Zones are sampled once per move, so a zone must be at least this deep along the way a ball crosses it, or a fast ball can step over it unseen.

const MaxRollOn

1const MaxRollOn = 120
source

MaxRollOn caps the substeps a ball may roll on past its stroke's own while a slope keeps it moving or it is still in the air.

const MaxWork

1const MaxWork = 1000000
source

MaxWork caps what one stroke may cost, whatever the field, in work units of about a thousand gas each (Shot.Work): a stroke that reaches it ends where the ball is. A Field's Cap lowers it for one stroke.

const MaxWorkStep

1const MaxWorkStep = 225000
source

MaxWorkStep is the most a stroke's Work passes its limit (MaxWork, or a lower Cap) by on a Decode-limited field: the most between two checks. Golf holds a shot to its limit plus this (shotBound).

const SpeedCap

1const SpeedCap = 8
source

SpeedCap is the fastest a ball may go, in board units per substep, held at the start of every substep and after every bounce: it bounds a substep to 6 moves, even between two bumpers or down a slope on ice.

const Surface, Slope, Tunnel, Hazard, Loop

 1const (
 2	Surface ZoneKind = iota // Scale sets the rolling resistance (Rolling): sand holds, ice frees
 3	Slope                   // a hill: Vec, gravity along it, is added to velocity each substep
 4	Tunnel                  // the ball is moved to Vec, keeping its velocity
 5	Hazard                  // the ball goes back where the stroke was played from: water, a pit, the void
 6	// Loop is a tube's mouth (Min..Max): a ball heading in within 25° at
 7	// Scale or faster comes out at Vec, else it falls back or off the side.
 8	// The mouth must be at least MaxMove deep, or a fast ball steps over it.
 9	Loop
10)
source

The zone kinds, each named in its own line.

Functions 11

func Kicks

1func Kicks(skin string) bool
source

Kicks reports whether a piece of this skin may kick the ball back faster than it came (a Bounce above 1). Every other piece is passive.

func Lengths

1func Lengths(s Segment, r float64) (l, lp, lm float64)
source

Lengths is the three square roots Prepare takes for a wall and a ball of radius r: the wall's length, then its plus and minus offset lines'.

func Prepare

1func Prepare(f *Field)
source

Prepare works out the field's wall offsets once, for every shot to reuse. Call it once the walls are where they stay: Step works out again any wall that no longer matches its entry.

func PrepareWith

1func PrepareWith(f *Field, lens []float64)
source

PrepareWith is Prepare with each wall's Lengths given, three per wall in wall order: the same prep, bit for bit, when they are the walls' own. It does not check them; whoever stored them must have. With the wrong count it is Prepare.

func Prepared

1func Prepared(f *Field) []float64
source

Prepared is a copy of the field's prep, to compare bit for bit.

func Rolling

1func Rolling(friction, scale float64) float64
source

Rolling is the rolling-resistance coefficient Crr of a green of the given Friction under a Surface of the given Scale (1 is plain grass). A Scale of 0 or less is an infinite Crr: the ball stays where it is.

func There

1func There(i, every, on, phase int) bool
source

There is the timing rule walls, zones and course pulses share (sign-safe mod, so a negative phase works): on at i when (i+phase) mod every is below on; every <= 0 is always there.

func WithTick

1func WithTick(f *Field, tick int) *Field
source

WithTick is the field with its clock moved on by tick substeps. It may return f itself (tick 0): do not mutate what it returns.

func FromPolar

1func FromPolar(angle, r float64) Vec2
source

FromPolar builds a vector of length r pointing at angle (radians).

func UnstickIn

1func UnstickIn(ball Vec2, walls []Wall, posts []Post, r float64, stays []Wall) Vec2
source

UnstickIn moves a ball of radius r out of pieces that appeared on top of it. walls are read in bars of four (build.Bar): a ball inside one leaves through the nearest side it can; one closer than r to a bar or a post is pushed off it. No push crosses an untimed wall of stays: out of a bar the ball tries the next side, else it stays; any other such push is not made.

func V

1func V(x, y float64) Vec2
source

V is Vec2{x, y}, short so a course's coordinates read as coordinates.

Types 9

type Circle

struct
1type Circle struct {
2	C Vec2
3	R float64
4}
source

Circle is a round barrier: a post, a bumper, the rim of a pond.

type Field

struct
 1type Field struct {
 2	Walls    []Wall
 3	Posts    []Post
 4	Zones    []Zone
 5	Friction float64 // the green's rolling resistance, as Rolling maps it: 0.87 is Crr 0.224
 6	Bounce   float64 // default restitution of barriers
 7	// Radius of the ball (0 plays it as a point).
 8	Radius float64
 9	// Tick is where the stroke starts on the clock of timed walls and zones.
10	Tick int
11	// Cap, above 0 and under MaxWork, replaces MaxWork for this stroke.
12	Cap int
13	// prep is the walls' offsets, worked out once (Prepare).
14	prep []float64
15}
source

Field is everything a ball rolls through: walls, posts and zones.

Methods on Field

func Step

method on Field
1func (f *Field) Step(pos, vel Vec2, substeps int) Shot
source

Step rolls a ball through the field until it comes to rest or runs out of substeps (and past them while a slope keeps it rolling or it is still in the air, see MaxRollOn). With a Radius, the ball meets walls and posts with its edge. Cost is O(moves * (walls + posts + zones)), paid on every shot.

type Post

struct
1type Post struct {
2	Circle
3	Bounce float64 // 0 = use the field default; played at MaxBounce at most; above 1 a bumper, if Kicks(Skin)
4	Mark   rune
5	Skin   string
6}
source

Post is a round obstacle. Bounce is the contact's restitution, played at MaxBounce at most; above 1 with a bumper's skin (Kicks) it kicks the ball back faster than it came (at most MaxKick times).

type Segment

struct
1type Segment struct{ A, B Vec2 }
source

Segment is a straight barrier from A to B.

Methods on Segment

func Closest

method on Segment
1func (s Segment) Closest(p Vec2) Vec2
source

Closest is the point of the segment nearest p.

func Crosses

method on Segment
1func (s Segment) Crosses(p0, p1 Vec2) bool
source

Crosses reports whether the motion p0->p1 crosses the segment, without working out the normal (and its square root).

func Normal

method on Segment
1func (s Segment) Normal() Vec2
source

Normal is the unit left-normal of the segment.

type Shot

struct
 1type Shot struct {
 2	Path    []Vec2
 3	Bounces int
 4	// Air marks the path points where the ball is off the ground (no zone
 5	// acts, no cup takes it). Same length as Path.
 6	Air []bool
 7	// Cause says, per path point, what most acted on the ball in the substep
 8	// that ended there: 'b' a bounce, 's' a hill, 'w' wind or a gust, 'i' a
 9	// slippery surface, '-' nothing but friction. Same length as Path.
10	Cause []byte
11	why   byte // this substep's cause so far
12	// Work is what the stroke cost, in MaxWork's units.
13	Work int
14	// start is where the stroke was played from, where a hazard sends it.
15	start Vec2
16}
source

Shot is everything a stroke did: where the ball was at every substep, and how many walls and posts it met. A renderer replays Path and never simulates; two consecutive points far apart are a tunnel, not a line to interpolate.

Methods on Shot

func Rest

method on Shot
1func (s Shot) Rest() Vec2
source

Rest is where the ball stopped.

type Vec2

struct
1type Vec2 struct{ X, Y float64 }
source

Vec2 is a point or a displacement on the board, in board units.

Methods on Vec2

func Add

method on Vec2
1func (a Vec2) Add(b Vec2) Vec2
source

Add is a+b.

func Dot

method on Vec2
1func (a Vec2) Dot(b Vec2) float64
source

Dot is the dot product of a and b.

func Len

method on Vec2
1func (a Vec2) Len() float64
source

Len is the length of a.

func LenCmp

method on Vec2
1func (a Vec2) LenCmp(r float64) int
source

LenCmp compares a.Len() with r: -1 shorter, 0 equal, 1 longer, exactly as comparing a.Len() would. It takes the costly square root only within 1e-12 of r², where a.Dot(a) alone could round the other way. For board-scale r.

func Scale

method on Vec2
1func (a Vec2) Scale(s float64) Vec2
source

Scale is a times s.

func Sub

method on Vec2
1func (a Vec2) Sub(b Vec2) Vec2
source

Sub is a-b.

type Wall

struct
1type Wall struct {
2	Seg    Segment
3	Bounce float64 // 0 = use the field default
4	Mark   rune
5	Skin   string
6	// Every > 0 times the wall within a stroke: it stands in substep i only
7	// when (i+Tick+Phase) mod Every is below On.
8	Every, On, Phase int
9}
source

Wall is a straight barrier. Bounce overrides the field's restitution (0 keeps it); Mark and Skin are for whoever draws it, except that only a bumper's skin kicks (Kicks).

type Zone

struct
 1type Zone struct {
 2	Kind     ZoneKind
 3	Min, Max Vec2
 4	Vec      Vec2    // Slope: acceleration (G·sin θ downhill). Tunnel: destination. Loop: where it comes down. Hazard: unused.
 5	Scale    float64 // Surface: its rolling resistance (Rolling). Loop: the speed to go round.
 6	Mark     rune
 7	Skin     string
 8	// Round makes the zone the ellipse inscribed in Min..Max.
 9	Round bool
10	// Poly (3 points or more) makes the zone that polygon, within Min..Max;
11	// Outside makes it everything in Min..Max but the polygon.
12	Poly    []Vec2
13	Outside bool
14	// Every, On, Phase time the zone within a stroke, as for a Wall.
15	Every, On, Phase int
16	// Air makes a Slope moving air: it pushes the ball but is no hill, and
17	// hides none under it. Capped air never speeds the ball up.
18	Air, Capped bool
19}
source

Zone is an area of the board that changes how the ball moves: the rectangle Min..Max, or the ellipse inside it (Round), or a polygon (Poly), or all of it but a polygon (Outside). Vec and Scale mean what the kind says.

Methods on Zone

func Contains

method on Zone
1func (z Zone) Contains(p Vec2) bool
source

Contains says whether p is in the zone, by its shape.

type ZoneKind

ident
1type ZoneKind int
source

ZoneKind is what a zone does to a ball inside it.

Methods on ZoneKind

func String

method on ZoneKind
1func (k ZoneKind) String() string
source

String is the kind's name as clients read it: "surface", "slope", ...

Imports 2

  • math stdlib
  • strings stdlib

Source Files 6