Documentation
¶
Overview ¶
Jel is a 2D soft-body physics library for games.
Index ¶
- Constants
- Variables
- func CalcSpringTension(a, b Vec2, rd RestDistance) float64
- func DefaultCollisionFilterFunc(info CollisionInfo, normalVelocity float64) bool
- func StiffnessDampingFrom(mass, softness float64) (stiffness, damping float64)
- type AABB
- type Bitmask
- type Body
- func (b *Body) AccumulateExternalForces(world *World)
- func (b *Body) AccumulateInternalForces(relaxing bool)
- func (b *Body) AddAngularVelocity(vel float64)
- func (b *Body) AddComponent(comp Component)
- func (b *Body) AddVelocity(velocity Vec2)
- func (b *Body) AddVelocityToPointAt(velocity Vec2, pointMassIndex int)
- func (b *Body) ApplyForceAtGlobalPoint(force Vec2, pt Vec2)
- func (b *Body) ApplyForceToPointAt(force Vec2, pointMassIndex int)
- func (b *Body) ApplyGlobalForce(force Vec2)
- func (b *Body) ApplyTorque(force float64)
- func (b *Body) ClosestEdge(point Vec2, tolerance float64) (edgePosition Vec2, edgeRatio float64, edgePoint1, edgePoint2 int, ok bool)
- func (b *Body) ClosestPoint(pt Vec2) (hitPoint, normal Vec2, pointA, pointB int, edgeD, distance float64)
- func (b *Body) ClosestPointMass(pos Vec2) (point int, distance float64)
- func (b *Body) ClosestPointOnEdge(pt Vec2, edgeNum int) (hitPoint, normal Vec2, edgeD, distance float64)
- func (b *Body) ClosestPointOnEdgeSq(pt Vec2, edgeNum int) (hitPoint, normal Vec2, edgeD, distance float64)
- func (b *Body) Contains(pt Vec2) bool
- func (b *Body) DampenVelocity(elapsed float64)
- func (b *Body) DerivePositionAndAngle(elapsed float64)
- func (b *Body) GetComponent[T Component]() (component T)
- func (b *Body) Integrate(elapsed float64)
- func (b *Body) IntersectsLine(start, end Vec2) bool
- func (b *Body) PointMass(pointMassIndex int) *PointMass
- func (b *Body) Raycast(start, end Vec2) (closestHit Vec2, ok bool)
- func (b *Body) RemoveComponent(comp Component)
- func (b *Body) Reset()
- func (b *Body) SetAngularVelocity(vel float64)
- func (b *Body) SetAverageVelocity(velocity Vec2)
- func (b *Body) SetMassAll(mass float64)
- func (b *Body) SetMassByIndex(pointMassIndex int, mass float64)
- func (b *Body) SetMassesFromSlice(masses []float64)
- func (b *Body) SetPointPositionAt(position Vec2, pointMassIndex int)
- func (b *Body) SetPointVelocityAt(velocity Vec2, pointMassIndex int)
- func (b *Body) SetScaleAnglePosition(scale Vec2, angle float64, pos Vec2)
- func (b *Body) SetShape(shape Shape)
- func (b *Body) TranslatePointAt(offset Vec2, i int)
- func (b *Body) UpdateAABB(elapsed float64, forceUpdate bool)
- type BodyEdge
- type BodyJointLink
- func (b *BodyJointLink) AddVelocity(velocity Vec2)
- func (b *BodyJointLink) ApplyForce(force Vec2)
- func (b *BodyJointLink) Body() *Body
- func (b *BodyJointLink) IsStatic() bool
- func (b *BodyJointLink) Mass() (totalMass float64)
- func (b *BodyJointLink) Position() Vec2
- func (b *BodyJointLink) Translate(offset Vec2)
- func (b *BodyJointLink) Velocity() Vec2
- type CollisionInfo
- type CollisionObserver
- type Component
- type EdgeJointLink
- func (e *EdgeJointLink) AddVelocity(velocity Vec2)
- func (e *EdgeJointLink) ApplyForce(force Vec2)
- func (b *EdgeJointLink) Body() *Body
- func (e *EdgeJointLink) IsStatic() bool
- func (e *EdgeJointLink) Mass() (totalMass float64)
- func (e *EdgeJointLink) Position() Vec2
- func (e *EdgeJointLink) Translate(offset Vec2)
- func (e *EdgeJointLink) Velocity() Vec2
- type GravityComponent
- type InternalSpring
- type Joint
- type JointLink
- type LineIntersectResult
- type MaterialPair
- type Matrix3x3
- type PinJoint
- type PointJointLink
- func (p *PointJointLink) AddVelocity(velocity Vec2)
- func (p *PointJointLink) ApplyForce(force Vec2)
- func (b *PointJointLink) Body() *Body
- func (p *PointJointLink) IsStatic() bool
- func (p *PointJointLink) Mass() (totalMass float64)
- func (p *PointJointLink) Position() Vec2
- func (p *PointJointLink) Translate(offset Vec2)
- func (p *PointJointLink) Velocity() Vec2
- type PointMass
- type PressureComponent
- type Resolver
- type RestDistance
- func (r RestDistance) Clamp(value float64) float64
- func (r RestDistance) InRange(value float64) bool
- func (r *RestDistance) MaxDist() float64
- func (r *RestDistance) MinDist() float64
- func (r *RestDistance) SetMaxDist(value float64)
- func (r *RestDistance) SetMinDist(value float64)
- func (r RestDistance) Squared() RestDistance
- type Shape
- func (c *Shape) AddVertex(pos Vec2)
- func (c *Shape) AddVertexXY(x, y float64)
- func (c *Shape) Clone() Shape
- func (c *Shape) FitHeight(h float64)
- func (c *Shape) FitWidth(w float64)
- func (c Shape) IsCCW() bool
- func (s Shape) PolygonPointsString(precision int) string
- func (c *Shape) Recenter()
- func (c *Shape) Reverse()
- func (c *Shape) Scale(x, y float64)
- func (c *Shape) TransformByMatrix(m Matrix3x3)
- func (c *Shape) TransformByMatrixToTarget(target []Vec2, matrix Matrix3x3)
- func (c *Shape) TranslateVerticesToTarget(target Shape, pos Vec2)
- type ShapeJointLink
- func (s *ShapeJointLink) AddVelocity(velocity Vec2)
- func (s *ShapeJointLink) ApplyForce(force Vec2)
- func (b *ShapeJointLink) Body() *Body
- func (s *ShapeJointLink) IsStatic() bool
- func (s *ShapeJointLink) Mass() (mass float64)
- func (s *ShapeJointLink) Position() Vec2
- func (s *ShapeJointLink) SubDerivedAngle() float64
- func (s *ShapeJointLink) Translate(offset Vec2)
- func (s *ShapeJointLink) Velocity() (vel Vec2)
- type ShapeMatchComponent
- func (b *ShapeMatchComponent) AccumulateExternalForces(body *Body, world *World)
- func (s *ShapeMatchComponent) AccumulateInternalForces(body *Body, relaxing bool)
- func (b *ShapeMatchComponent) Disabled() bool
- func (b *ShapeMatchComponent) Prepare(body *Body)
- func (s *ShapeMatchComponent) SetTarget(indices []int)
- type Spring
- type SpringComponent
- func (b *SpringComponent) AccumulateExternalForces(body *Body, world *World)
- func (s *SpringComponent) AccumulateInternalForces(body *Body, relaxing bool)
- func (s *SpringComponent) AddExtraSpring(body *Body, pointA, pointB int, stiffness, damping float64, ...) *InternalSpring
- func (s *SpringComponent) ApplyDefaults()
- func (s *SpringComponent) ClearAllSprings(body *Body)
- func (b *SpringComponent) Disabled() bool
- func (s *SpringComponent) Prepare(body *Body)
- func (s *SpringComponent) SetAll(stiffness, damping float64)
- func (s *SpringComponent) SetAllEdges(stiffness, damping float64)
- func (s *SpringComponent) SetExtraAt(relativeIndex int, stiffness, damping float64)
- func (s *SpringComponent) SetSpringPlasticity(relativeIndex int, plasticity *SpringPlasticity)
- type SpringJoint
- type SpringPlasticity
- type SpringType
- type StickyRayComponent
- type UnimplementedCollisionObserver
- type Vec2
- func AveragePointMassPosition(pointMasses []*PointMass) (centroid Vec2)
- func AveragePointMassVelocity(pointMasses []*PointMass) (average Vec2)
- func AverageVec2(vectors []Vec2) (average Vec2)
- func CalcSpringForce(posA, velA, posB, velB Vec2, distance, stiffness, damping float64) Vec2
- func FromAngle(angle float64) Vec2
- func (v Vec2) Abs() Vec2
- func (v Vec2) AbsX() float64
- func (v Vec2) AbsY() float64
- func (v Vec2) Add(a Vec2) Vec2
- func (v Vec2) AddX(n float64) Vec2
- func (v Vec2) AddY(n float64) Vec2
- func (v Vec2) Angle() float64
- func (v Vec2) AngleTo(other Vec2) float64
- func (v Vec2) Ceil() Vec2
- func (v Vec2) Cross(other Vec2) float64
- func (v Vec2) Dist(other Vec2) float64
- func (v Vec2) DistSq(other Vec2) float64
- func (v Vec2) Div(a Vec2) Vec2
- func (v Vec2) DivS(s float64) Vec2
- func (v Vec2) Dot(other Vec2) float64
- func (v Vec2) Equals(other Vec2) bool
- func (v Vec2) EqualsPr(other Vec2, allowedDelta float64) bool
- func (v Vec2) Floor() Vec2
- func (v Vec2) IsZero() bool
- func (v Vec2) Lerp(other Vec2, t float64) Vec2
- func (v Vec2) Limit(max float64) Vec2
- func (v Vec2) Mag() float64
- func (v Vec2) MagSq() float64
- func (v Vec2) Max(other Vec2) Vec2
- func (v Vec2) Min(other Vec2) Vec2
- func (v Vec2) Mul(a Vec2) Vec2
- func (v Vec2) Neg() Vec2
- func (v Vec2) NegX() Vec2
- func (v Vec2) NegY() Vec2
- func (v Vec2) Perp() Vec2
- func (v Vec2) Project(other Vec2) Vec2
- func (v Vec2) Reflect(normal Vec2) Vec2
- func (v Vec2) Rotate(angle float64) Vec2
- func (v Vec2) Round() Vec2
- func (v Vec2) Scale(s float64) Vec2
- func (v Vec2) SetMag(m float64) Vec2
- func (v Vec2) Slerp(to Vec2, weight float64) Vec2
- func (v Vec2) String() string
- func (v Vec2) Sub(a Vec2) Vec2
- func (v Vec2) Unit() Vec2
- type World
- func (w *World) AddBodies(bodies ...*Body)
- func (w *World) AddBody(body *Body)
- func (w *World) AddJoint(joint Joint)
- func (w *World) AddMaterial() int
- func (w *World) AreBodiesJoined(body1, body2 *Body) bool
- func (w *World) BodiesIntersectingLine(start, end Vec2, bitmask Bitmask) []*Body
- func (w *World) BodiesIntersectingShape(shape Shape, worldPos Vec2, ignoreTest func(*Body) bool, outResults []*Body, ...) []*Body
- func (w *World) BodiesUnder(pt Vec2, bitmask Bitmask) []*Body
- func (w *World) BodyUnder(pt Vec2, bitmask Bitmask) *Body
- func (w *World) ClosestPoint(pt Vec2, ignoreFunction func(*Body) bool) (closestBody *Body, closestHitPoint Vec2, found bool)
- func (w *World) ClosestPointMass(pt Vec2, ignoreFunction func(*Body, int) bool) (*Body, int, bool)
- func (w *World) IsRelaxing() bool
- func (w *World) RayCast(start, end Vec2, bitmask Bitmask, ignoreTest func(*Body) bool) (retPt Vec2, body *Body)
- func (w *World) RelaxBodies(bodies []*Body, timestep float64, iterations int)
- func (w *World) RelaxWorld(timestep float64, iterations int)
- func (w *World) RemoveBody(body *Body)
- func (w *World) RemoveJoint(joint Joint)
- func (w *World) Reset()
- func (w *World) SetMaterialPairCollide(a, b int, collide bool)
- func (w *World) SetMaterialPairData(a, b int, friction, elasticity float64)
- func (w *World) SetMaterialPairFilterCallback(a, b int, filter func(CollisionInfo, float64) bool)
- func (w *World) SetWorldLimits(min, max Vec2)
- func (w *World) Update(elapsed float64)
- func (w *World) WorldLimits() AABB
Constants ¶
const ( // Pi is a convenience re-export of math.Pi. Pi float64 = math.Pi // Tau (τ) is two times pi , representing a full circle in radians. https://oeis.org/A019692 Tau = 6.2831853071795864769252867665590057683943387987502 )
Variables ¶
var Infinity = math.Inf(1)
Infinity represents positive infinity, commonly used to mark a PointMass as having infinite mass (i.e. immovable / static).
var Vec2One = Vec2{X: 1, Y: 1}
Vec2One is a Vec2 with both components set to 1. Do not modify.
Functions ¶
func CalcSpringTension ¶
func CalcSpringTension(a, b Vec2, rd RestDistance) float64
CalcSpringTension computes the normalized tension (-1..1) of a spring based on the current distance between its two endpoints (a, b) relative to its rest distance range.
If dist falls within RestDistance.MinDist, RestDistance.MaxDist the spring is considered relaxed and tension is 0. Otherwise, the ratio is computed against the nearest bound (RestDistance.MaxDist when stretched, RestDistance.MinDist when compressed), clamped so that a ratio of ±30% or more maps to ±1. A positive value indicates stretching, a negative value indicates compression.
func DefaultCollisionFilterFunc ¶
func DefaultCollisionFilterFunc(info CollisionInfo, normalVelocity float64) bool
DefaultCollisionFilterFunc is the default collision filter. It always returns true, so all collisions passed through it are approved.
func StiffnessDampingFrom ¶
StiffnessDampingFrom returns (stiffness, damping) for a spring, given only a mass and a softness value in [0, 1].
- softness = 0 -> rigid (stiff, snaps back fast, no wobble)
- softness = 1 -> ideal loose/jelly (soft, wobbles, settles slowly)
Same softness value gives the same "feel" regardless of mass.
Types ¶
type AABB ¶
AABB is an axis-aligned bounding box. Valid is false for an empty/unset box.
func NewAABBFromPoints ¶
NewAABBFromPoints creates an AABB enclosing all the given points.
func (*AABB) ExpandToInclude ¶
ExpandToInclude grows the box, if needed, so it contains point.
func (*AABB) ExpandToIncludePoints ¶
ExpandToIncludePoints grows the box, if needed, so it contains all points.
func (AABB) Intersects ¶
Intersects reports whether the two boxes overlap.
type Bitmask ¶
type Bitmask uint64
Bitmask is a 64-bit flag set, typically used for collision layers/masks.
type Body ¶
type Body struct {
// The base shape for the body with local vertices
BaseShape Shape
// The global shape for the body - rotated and translated around the world
GlobalShape Shape
// Point masses for the body.
PointMasses []*PointMass
// Edges on the body.
Edges []*BodyEdge
// Body joints this body participates in
Joints []Joint
// Body components for this body object
Components []Component
// The scale for this body's shape
Scale Vec2
// The velocity damping to apply to the body. Values closer to 0
// decelerate faster, values closer to 1 decelerate slower.
//
// 1 never decelerates. Values outside the range [0, 1] inclusive may
// introduce instability. Default is 0.999
VelDamping float64
// The axis-aligned bounding box for this body's point masses.
//
// Will be slightly expanded to include the velocity of the points, in case
// this body is kinematic, so it won't always match exactly the position of
// the point masses.
AABB AABB
// The index of the material in the world material slice to use for this
// body.
Material int
// Whether this body is static.
IsStatic bool
// Whether this body is kinematic. When true, [Body.DerivePositionAndAngle]
// skips recomputing [Body.DerivedPos], [Body.DerivedVel], [Body.DerivedAngle],
// and [Body.DerivedOmega] from the point masses each frame. Instead, the
// body's transform is driven externally via [Body.SetScaleAnglePosition],
// which sets [Body.DerivedPos]/[Body.DerivedAngle] directly and pushes
// that transform onto the point masses (overwriting their positions to
// match the new base-shape placement). In other words, the usual
// point-masses -> derived-transform flow is reversed: for kinematic
// bodies, the derived transform drives the point masses instead of being
// computed from them.
//
// [Body.SetScaleAnglePosition] does not update [Body.DerivedVel],
// [Body.DerivedOmega], or the point masses' [PointMass.Velocity] — it
// only overwrites [PointMass.Position]. So a kinematic body's
// velocity/angular-velocity fields go stale (or stay zero) unless the
// caller updates them separately. Consumers should not assume these
// fields reflect the body's actual motion when IsKinematic is true (e.g.
// [ShapeMatchComponent.Damping] term ignores them in this case).
IsKinematic bool
// Whether this body is pinned - pinned bodies rotate around their axis,
// but try to remain in place, like a kinematic body.
IsPinned bool
// Whether the body is able to rotate while moving. Default is true
FreeRotate bool
// The collision bitmask for this body.
Bitmask Bitmask
// The X-axis bitmask for the body - used for collision filtering.
BitmaskX Bitmask
// The Y-axis bitmask for the body - used for collision filtering.
BitmaskY Bitmask
// The derived center position of this body - in world coordinates
DerivedPos Vec2
// The derived velocity of this body - in world coordinates. The derivation
DerivedVel Vec2
// The derived rotation of the body, in radians
DerivedAngle float64
// Omega (ω) is the relative angular speed of the body, in radians/s
DerivedOmega float64
// Custom user data attached to the body
UserData any
// contains filtered or unexported fields
}
Represents a soft body on the World
func NewBody ¶
NewBody returns a new Body from shape.
To ensure a stable physics simulation, the shape is automatically re-centered and inverted if it is not CCW. - pos: initial position in world coordinates. - angle: refers to the initial rotation angle from the center in radians (clockwise). - mass is the individual mass of each point within [Body.PointMasses]. See [Body.SetMassesFromSlice], [Body.SetMassAll], [Body.SetMassByIndex] - world: The world this body will be added to (optional). See [World.AddBody] and [World.AddBodies].
func NewStaticBody ¶
NewStaticBody returns a new static Body.
func (*Body) AccumulateExternalForces ¶
This function should add all external forces to the Force member variable of each PointMass in the body.
These are external forces acting on the PointMasses, such as gravity, etc.
func (*Body) AccumulateInternalForces ¶
This function should add all internal forces to the Force member variable of each PointMass in the body.
These should be forces that try to maintain the shape of the body.
func (*Body) AddAngularVelocity ¶
Accumulates the angular velocity for this body
func (*Body) AddComponent ¶
Adds a body component to this body.
func (*Body) AddVelocity ¶
Adds a velocity vector to all the point masses in this body. Does nothing, if body is static.
func (*Body) AddVelocityToPointAt ¶
Adds velocity to the current velocity of a single point mass.
func (*Body) ApplyForceAtGlobalPoint ¶
ApplyForce applies a force to the body at `pt` in world coordinates. If `pt` is not at the center (`derivedPos`), torque is applied causing spin. Ignored if the body is static.
Parameters:
- force: The force vector to apply
- pt: The world position where the force is applied. Use `derivedPos` for center.
func (*Body) ApplyForceToPointAt ¶
Applies a relative velocity change to a single point mass at the given index..
func (*Body) ApplyGlobalForce ¶
ApplyGlobalForce applies the same force to every point mass directly. No torque is calculated, so the body translates without rotating. Ignored if the body is static.
func (*Body) ApplyTorque ¶
Applies a rotational clockwise torque of a given force on this body. Ignored, if body is static.
func (*Body) ClosestEdge ¶
func (b *Body) ClosestEdge(point Vec2, tolerance float64) (edgePosition Vec2, edgeRatio float64, edgePoint1, edgePoint2 int, ok bool)
ClosestEdge finds the point on any of the body's edges that is closest to point. point must be given in world coordinates.
tolerance limits how far an edge may be from point to be considered: any edge whose closest point is farther than tolerance is ignored. Pass math.Inf(1) to consider every edge regardless of distance (this mirrors the original default behavior). Passing 0 means no edge will ever be accepted, since a distance can never be strictly less than 0 — this is rarely what you want, so double-check the value before hardcoding 0.
Returns:
- edgePosition: the closest point on the edge to point
- edgeRatio: where along the edge that point falls, in [0, 1], with 0 at edgePoint1 and 1 at edgePoint2
- edgePoint1: index of the first point mass forming the edge
- edgePoint2: index of the second point mass forming the edge
- ok: false if the body has no edges or point masses, or if no edge was found within tolerance — in that case the other return values are zero values and should not be used
func (*Body) ClosestPoint ¶
func (b *Body) ClosestPoint(pt Vec2) (hitPoint, normal Vec2, pointA, pointB int, edgeD, distance float64)
ClosestPoint finds the closest point on any edge of the body to the given global point. It returns detailed information about the edge, including its endpoints, normal, and the ratio along the edge.
Precondition: len(Body.PointMasses) > 0.
Parameters:
- pt: The point in world coordinates to find the closest point to
Returns:
- hitPoint: The closest point on the body's surface
- normal: The unit normal vector of the edge at the closest point
- pointA: The index of the first endpoint of the edge
- pointB: The index of the second endpoint of the edge
- edgeD: The ratio along the edge [0,1] where the closest point lies
- distance: The Euclidean distance from pt to the closest point
func (*Body) ClosestPointMass ¶
Find the closest PointMass index in this body, given a global point
func (*Body) ClosestPointOnEdge ¶
func (b *Body) ClosestPointOnEdge(pt Vec2, edgeNum int) (hitPoint, normal Vec2, edgeD, distance float64)
Given a global point, finds the closest point on an edge of a specified index, returning the distance to the edge found.
Precondition: len(Body.PointMasses) > 0.
Parameters:
- pt: The point to get the closest edge of, in world coordinates
- edgeNum: The index of the edge to search
Returns:
- hitPoint: The closest point in the edge to the global point provided
- normal: A unit vector containing information about the normal of the edge found
- edgeD: The ratio of the edge where the point was grabbed, [0-1] inclusive
- distance: The distance to the closest edge found
func (*Body) ClosestPointOnEdgeSq ¶
func (b *Body) ClosestPointOnEdgeSq(pt Vec2, edgeNum int) (hitPoint, normal Vec2, edgeD, distance float64)
ClosestPointOnEdgeSq finds the closest point on a specific edge of the body to the given global point.
Precondition: len(Body.PointMasses) > 0.
Parameters:
- pt: The point in world coordinates to find the closest edge point to
- edgeNum: The index of the edge to search
Returns:
- hitPoint: The closest point on the edge to the given point
- normal: A unit vector representing the normal of the edge
- edgeD: The ratio along the edge where the point was found, in range [0, 1]
- distance: The squared distance to the closest edge point
func (*Body) DampenVelocity ¶
Applies the velocity damping to the point masses. Ignored, if body is static.
func (*Body) DerivePositionAndAngle ¶
DerivePositionAndAngle derives the global position and angle of this body, based on the average of all the points.
This updates the [Body.derivedPos], [Body.derivedAngle], and [Body.derivedVel] fields.
This is called by World.Update, so usually a user does not need to call this. Instead you can just use the Body.DerivedPos, Body.DerivedAngle, Body.DerivedVel, and Body.DerivedOmega getter methods.
func (*Body) GetComponent ¶
GetComponent returns the first Component attached to this Body matching type T, or nil if not found.
Example:
if springComp := body.GetComponent[*jel.SpringComponent](); springComp != nil {
fmt.Println(springComp.EdgeSpringsCount)
}
func (*Body) IntersectsLine ¶
Returns whether the given line consisting of two points intersects this body.
func (*Body) Raycast ¶
Tests a ray starting and ending at a given interval, returning the point at which the ray intersects this body the closest to `start`.
If the ray does not crosses this body, `nil` is returned, instead.
func (*Body) RemoveComponent ¶
Removes a component from this body.
func (*Body) SetAngularVelocity ¶
Sets the angular velocity for this body. Ignored, if body is static.
The method keeps the average velocity of the point masses the same during the procedure.
func (*Body) SetAverageVelocity ¶
SetAverageVelocity modifies the average velocity of all point masses to a certain value.
The method keeps the individual difference of velocity between the point masses and the average body velocity while making the operation.
Does nothing if the body is static.
Parameters:
- velocity: The velocity to set. Set to Zero to reset average velocity of the body to 0.
func (*Body) SetMassAll ¶
SetMassAll sets the mass for all Body.PointMasses elements in the body.
func (*Body) SetMassByIndex ¶
SetMassByIndex sets the mass of the point mass at the given index.
If any point mass has an infinite mass, the body is marked as static.
func (*Body) SetMassesFromSlice ¶
SetMassesFromSlice sets the masses of the point masses from the given slice, up to the smaller of the two lengths.
If any point mass has an infinite mass, the body is marked as static.
func (*Body) SetPointPositionAt ¶
Sets the absolute position of a single point mass.
func (*Body) SetPointVelocityAt ¶
Sets the absolute velocity of a single point mass.
func (*Body) SetScaleAnglePosition ¶
Sets the scale, angle and position of the body manually.
Setting the position and angle resets the current shape to the original base shape of the object.
func (*Body) SetShape ¶
SetShape sets the body's shape to a new Shape. If the vertex count differs from the current shape, existing Body.PointMasses are replaced with new ones (mass set to zero). Otherwise, the shape is updated without affecting existing Body.PointMasses.
To ensure a stable physics simulation, the shape is automatically re-centered and inverted if it is not CCW.
func (*Body) TranslatePointAt ¶
Translates PointMass.Position at index i
func (*Body) UpdateAABB ¶
UpdateAABB updates the body's AABB with velocity padding for the given timestep. Called automatically by World.Update. Use forceUpdate to force update even for static bodies.
type BodyEdge ¶
type BodyEdge struct {
// EdgeIndex is the index of the edge on the body.
EdgeIndex int
// StartPointIndex is the index of the start point mass of this edge on the
// [Body]'s [Body.PointMasses] slice.
StartPointIndex int
// EndPointIndex is the index of the end point mass of this edge on the
// body's [Body.PointMasses] slice.
EndPointIndex int
// Start is the start position of the edge.
Start Vec2
// End is the end position of the edge.
End Vec2
// Normal is the normal for the edge.
Normal Vec2
// Difference is the difference between the start and end points, normalized.
Difference Vec2
// Length is the edge's length.
Length float64
// LengthSquared is the edge's length, squared.
LengthSquared float64
}
BodyEdge contains information about the edge of a body.
func NewBodyEdge ¶
NewBodyEdge creates and initializes a new BodyEdge with the given index, start point index, end point index, and start/end vectors.
The BodyEdge.Difference, BodyEdge.Normal, BodyEdge.Length and BodyEdge.LengthSquared fields are automatically initialized from these values.
type BodyJointLink ¶
type BodyJointLink struct {
// contains filtered or unexported fields
}
BodyJointLink represents a joint link that links to a while body
func NewBodyJointLink ¶
func NewBodyJointLink(body *Body) *BodyJointLink
NewBodyJointLink inits a new body joint link with the specified parameter
func (*BodyJointLink) AddVelocity ¶
func (b *BodyJointLink) AddVelocity(velocity Vec2)
AddVelocity adds a velocity delta to every point mass of the body.
func (*BodyJointLink) ApplyForce ¶
func (b *BodyJointLink) ApplyForce(force Vec2)
ApplyForce applies a given force to the subject of this joint link
func (*BodyJointLink) IsStatic ¶
func (b *BodyJointLink) IsStatic() bool
IsStatic returns a value specifying whether the object referenced by this JointLinkType is static
func (*BodyJointLink) Mass ¶
func (b *BodyJointLink) Mass() (totalMass float64)
Mass calculates and returns the total mass of the subject of this joint link
func (*BodyJointLink) Position ¶
func (b *BodyJointLink) Position() Vec2
Position returns the position, in world coordinates, at which this joint links with the underlying Body.
func (*BodyJointLink) Translate ¶
func (b *BodyJointLink) Translate(offset Vec2)
Translate applies a direct positional translation of this joint link
func (*BodyJointLink) Velocity ¶
func (b *BodyJointLink) Velocity() Vec2
Velocity returns the velocity of the object this joint links to
type CollisionInfo ¶
type CollisionInfo struct {
// BodyA is the body owning the colliding point mass (index BodyApm).
BodyA *Body
// BodyApm is the index of the colliding point mass on BodyA.
BodyApm int
// BodyB is the other body involved in the collision.
BodyB *Body
// BodyBpmA is the index of the first point mass of the edge on BodyB
// involved in the collision, or -1 if the collision is against a single
// point mass rather than an edge.
BodyBpmA int
// BodyBpmB is the index of the second point mass of the edge on BodyB
// involved in the collision, or -1 if not applicable.
BodyBpmB int
// HitPt is the world-space point at which the collision occurred.
HitPt Vec2
// EdgeD is the interpolation factor (0-1) along the BodyB edge
// (BodyBpmA -> BodyBpmB) at which the hit point lies.
EdgeD float64
// Normal is the collision normal, typically pointing from BodyB toward BodyA.
Normal Vec2
// Penetration is the overlap depth between the colliding shapes.
Penetration float64
}
CollisionInfo describes a single detected collision between a point mass on BodyA and either a point mass or an edge on BodyB.
func NewCollisionInfo ¶
func NewCollisionInfo(bodyA *Body, bodyApm int, bodyB *Body) CollisionInfo
NewCollisionInfo creates a CollisionInfo representing a collision between a point mass on bodyA and bodyB as a whole (not a specific edge). BodyBpmA and BodyBpmB are set to -1 to indicate no edge is involved.
func NewCollisionInfoWithEdge ¶
func NewCollisionInfoWithEdge(bodyA *Body, bodyApm int, bodyB *Body, bodyBpmA, bodyBpmB int) CollisionInfo
NewCollisionInfoWithEdge creates a CollisionInfo representing a collision between a point mass on bodyA and a specific edge on bodyB, defined by the point mass indices bodyBpmA and bodyBpmB.
type CollisionObserver ¶
type CollisionObserver interface {
// BodiesDidCollide is called once per step with all collisions detected
// during that step.
BodiesDidCollide(infos []CollisionInfo)
// BodyCollision is called for an individual collision, allowing the
// observer to react only when the penetration exceeds penetrationThreshold.
BodyCollision(info CollisionInfo, penetrationThreshold float64)
}
CollisionObserver receives notifications about collisions detected during a simulation step, allowing external code to react to them (e.g. play a sound, apply damage, trigger gameplay logic).
type Component ¶
type Component interface {
// Prepare is called once after the component is added to a body.
Prepare(body *Body)
// AccumulateInternalForces adds shape-preserving internal forces to
// each PointMass.Force in the body. worldRelaxing indicates whether the
// world is currently in its relaxation phase.
AccumulateInternalForces(body *Body, worldRelaxing bool)
// AccumulateExternalForces adds external forces (e.g. gravity) to
// each PointMass.Force in the body.
AccumulateExternalForces(body *Body, world *World)
Disabled() bool
}
Component represents something that can be attached to a Body to affect its physical behavior.
type EdgeJointLink ¶
type EdgeJointLink struct {
// A [0-1] ratio defining the point along the edge; 0.5 is the middle, while 0 or 1 acts like a [PointJointLink].
EdgeRatio float64
// contains filtered or unexported fields
}
Represents a joint link that links to an edge of a body
func NewEdgeJointLink ¶
func NewEdgeJointLink(body *Body, edgeIndex int, edgeRatio ...float64) *EdgeJointLink
NewEdgeJointLink returns new edge joint link with the specified parameters.
- edgeIndex: the index of the first point mass on the edge, the second is the next one with wrap around
- edgeRatio: A [0, 1] ratio defining the point along the edge; 0.5 is the middle, while 0 or 1 acts like a PointJointLink. See EdgeJointLink.EdgeRatio
func (*EdgeJointLink) AddVelocity ¶
func (e *EdgeJointLink) AddVelocity(velocity Vec2)
AddVelocity adds a velocity delta to both endpoints of the edge, weighted by EdgeRatio — mirrors ApplyForce's distribution.
func (*EdgeJointLink) ApplyForce ¶
func (e *EdgeJointLink) ApplyForce(force Vec2)
Applies a given force to the subject of this joint link
func (*EdgeJointLink) IsStatic ¶
func (e *EdgeJointLink) IsStatic() bool
IsStatic returns a value specifying whether the object referenced by this JointLinkType is static
func (*EdgeJointLink) Mass ¶
func (e *EdgeJointLink) Mass() (totalMass float64)
Gets the total mass of the subject of this joint link
func (*EdgeJointLink) Position ¶
func (e *EdgeJointLink) Position() Vec2
Gets the position, in world coordinates, at which this joint links with the underlying body
func (*EdgeJointLink) Translate ¶
func (e *EdgeJointLink) Translate(offset Vec2)
Applies a direct positional translation of this joint link by a given offset
func (*EdgeJointLink) Velocity ¶
func (e *EdgeJointLink) Velocity() Vec2
Velocity returns the velocity of the object this joint links to
type GravityComponent ¶
type GravityComponent struct {
Gravity Vec2 // The gravity vector to apply to the body
Relaxable bool
// contains filtered or unexported fields
}
Represents a Gravity component that can be added to a body to make it constantly affected by gravity
func NewGravityComponent ¶
func NewGravityComponent(gravityX, gravityY float64, relaxable bool) *GravityComponent
func (*GravityComponent) AccumulateExternalForces ¶
func (g *GravityComponent) AccumulateExternalForces(body *Body, world *World)
func (*GravityComponent) AccumulateInternalForces ¶
type InternalSpring ¶
func NewInternalSpring ¶
func NewInternalSpring(pmA int, pmB int, distance RestDistance, stiffness float64, damping float64, plasticity *SpringPlasticity) *InternalSpring
NewSpring creates a new spring.
type Joint ¶
type Joint interface {
Resolve(dt float64)
LinkA() JointLink
LinkB() JointLink
CollisionsAllowed() bool
}
Joint is implemented by every joint type (BodyJoint, SpringBodyJoint, ...). This is what allows the World to store and resolve different joint kinds polymorphically.
type JointLink ¶
type JointLink interface {
// Gets the body that this joint link is linked to.
Body() *Body
// Gets the position, in world coordinates, at which this joint links with
// the underlying body
Position() Vec2
// Gets the velocity of the object this joint links to
Velocity() Vec2
// Gets the total mass of the subject of this joint link
Mass() float64
// Gets a value specifying whether the object referenced by this
// JointLinkType is static
IsStatic() bool
// Applies a given force to the subject of this joint link.
ApplyForce(force Vec2)
// Applies a direct positional translation of this joint link by a given offset.
Translate(offset Vec2)
// AddVelocity adds a velocity delta to the subject(s) of this joint
// link, distributing it the same way ApplyForce does (e.g. across
// multiple point masses for Edge/Shape links).
AddVelocity(velocity Vec2)
}
Interface to be implemented by objects that specify the way a joint links with a body
type LineIntersectResult ¶
type LineIntersectResult struct {
// HitPt is the world-space point where the two line segments intersect.
HitPt Vec2
// Ua is the interpolation factor (0-1) along lineA at which the
// intersection occurs.
Ua float64
// Ub is the interpolation factor (0-1) along lineB at which the
// intersection occurs.
Ub float64
}
LineIntersectResult holds the outcome of a successful LineIntersect call.
func LineIntersect ¶
func LineIntersect(aStart, aEnd, bStart, bEnd Vec2) (LineIntersectResult, bool)
LineIntersect computes the intersection point of two finite line segments, lineA and lineB. It returns the intersection details and true if the segments intersect within their bounds; otherwise it returns a zero value and false (including the degenerate case where the segments are parallel or collinear).
type MaterialPair ¶
type MaterialPair struct {
// Whether the collision between the two bodies should happen
Collide bool
// The elasticity of the point mass when bouncing off the bodies
Elasticity float64
// The relative friction between the two bodies
Friction float64
// A function to call and utilize as a collision filter when figuring out
// whether the two bodies should collide
CollisionFilterFunc func(info CollisionInfo, normalVelocity float64) bool
}
MaterialPair represents information about the collision response behavior between two bodies
func DefaultMaterialPair ¶
func DefaultMaterialPair() MaterialPair
DefaultMaterialPair returns default MaterialPair
Friction: 0.3 Elasticity: 0.2
type Matrix3x3 ¶
type Matrix3x3 struct {
// contains filtered or unexported fields
}
Matrix3x3 represents a 2D affine transformation matrix.
The underlying structure is optimized so that its zero-value inherently represents the identity matrix. To achieve this, the main diagonal components
func NewMatrix3x3 ¶
NewMatrix3x3 returns a matrix that combines scale, rotation, and translation. Transformation order: scale -> rotate -> translate.
func (Matrix3x3) Apply ¶
Apply transforms the given 2D vector 'v' by multiplying it with the matrix.
func (*Matrix3x3) Clear ¶
func (g *Matrix3x3) Clear()
Clear resets the matrix to the identity transformation (zero-value).
func (*Matrix3x3) Rotate ¶
Rotate applies a counter-clockwise rotation (in radians) to the matrix. This effectively pre-multiplies the current matrix by a rotation matrix.
type PinJoint ¶
type PinJoint struct {
// MaxCorrection clamps the magnitude of the per-step position
// correction (and matching velocity impulse) applied to close the
// separation, to avoid explosive corrections after a large
// disturbance (e.g. body teleported, high dt spike). Zero means
// unclamped.
MaxCorrection float64
// contains filtered or unexported fields
}
PinJoint rigidly binds two JointLinks to occupy the same world-space point, using velocity impulses (not forces or direct position snapping) to resolve separation. Both bodies remain free to rotate/deform around the shared point — only the point itself is prevented from separating.
This is a fully rigid weld: there is no softness factor and no rest-distance range. Separation is closed completely every Resolve call, both in position and in relative velocity along the separation axis, so no residual gap is left to accumulate step to step.
func NewPinJoint ¶
NewPinJoint creates a joint that rigidly locks link a and link b to the same world point. There is no distance parameter (unlike NewSpringJoint) and no softness parameter (unlike a Baumgarte-style pin) — the joint always fully closes separation to zero every step, behaving like a weld.
func (*PinJoint) CollisionsAllowed ¶
func (j *PinJoint) CollisionsAllowed() bool
func (*PinJoint) Resolve ¶
Resolve resolves this joint by rigidly closing the separation between the two links: position is corrected fully (not fractionally) and the full relative velocity component along the separation axis is cancelled, not just the diverging part. Called once per physics step, same as SpringJoint.Resolve.
type PointJointLink ¶
type PointJointLink struct {
// contains filtered or unexported fields
}
Represents a joint link that links directly to a point mass of a body
func NewPointJointLink ¶
func NewPointJointLink(body *Body, pointMassIndex int) *PointJointLink
NewPointJointLink returns new NewPointJointLink
func (*PointJointLink) AddVelocity ¶
func (p *PointJointLink) AddVelocity(velocity Vec2)
AddVelocity adds a velocity delta to the linked point mass.
func (*PointJointLink) ApplyForce ¶
func (p *PointJointLink) ApplyForce(force Vec2)
Applies a given force to the subject of this joint link
func (*PointJointLink) IsStatic ¶
func (p *PointJointLink) IsStatic() bool
IsStatic returns a value specifying whether the object referenced by this JointLinkType is static
func (*PointJointLink) Mass ¶
func (p *PointJointLink) Mass() (totalMass float64)
Gets the total mass of the subject of this joint link
func (*PointJointLink) Position ¶
func (p *PointJointLink) Position() Vec2
Gets the position, in world coordinates, at which this joint links with the underlying body
func (*PointJointLink) Translate ¶
func (p *PointJointLink) Translate(offset Vec2)
Applies a direct positional translation of this joint link by a given offset
func (*PointJointLink) Velocity ¶
func (p *PointJointLink) Velocity() Vec2
Velocity returns the velocity of the object this joint links to
type PointMass ¶
type PointMass struct {
// Mass is the mass of the point. Use Infinity (or math.Inf(1)) to mark
// the point as immovable/static; Integrate becomes a no-op in that case.
Mass float64
// Position is the current world-space position of the point.
Position Vec2
// Velocity is the current velocity of the point.
Velocity Vec2
// Force is the force currently accumulated on the point, to be applied
// during the next call to Integrate. It is reset to zero after each
// integration step.
Force Vec2
// Normal is an optional surface normal associated with the point,
// typically used for collision response.
Normal Vec2
}
PointMass represents a single simulated particle with mass, position, velocity, and any accumulated force to apply on the next integration step. Point masses are the fundamental building blocks that soft/rigid Bodies.
func NewPointMass ¶
NewPointMass creates a new PointMass with the given mass and initial position. Velocity, Force, and Normal are left at their zero values.
func (*PointMass) ApplyForce ¶
ApplyForce accumulates force into the point mass's current Force, to be applied on the next call to Integrate.
func (*PointMass) Integrate ¶
Integrate advances the point mass's velocity and position by elapsed seconds using simple semi-implicit (symplectic) Euler integration: the accumulated Force is converted to acceleration (Force / Mass), applied to Velocity, and Velocity is then applied to Position. The accumulated Force is cleared afterward.
If Mass is infinite or NaN (i.e. the point is static/immovable), this is a no-op and the point's position and velocity are left unchanged.
type PressureComponent ¶
type PressureComponent struct {
// The current volume (area) enclosed by the body's shape
Volume float64
// The gas pressure constant used to push outward on the body's edges
GasPressure float64
// contains filtered or unexported fields
}
PressureComponent simulates internal gas pressure that pushes a body's edges outward, keeping soft-body shapes inflated (like a balloon).
func NewPressureComponent ¶
func NewPressureComponent(gasPressure float64) *PressureComponent
NewPressureComponent returns a new PressureComponent that can be added to a body to simulate outward gas pressure against its edges.
func (*PressureComponent) AccumulateExternalForces ¶
func (*PressureComponent) AccumulateInternalForces ¶
func (p *PressureComponent) AccumulateInternalForces(body *Body, relaxing bool)
AccumulateInternalForces recomputes the body's enclosed volume (area) and applies an outward force along each point's normal proportional to the gas pressure and inversely proportional to the current volume, so the body resists being squeezed.
type Resolver ¶
type Resolver interface {
// Resolve advances the implementation's state by dt seconds.
Resolve(dt float64)
}
Resolver is implemented by anything that can advance its own state by a fixed time step, such as a physics world or constraint solver.
type RestDistance ¶
type RestDistance struct {
// Distance is ranged between a minimum and maximum value
IsRanged bool
// Fixed distance (used when IsRanged is false)
Fixed float64
// contains filtered or unexported fields
}
Specifies a rest distance for a body joint or spring. Distances can either be fixed by a distance, or ranged so forces only apply when distance is outside a tolerance range.
func CalcPlasticity ¶
func CalcPlasticity(dist float64, rd RestDistance, sp *SpringPlasticity) RestDistance
CalcPlasticity calculates a new resting distance based on provided plasticity parameters. The resulting resting distance is returned by the function.
- Parameters:
- dist: The current distance of the spring
- rd: The resting distance for the spring
- Returns: The new rest distance to the spring, after plasticity is applied.
func NewFixedRestDistance ¶
func NewFixedRestDistance(value float64) RestDistance
func NewRangedRestDistance ¶
func NewRangedRestDistance(min, max float64) RestDistance
func (RestDistance) Clamp ¶
func (r RestDistance) Clamp(value float64) float64
Clamp clamps a given value to be within the range of this rest distance. If RestDistance.IsRanged is false (fixed mode), the value parameter is ignored and RestDistance.Fixed is returned. If RestDistance.IsRanged is true (ranged mode), the value is clamped between min and max.
func (RestDistance) InRange ¶
func (r RestDistance) InRange(value float64) bool
InRange returns whether a given value is within the range of this rest distance. If RestDistance.IsRanged is false (fixed mode), checks for exact equality. If RestDistance.IsRanged is true (ranged mode), performs value >= min && value <= max.
func (*RestDistance) MaxDist ¶
func (r *RestDistance) MaxDist() float64
MaxDist returns the maximum distance for this rest distance. If RestDistance.IsRanged is false (fixed mode), returns the fixed distance. If RestDistance.IsRanged is true (ranged mode), returns the maximum distance.
func (*RestDistance) MinDist ¶
func (r *RestDistance) MinDist() float64
MinDist returns the minimum distance for this rest distance. If RestDistance.IsRanged is false (fixed mode), returns the fixed distance. If RestDistance.IsRanged is true (ranged mode), returns the minimum distance.
func (*RestDistance) SetMaxDist ¶
func (r *RestDistance) SetMaxDist(value float64)
SetMaximumDistance sets the maximum distance for this rest distance. If RestDistance.IsRanged is false (fixed mode), updates the RestDistance.Fixed value. If RestDistance.IsRanged is true (ranged mode), updates the max value.
func (*RestDistance) SetMinDist ¶
func (r *RestDistance) SetMinDist(value float64)
SetMinDist sets the minimum distance for this rest distance. If RestDistance.IsRanged is false (fixed mode), updates the RestDistance.Fixed value. If RestDistance.IsRanged is true (ranged mode), updates the min value.
func (RestDistance) Squared ¶
func (r RestDistance) Squared() RestDistance
Squared returns a new rest distance structure which represents the square of this rest distance's parameters. If RestDistance.IsRanged is false (fixed mode), returns a new fixed rest distance with squared RestDistance.Fixed value. If RestDistance.IsRanged is true (ranged mode), returns a new ranged rest distance with squared min and max.
type Shape ¶
type Shape []Vec2
Shape contains a set of points that is equivalent as the local shape of a Body.
Points must be added in a counter-clockwise (CCW) fashion to align with screen space coordinates where the y-axis grows downwards, ensuring outward-facing edge normals.
func Rectangle ¶
Rectangle creates a rectangle shape with optional corner chamfering. Parameters:
- w, h: width and height of the rectangle.
- cornerRatio: optional, ratio of corner cut from 0.0 to 0.5. 0.5 means the cut reaches exactly the center of the shortest edge.
func RegularPolygon ¶
RegularPolygon returns a new regular polygon shape with radius and n number of vertices. It can also be used to create circles. The polygon is rotated so that an edge is always flat at the bottom. Vertices are in CCW (counter-clockwise) order.
func ShapeFromCoords ¶
ShapeFromCoords creates a shape from a flat list of x, y, x, y, ... coordinates. Points must be given in counter-clockwise (CCW) order.
If the attribute contains an odd number of coordinates, the last one will be ignored.
Example:
ShapeFromCoords(0.29, 0.22, -0.09, -0.37, -0.3, 0.24)
ShapeFromCoords([]float64{1, -1, 2, 4, 3, 1})
func ShapeFromSVGPath ¶
ShapeFromSVGPath makes Shape from an SVG path data string ('d' attribute) Note: Only 'M' (MoveTo) and 'L' (LineTo) commands are supported.
https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/d
If the attribute contains an odd number of coordinates, the last one will be ignored. Points must be given in counter-clockwise (CCW) order.
Example:
ShapeFromSVGPath("M 0.29 0.22 L -0.09 -0.37 L -0.3 0.24")
func ShapeFromSVGPolygonPoints ¶
ShapeFromSVGPolygonPoints makes shape from SVG polygon points string.
https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/points
If the attribute contains an odd number of coordinates, the last one will be ignored. Points must be given in counter-clockwise (CCW) order.
Example:
ShapeFromSVGPolygonPoints("0.29 0.22 -0.09 -0.37 -0.3 0.24")
func (Shape) IsCCW ¶
IsCCW reports whether the shape's vertices are wound counter-clockwise (CCW) in screen space, where the Y axis grows downward. Returns false for shapes with fewer than 3 vertices, since winding is undefined.
func (Shape) PolygonPointsString ¶
PolygonPointsString returns the vertices in the format used by the SVG <polygon> element's points, which is also the format accepted by ShapeFromSVGPolygonPoints. Precision specifies the number of digits after the decimal point.
func (*Shape) Recenter ¶
func (c *Shape) Recenter()
Recenter re-centers the points of this shape in-place so its centroid lies at (0, 0).
func (*Shape) Reverse ¶
func (c *Shape) Reverse()
Reverse reverses the vertices, so they rotate clockwise if they were counterclockwise, and counterclockwise if they were clockwise.
func (*Shape) TransformByMatrix ¶
TransformByMatrix transforms vertices on this this shape inplace using a given Matrix3x3.
func (*Shape) TransformByMatrixToTarget ¶
TransformByMatrixToTarget transforms the points on this this shape using a given transformation matrix, applying the result into a given target slice of points.
- note: The target slice of points must have the **same** count of vertices as this shape.
func (*Shape) TranslateVerticesToTarget ¶
type ShapeJointLink ¶
type ShapeJointLink struct {
// The indices of this shape joint link
Indexes []int
/// The Offset to apply to the position of this shape joint, in body
/// coordinates
Offset Vec2
// contains filtered or unexported fields
}
Represents a joint link that links to multiple point masses of a body
func NewShapeJointLink ¶
func NewShapeJointLink(body *Body, pointMassIndexes []int) *ShapeJointLink
ShapeJointLink returns new ShapeJointLink. See ShapeJointLink
func (*ShapeJointLink) AddVelocity ¶
func (s *ShapeJointLink) AddVelocity(velocity Vec2)
AddVelocity adds a velocity delta at the offset point, distributing it across the indexed point masses the same way ApplyForce distributes a force — including the rotational component so a velocity change at an offset point produces angular motion around the shape's centroid, not just a uniform translation.
func (*ShapeJointLink) ApplyForce ¶
func (s *ShapeJointLink) ApplyForce(force Vec2)
Applies a given force to the subject of this joint link
func (*ShapeJointLink) IsStatic ¶
func (s *ShapeJointLink) IsStatic() bool
IsStatic returns a value specifying whether the object referenced by this JointLinkType is static
func (*ShapeJointLink) Mass ¶
func (s *ShapeJointLink) Mass() (mass float64)
Gets the total mass of the subject of this joint link
func (*ShapeJointLink) Position ¶
func (s *ShapeJointLink) Position() Vec2
Position returns the position, in world coordinates, at which this joint links with the underlying body — the centroid of the indexed point masses, plus Offset rotated into world space by the shape's current deformation angle (so the offset point follows the body's rotation, not just its centroid).
func (*ShapeJointLink) SubDerivedAngle ¶
func (s *ShapeJointLink) SubDerivedAngle() float64
SubDerivedAngle returns the average angle of the vertices of this ShapeJointLink, based on the body's original shape's vertices.
This represents the local deformation angle of this specific point mass subset, which may differ from the body's overall derivedAngle in a soft body where different regions can rotate independently.
func (*ShapeJointLink) Translate ¶
func (s *ShapeJointLink) Translate(offset Vec2)
Applies a direct positional translation of this joint link by a given offset
func (*ShapeJointLink) Velocity ¶
func (s *ShapeJointLink) Velocity() (vel Vec2)
Velocity returns the velocity of the object this joint links to — the average velocity of the indexed point masses (centroid velocity), plus the rotational contribution from Offset, computed as ω × r using the body's current angular velocity. This keeps Velocity() consistent with the offset point returned by Position(): both describe the same physical point on the rotating body, not just the centroid.
type ShapeMatchComponent ¶
type ShapeMatchComponent struct {
// The spring stiffness for all points used to pull points back toward the base shape
Stiffness float64
// The spring damping for all points used to pull points back toward the base shape
Damping float64
// The point mass indices to match against; empty means match the full shape
TargetIndices []int
// contains filtered or unexported fields
}
ShapeMatchComponent pulls a body's point masses back toward its original base shape using spring forces, so the body tends to retain its shape after deformation. It can target the full shape or a subset of points.
func DefaultShapeMatchComponent ¶
func DefaultShapeMatchComponent() *ShapeMatchComponent
DefaultShapeMatchComponent returns a full-shape ShapeMatchComponent with default spring constants.
func NewShapeMatchComponent ¶
func NewShapeMatchComponent(stiffness, damping float64, indices []int) *ShapeMatchComponent
NewShapeMatchComponent returns a new ShapeMatchComponent that pulls a body (or a subset of its points) back toward its original base shape using a spring force. Pass nil (or an empty slice) for indices to match the full shape, or a list of point mass indices to match only that subset.
func (*ShapeMatchComponent) AccumulateExternalForces ¶
func (*ShapeMatchComponent) AccumulateInternalForces ¶
func (s *ShapeMatchComponent) AccumulateInternalForces(body *Body, relaxing bool)
AccumulateInternalForces applies shape-matching spring forces if shape matching is enabled and the spring constant is positive.
func (*ShapeMatchComponent) SetTarget ¶
func (s *ShapeMatchComponent) SetTarget(indices []int)
SetTarget changes what the component matches against: pass nil (or an empty slice) to match the full shape, or a list of point mass indices to match only that subset.
type Spring ¶
type Spring struct {
// Rest distance of the spring, or the distance the spring tries to maintain.
RestDistance RestDistance
// Stiffness is the spring stiffness.
Stiffness float64
// Damping is the spring damping.
Damping float64
// Plasticity specifies the plasticity properties of this spring.
// If nil, plasticity is disabled and spring never deforms permanently.
Plasticity *SpringPlasticity
// Spring type
Type SpringType
}
Spring represents an spring and keeps points close together.
func (*Spring) UpdatePlasticity ¶
UpdatePlasticity updates the plasticity settings of this spring. Does nothing, if plasticity is not configured.
type SpringComponent ¶
type SpringComponent struct {
// The number of default edge springs built between consecutive point masses
EdgeSpringsCount int
// All springs belonging to this component (edge springs first, then extra springs) See [SpringComponent.AddExtraSpring]
Springs []*InternalSpring
// The stiffness constant
DefaultStiffness float64
// The damping constant
DefaultDamping float64
// contains filtered or unexported fields
}
SpringComponent adds spring-based physics to a body's point masses.
By default it places a spring between every pair of consecutive point masses along the body's outline (i.e. one spring per edge, wrapping around to close the shape), plus any extra springs added manually via SpringComponent.AddExtraSpring. Each spring pulls its two endpoints back toward a rest distance whenever they drift apart or are pushed together, which is what keeps neighboring points from separating or overlapping.
func DefaultSpringComponent ¶
func DefaultSpringComponent() *SpringComponent
Returns default SpringComponent
func NewSpringComponent ¶
func NewSpringComponent(stiffness, damping float64) *SpringComponent
NewSpringComponent returns new SpringComponent.
func (*SpringComponent) AccumulateExternalForces ¶
func (*SpringComponent) AccumulateInternalForces ¶
func (s *SpringComponent) AccumulateInternalForces(body *Body, relaxing bool)
AccumulateInternalForces applies each spring's force between its two point masses, clamping the rest distance to the spring's actual current distance when applicable, and updates spring plasticity (permanent deformation) when not relaxing. AccumulateInternalForces applies each spring's force between its two point masses, clamping the rest distance to the spring's actual current distance when applicable, and updates spring plasticity (permanent deformation) when not relaxing.
func (*SpringComponent) AddExtraSpring ¶
func (s *SpringComponent) AddExtraSpring(body *Body, pointA, pointB int, stiffness, damping float64, plasticity *SpringPlasticity) *InternalSpring
AddExtraSpring adds an internal spring to this body. plasticity is an optional argument and may be nil.
func (*SpringComponent) ApplyDefaults ¶
func (s *SpringComponent) ApplyDefaults()
ApplyDefaults sets the SpringComponent.DefaultStiffness and SpringComponent.DefaultDamping values for all springs.
func (*SpringComponent) ClearAllSprings ¶
func (s *SpringComponent) ClearAllSprings(body *Body)
ClearAllSprings removes all springs (including any added via SpringComponent.AddExtraSpring
func (*SpringComponent) Prepare ¶
func (s *SpringComponent) Prepare(body *Body)
Prepare rebuilds all internal springs for the body, discarding any previously added springs and re-creating the default edge springs.
func (*SpringComponent) SetAll ¶
func (s *SpringComponent) SetAll(stiffness, damping float64)
SetAll sets the stiffness and damping of all springs (edge + extra)
func (*SpringComponent) SetAllEdges ¶
func (s *SpringComponent) SetAllEdges(stiffness, damping float64)
SetAllEdges sets the stiffness and damping of every edge springs
func (*SpringComponent) SetExtraAt ¶
func (s *SpringComponent) SetExtraAt(relativeIndex int, stiffness, damping float64)
SetExtraAt sets the stiffness and damping of an extra (non-edge) spring. relativeIndex is the spring's position among the extra springs only (0 = first extra spring added after the edge springs), not its index in the full Springs slice. See SpringComponent.AddExtraSpring
func (*SpringComponent) SetSpringPlasticity ¶
func (s *SpringComponent) SetSpringPlasticity(relativeIndex int, plasticity *SpringPlasticity)
type SpringJoint ¶
type SpringJoint struct {
Spring
// contains filtered or unexported fields
}
SpringJoint represents a joint that links two JointLink's with spring forces
func NewSpringJoint ¶
func NewSpringJoint(a, b JointLink, coefficient, damping float64, distance ...RestDistance) *SpringJoint
func (*SpringJoint) CollisionsAllowed ¶
func (j *SpringJoint) CollisionsAllowed() bool
func (*SpringJoint) Resolve ¶
func (j *SpringJoint) Resolve(dt float64)
Resolve resolves this joint
dt is the delta time to update the resolve on
func (*SpringJoint) SetPlasticity ¶
func (j *SpringJoint) SetPlasticity(p *SpringPlasticity)
SetPlasticity enables plasticity for this joint, using the joint's current rest distance as the reference point for the plasticity limit. Pass nil to disable plasticity.
type SpringPlasticity ¶
type SpringPlasticity struct {
// YieldRatio is the ratio (of resting distance vs actual length) before plasticity starts
// to change the resting length of the spring, deforming it permanently.
YieldRatio float64
// Rate is the plasticity rate for the spring.
// When the rest distance of a spring goes past its yield limit, the
// resting distance of the spring is stretched so it deforms 'plastically'
// by adapting the resting length to be the resulting factor between the
// rest length and the actual length, times this rate.
Rate float64
// Limit is a factor limit at which the plasticity stops affecting the rest length
// of the spring beyond its initial rest length.
Limit float64
// contains filtered or unexported fields
}
SpringPlasticity specifies plasticity properties of a spring.
Plasticity permanently affects a spring's rest length by modifying it when its length is stretched beyond a certain limit.
func DefaultSpringPlasticity ¶
func DefaultSpringPlasticity() *SpringPlasticity
DefaultSpringPlasticity returns a SpringPlasticity with default values.
func NewSpringPlasticity ¶
func NewSpringPlasticity(yieldRatio float64, rate float64, limit float64) *SpringPlasticity
NewSpringPlasticity creates a new SpringPlasticity with the given values.
type SpringType ¶
type SpringType uint8
SpringType identifies what a spring connection represents within the simulation, distinguishing default perimeter springs, extra internal springs, and springs used by joints between separate bodies.
const ( // EdgeSpring is a default spring between two consecutive point masses // along a body's outline (perimeter), automatically created to keep // the shape's outline together. EdgeSpring SpringType = iota // ExtraSpring is an extra spring added between two point masses // that are not necessarily adjacent on the outline, used to connect // edges to each other and help the body resist internal deformation // (e.g. shape-holding cross braces). Added via [SpringComponent.AddExtraSpring]. ExtraSpring // JointSpring is the spring used by a [SpringBodyJoint], connecting two // joint links — typically belonging to two separate bodies — rather // than two point masses within the same body. JointSpring )
type StickyRayComponent ¶
type StickyRayComponent struct {
// IgnoreJoinedBodies skips raycasting against bodies connected to this
// one via a Joint, avoiding redundant sticky forces on an existing joint.
IgnoreJoinedBodies bool
// RayLength is the length of the ray cast out from each point mass
RayLength float64
// Stiffness is the stiffness of the spring pulling toward the hit edge
Stiffness float64
// Damping is the damping applied to the spring force
Damping float64
// contains filtered or unexported fields
}
StickyRayComponent sticks a body to whatever other body its point masses' rays hit. For each point mass, a short ray is cast outward along that point's normal; if it hits another body, the closest point on that body's nearest edge is found, and the originating point mass is pulled toward that point with a spring force (like tape/velcro between two soft bodies). The target is not the middle of the edge — it's whichever point along the edge sits closest to where the ray actually hit.
func DefaultStickyRayComponent ¶
func DefaultStickyRayComponent() *StickyRayComponent
DefaultStickyRayComponent returns a StickyRayComponent with default settings
func NewStickyRayComponent ¶
func NewStickyRayComponent(rayLength, stiffness, damping float64, ignoreJoinedBodies bool) *StickyRayComponent
NewStickyRayComponent creates a new StickyRayComponent See StickyRayComponent for info
func (*StickyRayComponent) AccumulateExternalForces ¶
func (s *StickyRayComponent) AccumulateExternalForces(body *Body, world *World)
AccumulateExternalForces applies sticky rays to other bodies
func (*StickyRayComponent) AccumulateInternalForces ¶
type UnimplementedCollisionObserver ¶
type UnimplementedCollisionObserver struct{}
UnimplementedCollisionObserver is a no-op CollisionObserver that can be embedded to satisfy the CollisionObserver interface without implementing every method.
func (*UnimplementedCollisionObserver) BodiesDidCollide ¶
func (u *UnimplementedCollisionObserver) BodiesDidCollide(infos []CollisionInfo)
BodiesDidCollide is a no-op implementation of CollisionObserver.
func (*UnimplementedCollisionObserver) BodyCollision ¶
func (u *UnimplementedCollisionObserver) BodyCollision(info CollisionInfo, penetrationThreshold float64)
BodyCollision is a no-op implementation of CollisionObserver.
type Vec2 ¶
type Vec2 struct {
X, Y float64
}
Vec2 represents a 2D vector with X and Y components.
func AveragePointMassPosition ¶
AveragePointMassPosition returns the centroid (mean position) of pointMasses. Returns the zero Vec2 if pointMasses is empty.
func AveragePointMassVelocity ¶
AveragePointMassVelocity returns the mean velocity across pointMasses. Returns the zero Vec2 if pointMasses is empty.
func AverageVec2 ¶
AverageVec2 returns the mean of the given vectors. Returns the zero Vec2 if vectors is empty.
func CalcSpringForce ¶
CalcSpringForce computes the force exerted by a damped spring connecting two points (posA, velA) and (posB, velB), given the spring's rest length (distance), stiffness, and damping factor. The returned force is directed along the axis between the two points and should be applied to posA (and its negation to posB). Returns the zero Vec2 if the two points are closer than epsilonSpring, to avoid dividing by a near-zero distance.
func (Vec2) Cross ¶
Cross calculates the 2D vector cross product analog. The cross product of 2D vectors results in a 3D vector with only a z component. This function returns the magnitude of the z value.
func (Vec2) DistSq ¶
DistSq returns the squared distance between this and other.
Faster than v.Dist() when you only need to compare distances.
func (Vec2) Equals ¶
Equals checks if two vectors are equal. (Be careful when comparing floating point numbers!)
func (Vec2) EqualsPr ¶
EqualsP returns they are practically equal with each other within a delta tolerance.
func (Vec2) Floor ¶
Floor returns vector with all components rounded down (towards negative infinity).
func (Vec2) MagSq ¶
MagSq returns the magnitude (length) of the vector, squared.
This method is often used to improve performance since, unlike Mag(), it does not require a Sqrt() operation.
func (Vec2) Reflect ¶
Reflect returns the reflection of the vector v over the given normal. normal should be a normalized (unit) vector.
func (Vec2) Slerp ¶
Slerp performs spherical linear interpolation between two vectors with given weight value in [0,1] range, returning interpolated vector
type World ¶
type World struct {
// The bodies contained within this world
Bodies []*Body
// The joints contained within this world
Joints []Joint
// MaterialPairs is a 2D lookup table used to resolve collisions between different materials.
// It is accessed using material IDs (e.g., MaterialPairs[idA][idB]) to determine
// shared physical properties like friction, bounciness, and custom collision rules.
MaterialPairs [][]MaterialPair
// The default material pair for newly created materials
DefaultMatPair MaterialPair
// The object to report collisions to
CollisionObserver CollisionObserver
// The threshold at which penetrations are ignored, since they are far too
// deep to be resolved without applying unreasonable forces that will
// destabilize the simulation. Default is 0.3
PenetrationThreshold float64
// contains filtered or unexported fields
}
func (*World) AddJoint ¶
Adds a joint to the world. Joints call this automatically during their initialization
func (*World) AddMaterial ¶
Adds a new material to the world. All previous material data is kept intact.
func (*World) AreBodiesJoined ¶
Returns `true` if the two given bodies are joined to one another. SONRA
func (*World) BodiesIntersectingLine ¶
Returns a vector of bodies intersecting with the given line.
func (*World) BodiesIntersectingShape ¶
func (w *World) BodiesIntersectingShape( shape Shape, worldPos Vec2, ignoreTest func(*Body) bool, outResults []*Body, tempBuffer Shape, ) []*Body
BodiesIntersectingShape returns all bodies that overlap a given shape at a specified point in world coordinates.
This method is optimized for zero-allocation performance. It utilizes pre-allocated slices for both the result set and the vertex transformations to prevent heap allocations and reduce Garbage Collector overhead during the game loop.
Parameters:
- Shape: A shape that represents the segments to query. Must contain at least 2 vertices.
- worldPos: The location in world coordinates to apply to the shape when performing the query.
- ignoreTest: An optional function applied to every body intersecting the shape to filter out results. If the function returns true, the body is ignored. Defaults to nil.
- outResults: A pre-allocated slice where the intersecting bodies will be appended. To reuse this slice across frames, it should be cleared beforehand (e.g., results = results[:0]).
- tempBuffer: A pre-allocated slice used internally to store the transformed vertices of the shape. Its capacity must be greater than or equal to the number of vertices in the shape.
Returns:
- A slice containing all bodies that intersect with the shape. This is the populated 'outResults' slice. If the shape contains less than 2 points, the unmodified 'outResults' slice is returned.
func (*World) BodiesUnder ¶
Given a global point, returns all bodies that contain this point. Useful for picking objects with a cursor, etc.
func (*World) BodyUnder ¶
Given a global point, returns a body (if any) that contains this point. Useful for picking objects with a cursor, etc.
func (*World) ClosestPoint ¶
func (w *World) ClosestPoint(pt Vec2, ignoreFunction func(*Body) bool) (closestBody *Body, closestHitPoint Vec2, found bool)
ClosestPoint returns the closest body and the nearest point on its surface to the given position. The hit point always lies on the body's boundary. Bodies can be excluded using ignoreFunction.
func (*World) ClosestPointMass ¶
Finds the closest PointMass in the world to a given point
func (*World) RayCast ¶
func (w *World) RayCast(start, end Vec2, bitmask Bitmask, ignoreTest func(*Body) bool) (retPt Vec2, body *Body)
Casts a ray between the given points and returns the first body it comes in contact with.
Parameters:
- start: The start point to cast the ray from, in world coordinates
- end: The end point to end the ray cast at, in world coordinates
- bitmask: An optional collision bitmask that filters the bodies to collide using a bitwise AND (&) operation. If the value specified is 0, collision filtering is ignored and all bodies are considered for collision.
- ignoreTest: Optional function that will be called for each body along the way (not guaranteed to execute in order of farthest to closest body) that tests whether the body should be ignored during ray casting.
Returns:
- An optional tuple containing the farthest point reached by the ray, and a Body value specifying the body that was closest to the ray, if it hit any body, or nil if it hit nothing.
func (*World) RelaxBodies ¶
Relaxes a list of bodies in this simulation so they match a more approximate rest shape once simulation starts.
This will move or change the position of each body after iterations are done. It performs collisions and joint resolving of only the bodies or joints that are related to the bodies array, and resets the velocities to 0 before finishing.
Only body joints that involve bodies contained within the passed body list are executed. Joints that involve a body within this list and another body that is not in the list are not resolved during relaxation.
All body joints, velocities, and components are executed, except those with relaxable == false.
Parameters:
- bodies: The list of bodies to relax.
- iterations: The number of iterations of relaxation to apply.
- timestep: The timestep (in seconds) of each iteration.
Precondition: iterations > 0.
func (*World) RelaxWorld ¶
Relaxes all bodies in this simulation so they match a more approximate rest shape once simulation starts.
This will move or change the position of each body after iterations are done. It performs collisions and joint resolving, and resets the velocities to 0 before finishing.
All body joints, velocities, and components are executed, except those with relaxable == false.
Parameters:
- iterations: The number of iterations of relaxation to apply.
- timestep: The timestep (in seconds) of each iteration.
Precondition: iterations > 0.
func (*World) RemoveBody ¶
Removes a body from the world. Call this outside of an update to remove the body.
func (*World) Reset ¶
func (w *World) Reset()
Reset resets the world's contents to their initial state and readies it to be loaded again.
func (*World) SetMaterialPairCollide ¶
Enables or disables collision between 2 materials.
func (*World) SetMaterialPairData ¶
Sets the collision response variables for a pair of materials.
func (*World) SetMaterialPairFilterCallback ¶
func (w *World) SetMaterialPairFilterCallback(a, b int, filter func(CollisionInfo, float64) bool)
Sets a user function to call when 2 bodies of the given materials collide.
func (*World) SetWorldLimits ¶
SetWorldLimits sets the boundaries of the simulation world. The world is divided into a grid for broad-phase collision detection, with the grid step size calculated based on the world size and subdivision count. The world is divided into worldGridSubdivision x worldGridSubdivision cells (default is 64x64 = 4096 cells).
Parameters:
- min: The minimum corner of the world bounds.
- max: The maximum corner of the world bounds.