Documentation
¶
Index ¶
- Constants
- func AngleBetweenTwoVectors(vector, referenceVector Vec2) float32
- func AngleOfParticlesWithLocalPositions(pA, pB, pC *Particle) float32
- func ApplyForceToParticleSegment(pA, pB *Particle, force Vec2, fromPosition Vec2)
- func CanCollide(bodyA, bodyB *Body, checkBodiesAreEnabled bool) bool
- func RegisterAreaBody(b *Body, ab *AreaBody)
- func RegisterPostUpdater(b *Body, fn func())
- func RegisterRigidBody(b *Body, rb *RigidBody)
- func RegisterSoftBody(b *Body, sb *SoftBody)
- func SetConvexPartitioner(f func(polygon []*Particle) [][]*Particle)
- func SortParticlesHorizontal(a, b *Particle) bool
- type AABB
- func (a AABB) Area() float32
- func (a AABB) CenterPosition() Vec2
- func (a AABB) Fatten(amount float32) AABB
- func (a AABB) FattenedWithRate(rate float32) AABB
- func (a AABB) IsCollidingWith(other AABB) bool
- func (a AABB) IsContain(other AABB) bool
- func (a AABB) Perimeter() float32
- func (a AABB) SetMinMax(min, max Vec2) AABB
- func (a AABB) Size() Vec2
- type AngleConstraint
- func (ac *AngleConstraint) CurrentAngle() float32
- func (ac *AngleConstraint) Enabled() bool
- func (ac *AngleConstraint) MaxAngle() float32
- func (ac *AngleConstraint) MinAngle() float32
- func (ac *AngleConstraint) ParticleA() *Particle
- func (ac *AngleConstraint) ParticleB() *Particle
- func (ac *AngleConstraint) ParticleC() *Particle
- func (ac *AngleConstraint) Rigidity() float32
- func (ac *AngleConstraint) SetEnabled(b bool) *AngleConstraint
- func (ac *AngleConstraint) SetMaxAngle(v float32) *AngleConstraint
- func (ac *AngleConstraint) SetMinAngle(v float32) *AngleConstraint
- func (ac *AngleConstraint) SetParticleA(p *Particle) *AngleConstraint
- func (ac *AngleConstraint) SetParticleB(p *Particle) *AngleConstraint
- func (ac *AngleConstraint) SetParticleC(p *Particle) *AngleConstraint
- func (ac *AngleConstraint) SetRigidity(r float32) *AngleConstraint
- func (ac *AngleConstraint) Update(specifiedRigidity float32, addToAccumulatedForces bool)
- type AreaBody
- func (ab *AreaBody) AsBody() *Body
- func (ab *AreaBody) CheckBodies()
- func (ab *AreaBody) ComputeLinearForce(body *Body) Vec2
- func (ab *AreaBody) GetBodies() []*Body
- func (ab *AreaBody) GravityFreeEnabled() bool
- func (ab *AreaBody) HasBody(b *Body) bool
- func (ab *AreaBody) LinearForceToApply() Vec2
- func (ab *AreaBody) SetGravityFreeEnabled(b bool) *AreaBody
- func (ab *AreaBody) SetLinearForceToApply(v Vec2) *AreaBody
- type Body
- func (b *Body) AABB() AABB
- func (b *Body) AddMesh(m *Mesh) *Body
- func (b *Body) AddPosition(v Vec2, withPreviousPosition ...bool) *Body
- func (b *Body) AddPreviousPosition(v Vec2) *Body
- func (b *Body) AddPreviousRotation(angleRadian float32) *Body
- func (b *Body) AddRotation(angleRadian float32, withPreviousRotation ...bool) *Body
- func (b *Body) AirFriction() float32
- func (b *Body) AllowKinematicCollisions() bool
- func (b *Body) ApplyForce(force Vec2) *Body
- func (b *Body) BodyType() BodyType
- func (b *Body) CanGiveCollisionResponseTo(other *Body) bool
- func (b *Body) CanSleep() bool
- func (b *Body) Circumference() float32
- func (b *Body) CollidableLayersBit() int
- func (b *Body) CustomGravity() Vec2
- func (b *Body) CustomGravityEnabled() bool
- func (b *Body) Enabled() bool
- func (b *Body) Friction() float32
- func (b *Body) IgnoreGravity() bool
- func (b *Body) Inertia() float32
- func (b *Body) IntegratedVelocitiesEnabled() bool
- func (b *Body) IsKinematic() bool
- func (b *Body) IsSleeping() bool
- func (b *Body) LayersBit() int
- func (b *Body) Mass() float32
- func (b *Body) MeshAt(i int) *Mesh
- func (b *Body) MeshCount() int
- func (b *Body) Meshes() []*Mesh
- func (b *Body) Mode() BodyMode
- func (b *Body) OverlapWithCollidableLayersBit(layersBit int) bool
- func (b *Body) OverlapWithLayersBit(layersBit int) bool
- func (b *Body) Position() Vec2
- func (b *Body) PostUpdate()
- func (b *Body) PreviousPosition() Vec2
- func (b *Body) PreviousRotation() float32
- func (b *Body) RemoveMeshAt(i int) *Body
- func (b *Body) Restitution() float32
- func (b *Body) Rotation() float32
- func (b *Body) RotationDegree() float32
- func (b *Body) SetAirFriction(v float32) *Body
- func (b *Body) SetAllowKinematicCollisions(v bool) *Body
- func (b *Body) SetBodySpecificTimeScale(value float32) *Body
- func (b *Body) SetBodySpecificTimeScaleEnabled(v bool) *Body
- func (b *Body) SetCanSleep(v bool) *Body
- func (b *Body) SetCollidableLayersBit(v int) *Body
- func (b *Body) SetCustomGravity(v Vec2) *Body
- func (b *Body) SetCustomGravityEnabled(v bool) *Body
- func (b *Body) SetEnabled(v bool) *Body
- func (b *Body) SetFriction(v float32) *Body
- func (b *Body) SetIntegratedVelocitiesEnabled(v bool) *Body
- func (b *Body) SetKinematic(v bool) *Body
- func (b *Body) SetLayersBit(v int) *Body
- func (b *Body) SetMass(v float32) *Body
- func (b *Body) SetMode(m BodyMode) *Body
- func (b *Body) SetPosition(v Vec2, withPreviousPosition ...bool) *Body
- func (b *Body) SetPreviousPosition(v Vec2) *Body
- func (b *Body) SetPreviousRotation(angleRadian float32) *Body
- func (b *Body) SetRestitution(v float32) *Body
- func (b *Body) SetRotation(angleRadian float32, withPreviousRotation ...bool) *Body
- func (b *Body) SetRotationDegree(degree float32, withPreviousRotation ...bool) *Body
- func (b *Body) SetStaticFriction(v float32) *Body
- func (b *Body) SetVelocityLimit(v float32) *Body
- func (b *Body) StaticFriction() float32
- func (b *Body) TotalInitialArea() float32
- func (b *Body) TotalPolygonsArea() float32
- func (b *Body) TotalPolygonsInitialArea() float32
- func (b *Body) Update()
- func (b *Body) UpdateAABB()
- func (b *Body) UpdateMeshTransforms()
- func (b *Body) VelocityLimit() float32
- func (b *Body) WakeUp() *Body
- func (b *Body) World() *World
- type BodyMode
- type BodyPair
- type BodyType
- type BroadPhase
- type CollisionBehavior
- type CollisionInfo
- type ConcurrencyConfig
- type Contact
- type ContactPool
- type Gizmo
- type GizmoType
- type Joint
- func (j *Joint) AnchorAGlobalPosition() Vec2
- func (j *Joint) AnchorAPosition() Vec2
- func (j *Joint) AnchorBGlobalPosition() Vec2
- func (j *Joint) AnchorBPosition() Vec2
- func (j *Joint) Balance() float32
- func (j *Joint) BodyA() *RigidBody
- func (j *Joint) BodyB() *RigidBody
- func (j *Joint) CollisionEnabled() bool
- func (j *Joint) Enabled() bool
- func (j *Joint) GrooveEnabled() bool
- func (j *Joint) Length() float32
- func (j *Joint) Rigidity() float32
- func (j *Joint) SetAnchorAPosition(worldPosition Vec2) *Joint
- func (j *Joint) SetAnchorBPosition(worldPosition Vec2) *Joint
- func (j *Joint) SetBalance(b float32) *Joint
- func (j *Joint) SetBodyA(b *RigidBody) *Joint
- func (j *Joint) SetBodyB(b *RigidBody) *Joint
- func (j *Joint) SetCollisionEnabled(b bool) *Joint
- func (j *Joint) SetEnabled(b bool) *Joint
- func (j *Joint) SetGrooveEnabled(b bool) *Joint
- func (j *Joint) SetLength(l float32) *Joint
- func (j *Joint) SetRigidity(r float32) *Joint
- func (j *Joint) Update()
- type Manifold
- type Mesh
- func NewCircleMesh(radius float32, centerPosition Vec2) *Mesh
- func NewMesh() *Mesh
- func NewMeshFromData(data MeshData, enableSprings, enablePolygons bool) *Mesh
- func NewPolygonMesh(radius float32, sideCount int, centerPosition Vec2, polarGrid int, ...) *Mesh
- func NewRectMesh(size, centerPosition, grid Vec2, opts ...MeshFactoryOption) *Mesh
- func (m *Mesh) AddAngleConstraint(ac *AngleConstraint) *Mesh
- func (m *Mesh) AddParticle(p *Particle) *Mesh
- func (m *Mesh) AddSpring(s *Spring) *Mesh
- func (m *Mesh) AngleConstraints() []*AngleConstraint
- func (m *Mesh) ApplyAngleConstraintsToPolygon()
- func (m *Mesh) Area() float32
- func (m *Mesh) Circumference() float32
- func (m *Mesh) CollisionBehavior() CollisionBehavior
- func (m *Mesh) GlobalPosition() Vec2
- func (m *Mesh) GlobalRotation() float32
- func (m *Mesh) InitialArea() float32
- func (m *Mesh) OwnerBody() *Body
- func (m *Mesh) ParticleAt(i int) *Particle
- func (m *Mesh) ParticleCount() int
- func (m *Mesh) ParticleIndex(p *Particle) int
- func (m *Mesh) Particles() []*Particle
- func (m *Mesh) Polygon() []*Particle
- func (m *Mesh) PolygonArea() float32
- func (m *Mesh) Position() Vec2
- func (m *Mesh) RemoveParticle(p *Particle) *Mesh
- func (m *Mesh) RemoveParticleAt(i int) *Mesh
- func (m *Mesh) Rotation() float32
- func (m *Mesh) SetGlobalPosition(v Vec2) *Mesh
- func (m *Mesh) SetPolygonForCollisionsDisabled(b bool) *Mesh
- func (m *Mesh) SetPosition(v Vec2) *Mesh
- func (m *Mesh) SetRotation(r float32) *Mesh
- func (m *Mesh) SpringCount() int
- func (m *Mesh) Springs() []*Spring
- func (m *Mesh) SubConvexPolygons() [][]*Particle
- func (m *Mesh) UpdateCollisionBehavior()
- func (m *Mesh) UpdateSubConvexPolygons(majorUpdate bool)
- type MeshData
- type MeshFactoryConfig
- type MeshFactoryOption
- type Particle
- func (p *Particle) AABB() AABB
- func (p *Particle) AddAccumulatedForce(v Vec2) *Particle
- func (p *Particle) AddForce(v Vec2) *Particle
- func (p *Particle) AddGlobalPosition(v Vec2) *Particle
- func (p *Particle) AddPosition(v Vec2) *Particle
- func (p *Particle) AddPreviousGlobalPosition(v Vec2) *Particle
- func (p *Particle) ApplyAccumulatedForces() *Particle
- func (p *Particle) ApplyForce(force Vec2) *Particle
- func (p *Particle) ClearAccumulatedForces() *Particle
- func (p *Particle) ClearOneTimeCollisions()
- func (p *Particle) Enabled() bool
- func (p *Particle) Force() Vec2
- func (p *Particle) GlobalPosition() Vec2
- func (p *Particle) IgnoreGravity() bool
- func (p *Particle) IsConnectedWithSpring(other *Particle) bool
- func (p *Particle) IsInternal() bool
- func (p *Particle) IsLazy() bool
- func (p *Particle) Mass() float32
- func (p *Particle) OwnerMesh() *Mesh
- func (p *Particle) Position() Vec2
- func (p *Particle) PreviousGlobalPosition() Vec2
- func (p *Particle) Radius() float32
- func (p *Particle) ResetOneTimeCollisions()
- func (p *Particle) SetEnabled(b bool) *Particle
- func (p *Particle) SetForce(v Vec2) *Particle
- func (p *Particle) SetGlobalPosition(v Vec2) *Particle
- func (p *Particle) SetIsInternal(b bool) *Particle
- func (p *Particle) SetIsLazy(b bool) *Particle
- func (p *Particle) SetMass(m float32) *Particle
- func (p *Particle) SetOwnerMesh(m *Mesh) *Particle
- func (p *Particle) SetPosition(v Vec2) *Particle
- func (p *Particle) SetPreviousGlobalPosition(v Vec2) *Particle
- func (p *Particle) SetRadius(r float32) *Particle
- func (p *Particle) UpdateAABB()
- type Raycast
- func (r *Raycast) CollidableLayersBit() int
- func (r *Raycast) Contacts() []RaycastContact
- func (r *Raycast) EnabledContainingBodies() bool
- func (r *Raycast) Position() Vec2
- func (r *Raycast) RayVector() Vec2
- func (r *Raycast) Rotation() float32
- func (r *Raycast) SetCollidableLayersBit(b int) *Raycast
- func (r *Raycast) SetEnabledContainingBodies(b bool) *Raycast
- func (r *Raycast) SetPosition(v Vec2) *Raycast
- func (r *Raycast) SetRayVector(v Vec2) *Raycast
- func (r *Raycast) SetRotation(rad float32) *Raycast
- func (r *Raycast) UpdateContacts()
- func (r *Raycast) World() *World
- type RaycastContact
- type RigidBody
- func (rb *RigidBody) AddAngularForce(v float32) *RigidBody
- func (rb *RigidBody) AddForce(v Vec2) *RigidBody
- func (rb *RigidBody) AngularForce() float32
- func (rb *RigidBody) ApplyForce(force Vec2) *RigidBody
- func (rb *RigidBody) ApplyForceAt(force, r Vec2, updateMeshTransforms bool) *RigidBody
- func (rb *RigidBody) ApplyImpulse(impulse, r Vec2) *RigidBody
- func (rb *RigidBody) AsBody() *Body
- func (rb *RigidBody) FixedRotationEnabled() bool
- func (rb *RigidBody) Force() Vec2
- func (rb *RigidBody) KinematicCollisionsEnabled() bool
- func (rb *RigidBody) KinematicEnabled() bool
- func (rb *RigidBody) PostUpdate()
- func (rb *RigidBody) SetAngularForce(v float32) *RigidBody
- func (rb *RigidBody) SetFixedRotationEnabled(v bool) *RigidBody
- func (rb *RigidBody) SetForce(v Vec2) *RigidBody
- func (rb *RigidBody) SetKinematicCollisionsEnabled(v bool) *RigidBody
- func (rb *RigidBody) SetKinematicEnabled(v bool) *RigidBody
- func (rb *RigidBody) SetPositionAndCollide(v Vec2, withPreviousPosition bool) *RigidBody
- func (rb *RigidBody) Update()
- type SAPBroadPhase
- type Side
- type SoftBody
- func (sb *SoftBody) ApplyForce(force Vec2) *SoftBody
- func (sb *SoftBody) ApplyShapeMatching()
- func (sb *SoftBody) AreaPreservingEnabled() bool
- func (sb *SoftBody) AreaPreservingRate() float32
- func (sb *SoftBody) AreaPreservingRigidity() float32
- func (sb *SoftBody) AsBody() *Body
- func (sb *SoftBody) Mass() float32
- func (sb *SoftBody) ParticleSpecificMass() float32
- func (sb *SoftBody) ParticleSpecificMassEnabled() bool
- func (sb *SoftBody) PassivationOfInternalSpringsEnabled() bool
- func (sb *SoftBody) PostUpdate()
- func (sb *SoftBody) PreserveAreas()
- func (sb *SoftBody) Rigidity() float32
- func (sb *SoftBody) SelfCollisionsEnabled() bool
- func (sb *SoftBody) SelfCollisionsSpecifiedRadius() float32
- func (sb *SoftBody) SetAreaPreservingEnabled(b bool) *SoftBody
- func (sb *SoftBody) SetAreaPreservingRate(r float32) *SoftBody
- func (sb *SoftBody) SetAreaPreservingRigidity(r float32) *SoftBody
- func (sb *SoftBody) SetParticleSpecificMass(m float32) *SoftBody
- func (sb *SoftBody) SetParticleSpecificMassEnabled(b bool) *SoftBody
- func (sb *SoftBody) SetPassivationOfInternalSpringsEnabled(b bool) *SoftBody
- func (sb *SoftBody) SetRigidity(r float32) *SoftBody
- func (sb *SoftBody) SetSelfCollisionsEnabled(b bool) *SoftBody
- func (sb *SoftBody) SetSelfCollisionsSpecifiedRadius(r float32) *SoftBody
- func (sb *SoftBody) SetShapeMatchingEnabled(b bool, withoutInternals bool) *SoftBody
- func (sb *SoftBody) SetShapeMatchingFixedPosition(v Vec2) *SoftBody
- func (sb *SoftBody) SetShapeMatchingFixedRotation(r float32) *SoftBody
- func (sb *SoftBody) SetShapeMatchingFixedTransformEnabled(b bool) *SoftBody
- func (sb *SoftBody) SetShapeMatchingRate(r float32) *SoftBody
- func (sb *SoftBody) SetTargetPreservationArea(a float32) *SoftBody
- func (sb *SoftBody) ShapeMatchingEnabled() bool
- func (sb *SoftBody) ShapeMatchingFixedPosition() Vec2
- func (sb *SoftBody) ShapeMatchingFixedRotation() float32
- func (sb *SoftBody) ShapeMatchingFixedTransformEnabled() bool
- func (sb *SoftBody) ShapeMatchingRate() float32
- func (sb *SoftBody) TargetPreservationArea() float32
- func (sb *SoftBody) Update()
- type Spring
- func (s *Spring) DistanceLimitEnabled() bool
- func (s *Spring) Enabled() bool
- func (s *Spring) IsInternal() bool
- func (s *Spring) Length() float32
- func (s *Spring) MaximumDistanceFactor() float32
- func (s *Spring) MinimumDistanceFactor() float32
- func (s *Spring) ParticleA() *Particle
- func (s *Spring) ParticleB() *Particle
- func (s *Spring) Rigidity() float32
- func (s *Spring) SetDistanceLimitEnabled(b bool) *Spring
- func (s *Spring) SetEnabled(b bool) *Spring
- func (s *Spring) SetIsInternal(b bool) *Spring
- func (s *Spring) SetLength(l float32) *Spring
- func (s *Spring) SetMaximumDistanceFactor(v float32) *Spring
- func (s *Spring) SetMinimumDistanceFactor(v float32) *Spring
- func (s *Spring) SetParticleA(p *Particle) *Spring
- func (s *Spring) SetParticleB(p *Particle) *Spring
- func (s *Spring) SetRigidity(r float32) *Spring
- func (s *Spring) Update(rigidity float32, internalsException bool, isWorldSpring bool)
- type Vec2
- func AngleToUnitVector(radianAngle float32) Vec2
- func ComputeFriction(bodyA, bodyB *Body, normal Vec2, penetration float32, relativeVelocity Vec2) Vec2
- func GetAveragePositionAndRotation(particles []*Particle) (Vec2, float32)
- func GetBisectorUnitVector(pointA, pointB, pointC Vec2, checkPointsAreCCW bool) Vec2
- func GetMatchingParticlePositions(particles []*Particle, targetPosition Vec2, targetRotation float32) []Vec2
- func LineIntersectionLine(d1A, d1B, d2A, d2B Vec2) Vec2
- func Vec2Down() Vec2
- func Vec2Left() Vec2
- func Vec2NaN() Vec2
- func Vec2Right() Vec2
- func Vec2Up() Vec2
- func Vec2Zero() Vec2
- func (v Vec2) Add(other Vec2) Vec2
- func (v *Vec2) AddAssign(other Vec2) *Vec2
- func (v Vec2) Div(s float32) Vec2
- func (v Vec2) DivVec(other Vec2) Vec2
- func (v Vec2) Dot(other Vec2) float32
- func (v Vec2) Equal(other Vec2) bool
- func (v Vec2) IsNaN() bool
- func (v Vec2) Length() float32
- func (v Vec2) LengthSquared() float32
- func (v Vec2) Mul(s float32) Vec2
- func (v *Vec2) MulAssign(s float32) *Vec2
- func (v Vec2) Neg() Vec2
- func (v Vec2) Normalized() Vec2
- func (v Vec2) NotEqual(other Vec2) bool
- func (v Vec2) Perpendicular() Vec2
- func (v Vec2) Rotated(radianAngle float32) Vec2
- func (v Vec2) Sub(other Vec2) Vec2
- func (v *Vec2) SubAssign(other Vec2) *Vec2
- type World
- func (w *World) AddAreaBody(ab *AreaBody) *World
- func (w *World) AddBody(b *Body) *World
- func (w *World) AddCollisionException(a, b *Body) *World
- func (w *World) AddGizmo(g *Gizmo)
- func (w *World) AddJoint(j *Joint) *World
- func (w *World) AddRaycast(r *Raycast) *World
- func (w *World) AddRigidBody(rb *RigidBody) *World
- func (w *World) AddSoftBody(sb *SoftBody) *World
- func (w *World) AddSpring(s *Spring) *World
- func (w *World) Bodies() []*Body
- func (w *World) BodyAt(i int) *Body
- func (w *World) BodyCount() int
- func (w *World) BodyIndex(b *Body) int
- func (w *World) Broadphase() BroadPhase
- func (w *World) BroadphaseEnabled() bool
- func (w *World) CheckCollisionException(a, b *Body) bool
- func (w *World) ClearGizmos()
- func (w *World) CollideWithWorld(body *Body) bool
- func (w *World) ContactPool() *ContactPool
- func (w *World) DebugGizmos() bool
- func (w *World) Enabled() bool
- func (w *World) Gizmos() []*Gizmo
- func (w *World) Gravity() Vec2
- func (w *World) IterationCount() int
- func (w *World) JointCount() int
- func (w *World) Joints() []*Joint
- func (w *World) RaycastCount() int
- func (w *World) Raycasts() []*Raycast
- func (w *World) RemoveBody(b *Body) *World
- func (w *World) RemoveBodyAt(i int) *World
- func (w *World) RemoveCollisionException(a, b *Body) *World
- func (w *World) RemoveJoint(j *Joint) *World
- func (w *World) RemoveMatchingCollisionExceptions(body *Body) *World
- func (w *World) RemoveRaycast(r *Raycast) *World
- func (w *World) RemoveSpring(s *Spring) *World
- func (w *World) SetBroadphase(bp BroadPhase) *World
- func (w *World) SetBroadphaseEnabled(b bool) *World
- func (w *World) SetDebugGizmos(b bool) *World
- func (w *World) SetEnabled(b bool) *World
- func (w *World) SetGravity(g Vec2) *World
- func (w *World) SetIterationCount(n int) *World
- func (w *World) SetSleepingEnabled(b bool) *World
- func (w *World) SetSoftBodyCollisionHysteresis(v float32) *World
- func (w *World) SetTimeScale(ts float32) *World
- func (w *World) SleepingEnabled() bool
- func (w *World) SoftBodyCollisionHysteresis() float32
- func (w *World) SpringCount() int
- func (w *World) Springs() []*Spring
- func (w *World) Step() int
- func (w *World) TestCollisionWithWorld(body *Body) []Manifold
- func (w *World) TimeScale() float32
- func (w *World) Update()
- func (w *World) UpdateConstraints()
- type WorldOption
- func WithBroadphase(b bool) WorldOption
- func WithBroadphaseImpl(bp BroadPhase) WorldOption
- func WithConcurrency(config ConcurrencyConfig) WorldOption
- func WithDebugGizmos(b bool) WorldOption
- func WithGravity(g Vec2) WorldOption
- func WithIterations(n int) WorldOption
- func WithSleeping(b bool) WorldOption
Constants ¶
const MaxWorldSize float32 = 99999.0
Variables ¶
This section is empty.
Functions ¶
func AngleBetweenTwoVectors ¶
AngleBetweenTwoVectors returns the angle from referenceVector to vector, in radians. Matches QVector::AngleBetweenTwoVectors in qvector.cpp.
The C++ implementation computes:
refPerp = referenceVector.Perpendicular() dot = vector · referenceVector perpDot = vector · refPerp // = vector.X*refY - vector.Y*refX totalLen = vector.Length() + referenceVector.Length() cosA = dot / totalLen sinA = perpDot / totalLen aSin = asin(clamp(sinA, -1, 1))
AngleBetweenTwoVectors computes the signed angle from referenceVector to vector. Matches QVector::AngleBetweenTwoVectors in qvector.cpp:37-69 exactly.
C++ algorithm:
totalLength = vector.Length() + referenceVector.Length() refPerp = referenceVector.Perpendicular() dot = vector · referenceVector perpDot = vector · refPerp cosA = totalLength != 0 ? dot/totalLength : 0 sinA = totalLength != 0 ? perpDot/totalLength : 0 aSin = clamp(asin(sinA), -1, 1) return -atan2(aSin, cosA)
NOTE: The C++ formula divides by the SUM of lengths (not product), then applies asin. This is non-standard but is the reference behavior — it must be reproduced verbatim because AngleConstraint, polygon corner-angle tracking, and platformer slope detection all accumulate this value.
func AngleOfParticlesWithLocalPositions ¶
AngleOfParticlesWithLocalPositions computes the angle at pB formed by rays pB→pA and pB→pC, using LOCAL positions. Returns a value in [0, 2π).
func ApplyForceToParticleSegment ¶
ApplyForceToParticleSegment distributes `force` across two particles forming a segment, weighted by where `fromPosition` projects onto the segment. Matches QParticle::ApplyForceToParticleSegment in qparticle.cpp:220-241.
Used by Manifold.Solve to apply collision response along a reference edge (2 particles) at the contact point.
func CanCollide ¶
CanCollide reports whether two bodies can collide based on their state and layer bits.
func RegisterAreaBody ¶
RegisterAreaBody associates a *Body with its *AreaBody container.
func RegisterPostUpdater ¶
func RegisterPostUpdater(b *Body, fn func())
RegisterPostUpdater associates a *Body with a function that calls its PostUpdate. Called by ext/platformer when a PlatformerBody is added.
func RegisterRigidBody ¶
RegisterRigidBody associates a *Body with its *RigidBody container. Called by World.AddBody when the body is a RigidBody.
func RegisterSoftBody ¶
RegisterSoftBody associates a *Body with its *SoftBody container.
func SetConvexPartitioner ¶
SetConvexPartitioner registers the function used for concave polygon decomposition. Pass nil to disable (concave polygons will use the full polygon without decomposition, which may cause collision artifacts).
func SortParticlesHorizontal ¶
SortParticlesHorizontal sorts particles by AABB min.X (ascending), breaking ties by AABB max.Y (descending). Matches the C++ comparator QParticle::SortParticlesHorizontal in qparticle.h:273-278.
Used by CircleAndCircle for sweep-and-prune pair generation.
Types ¶
type AABB ¶
type AABB struct {
Min, Max Vec2
}
AABB is an axis-aligned bounding box, the cheap pre-collision filter.
Convention: Min is the top-left corner, Max is the bottom-right corner (Y axis points down, matching the rest of the engine).
func GetAABBFromParticles ¶
GetAABBFromParticles returns the bounding box of a set of particles, expanded by each particle's radius.
The particle slice is required because AABB is a value type and cannot reference particles directly. This is the main place where the Go port differs structurally from C++ (which used a vector<QParticle*>&).
func (AABB) CenterPosition ¶
CenterPosition returns the midpoint of the AABB.
func (AABB) FattenedWithRate ¶
FattenedWithRate returns a new AABB expanded proportionally to its size. rate=0.1 expands by 5% on each side (10% total).
func (AABB) IsCollidingWith ¶
IsCollidingWith reports whether a and other overlap.
type AngleConstraint ¶
type AngleConstraint struct {
// contains filtered or unexported fields
}
AngleConstraint is a 3-particle angle constraint.
Constrains the angle at pB (between rays pB→pA and pB→pC) to stay within [minAngle, maxAngle]. When the angle exceeds the bounds, forces are applied to pA and pC to rotate them back toward the target.
Wrap-around handling: angles are tracked via prevAngle and updated by the angle difference (computed via AngleBetweenTwoVectors on unit vectors). This allows the constraint to track angles across the 0/2π boundary.
func NewAngleConstraint ¶
func NewAngleConstraint(pA, pB, pC *Particle, angleRange float32) *AngleConstraint
NewAngleConstraint creates an angle constraint between three particles, auto-calculating min/max angles from the current local positions.
func NewAngleConstraintWithBounds ¶
func NewAngleConstraintWithBounds(pA, pB, pC *Particle, minAngle, maxAngle float32) *AngleConstraint
NewAngleConstraintWithBounds creates an angle constraint with explicit min and max angles.
func (*AngleConstraint) CurrentAngle ¶
func (ac *AngleConstraint) CurrentAngle() float32
func (*AngleConstraint) Enabled ¶
func (ac *AngleConstraint) Enabled() bool
func (*AngleConstraint) MaxAngle ¶
func (ac *AngleConstraint) MaxAngle() float32
func (*AngleConstraint) MinAngle ¶
func (ac *AngleConstraint) MinAngle() float32
func (*AngleConstraint) ParticleA ¶
func (ac *AngleConstraint) ParticleA() *Particle
func (*AngleConstraint) ParticleB ¶
func (ac *AngleConstraint) ParticleB() *Particle
func (*AngleConstraint) ParticleC ¶
func (ac *AngleConstraint) ParticleC() *Particle
func (*AngleConstraint) Rigidity ¶
func (ac *AngleConstraint) Rigidity() float32
func (*AngleConstraint) SetEnabled ¶
func (ac *AngleConstraint) SetEnabled(b bool) *AngleConstraint
func (*AngleConstraint) SetMaxAngle ¶
func (ac *AngleConstraint) SetMaxAngle(v float32) *AngleConstraint
func (*AngleConstraint) SetMinAngle ¶
func (ac *AngleConstraint) SetMinAngle(v float32) *AngleConstraint
func (*AngleConstraint) SetParticleA ¶
func (ac *AngleConstraint) SetParticleA(p *Particle) *AngleConstraint
func (*AngleConstraint) SetParticleB ¶
func (ac *AngleConstraint) SetParticleB(p *Particle) *AngleConstraint
func (*AngleConstraint) SetParticleC ¶
func (ac *AngleConstraint) SetParticleC(p *Particle) *AngleConstraint
func (*AngleConstraint) SetRigidity ¶
func (ac *AngleConstraint) SetRigidity(r float32) *AngleConstraint
func (*AngleConstraint) Update ¶
func (ac *AngleConstraint) Update(specifiedRigidity float32, addToAccumulatedForces bool)
Update applies the angle constraint.
Parameters:
- specifiedRigidity: override rigidity (-1.0 = use the constraint's own rigidity)
- addToAccumulatedForces: if true, route forces through the accumulated-force pipeline
type AreaBody ¶
type AreaBody struct {
Body
// Event listeners (function fields, replace std::function)
OnCollisionEnter func(*AreaBody, *Body)
OnCollisionExit func(*AreaBody, *Body)
// ComputeLinearForceListener returns a per-body linear force.
// If set, overrides linearForceToApply.
ComputeLinearForceListener func(*Body) Vec2
// contains filtered or unexported fields
}
AreaBody is a sensor/trigger body.
Area bodies do NOT respond to collisions or receive forces — they only REPORT collisions. They maintain a set of currently-collided bodies and dispatch OnCollisionEnter / OnCollisionExit events when bodies enter or leave the area.
Supported features:
- OnCollisionEnter/OnCollisionExit events (virtual + function field)
- gravityFree mode (disables gravity on contained bodies)
- linearForceToApply (continuous force applied to contained bodies)
- ComputeLinearForce per-body callback (custom force per contained body)
func NewAreaBody ¶
func NewAreaBody() *AreaBody
NewAreaBody constructs an AreaBody with default values.
func (*AreaBody) CheckBodies ¶
func (ab *AreaBody) CheckBodies()
CheckBodies re-tests all currently-collided bodies and dispatches enter/exit events. Called once per physics step by World.Update.
func (*AreaBody) ComputeLinearForce ¶
ComputeLinearForce returns the force to apply to a specific body. If ComputeLinearForceListener is set, uses it; otherwise uses linearForceToApply.
func (*AreaBody) GravityFreeEnabled ¶
GravityFreeEnabled reports whether the gravity-free zone is active.
func (*AreaBody) LinearForceToApply ¶
LinearForceToApply returns the continuous force applied to contained bodies.
func (*AreaBody) SetGravityFreeEnabled ¶
SetGravityFreeEnabled enables/disables the gravity-free zone. When enabled, contained bodies are exempt from gravity.
func (*AreaBody) SetLinearForceToApply ¶
SetLinearForceToApply sets a continuous force applied to contained bodies.
type Body ¶
type Body struct {
// Event listeners (function fields, replace std::function)
OnPreStep func(*Body)
OnStep func(*Body)
OnCollision func(*Body, CollisionInfo) bool
// contains filtered or unexported fields
}
Body is the base type for all physics bodies.
Body is abstract in the C++ engine (has virtual methods). In Go, we embed it as a struct field in RigidBody, SoftBody, and AreaBody. The BodyType field drives dispatch in World.Update via a switch (see D006 in DECISIONS.md).
Key concepts:
- Verlet integration: velocity is implicit (position - prevPosition)
- Meshes carry particles, which carry their own positions
- The AABB is recomputed from particle positions
- Sleeping bodies skip integration but still collide
func (*Body) AddMesh ¶
AddMesh attaches a mesh to the body. Matches QBody::AddMesh in qbody.cpp:154-162.
func (*Body) AddPosition ¶
AddPosition adds a vector to the body's position.
func (*Body) AddPreviousPosition ¶
AddPreviousPosition adds a vector to the body's previous position.
func (*Body) AddPreviousRotation ¶
AddPreviousRotation adds to the body's previous rotation.
func (*Body) AddRotation ¶
AddRotation adds to the body's rotation in radians.
func (*Body) AirFriction ¶
AirFriction returns the body's air friction (drag) coefficient.
func (*Body) AllowKinematicCollisions ¶
AllowKinematicCollisions reports whether this kinematic body reacts to collisions with other kinematic bodies.
func (*Body) ApplyForce ¶
ApplyForce applies an immediate force to the body. The base implementation is a no-op; RigidBody and SoftBody override.
func (*Body) CanGiveCollisionResponseTo ¶
CanGiveCollisionResponseTo reports whether this body should receive collision responses from otherBody. Matches QBody::CanGiveCollisionResponseTo.
func (*Body) Circumference ¶
Circumference returns the total perimeter of all meshes' polygons. Caches the computed perimeter for the warm path.
func (*Body) CollidableLayersBit ¶
CollidableLayersBit returns the bitmask of layers this body can collide with.
func (*Body) CustomGravity ¶
CustomGravity returns the per-body gravity vector (if enabled).
func (*Body) CustomGravityEnabled ¶
CustomGravityEnabled reports whether a per-body gravity override is active.
func (*Body) IgnoreGravity ¶
IgnoreGravity reports whether the body is exempt from gravity. Set by QAreaBody when gravityFree is enabled.
func (*Body) Inertia ¶
Inertia returns the body's rotational inertia. Computed lazily. The clamped value is cached in b.inertiaCache so callers after the first compute see the same floor that C++ returns from its private `float inertia` field. Without this cache, small rigid bodies (e.g. 10×10 with mass 1, area*2*mass ≈ 200 < 500) would compute ~2.5x larger torque on every ApplyForce/ApplyImpulse call after the first.
func (*Body) IntegratedVelocitiesEnabled ¶
IntegratedVelocitiesEnabled reports whether Verlet integration is active.
func (*Body) IsKinematic ¶
IsKinematic reports whether the body is kinematic (user-controlled, not affected by forces).
func (*Body) IsSleeping ¶
IsSleeping reports whether the body is currently sleeping.
func (*Body) OverlapWithCollidableLayersBit ¶
OverlapWithCollidableLayersBit reports whether this body can collide with bodies on the given layers bitmask.
func (*Body) OverlapWithLayersBit ¶
OverlapWithLayersBit reports whether this body is on any of the given layers.
func (*Body) PostUpdate ¶
func (b *Body) PostUpdate()
PostUpdate is called after all bodies have completed their Update step. Base implementation is a no-op; RigidBody and PlatformerBody override.
func (*Body) PreviousPosition ¶
PreviousPosition returns the body's previous position (Verlet velocity source).
func (*Body) PreviousRotation ¶
PreviousRotation returns the body's previous rotation.
func (*Body) RemoveMeshAt ¶
RemoveMeshAt removes the mesh at the given index.
func (*Body) Restitution ¶
Restitution returns the body's restitution (bounciness).
func (*Body) RotationDegree ¶
RotationDegree returns the body's rotation in degrees.
func (*Body) SetAirFriction ¶
SetAirFriction sets the air friction (drag) coefficient.
func (*Body) SetAllowKinematicCollisions ¶
SetAllowKinematicCollisions controls kinematic-kinematic collision response.
func (*Body) SetBodySpecificTimeScale ¶
SetBodySpecificTimeScale sets a per-body time scale. When the value changes AND body-specific time scale is enabled, the body's implicit velocity (position - prevPosition, and per-particle for soft bodies) is rescaled to preserve continuity across the time-scale change. Matches qbody.h:579-615.
velocityTimeScaleFactor logic (C++ qbody.h:583-590):
- If old scale == 0: factor = 0 (no rescale; old was frozen)
- If new < old: factor = (1/old) * new (slow down further)
- If new >= old: factor = 1.0 (no slow-down needed)
For RIGID bodies: rescale (position - prevPosition) and (rotation - prevRotation). For SOFT bodies: rescale each particle's (globalPosition - prevGlobalPosition). For AREA bodies: no rescale (they don't integrate).
func (*Body) SetBodySpecificTimeScaleEnabled ¶
SetBodySpecificTimeScaleEnabled toggles whether the body uses its own time scale instead of the world's. Matches qbody.h:570-573.
func (*Body) SetCanSleep ¶
SetCanSleep controls whether the body is allowed to sleep.
func (*Body) SetCollidableLayersBit ¶
SetCollidableLayersBit sets the bitmask of layers this body can collide with.
func (*Body) SetCustomGravity ¶
SetCustomGravity sets the per-body gravity vector.
func (*Body) SetCustomGravityEnabled ¶
SetCustomGravityEnabled controls whether a per-body gravity override is active.
func (*Body) SetEnabled ¶
SetEnabled enables or disables the body.
func (*Body) SetFriction ¶
SetFriction sets the dynamic friction coefficient.
func (*Body) SetIntegratedVelocitiesEnabled ¶
SetIntegratedVelocitiesEnabled controls whether Verlet integration runs.
func (*Body) SetKinematic ¶
SetKinematic controls whether the body is kinematic. (Defined on RigidBody in C++; we expose it on Body for convenience.)
func (*Body) SetLayersBit ¶
SetLayersBit sets the bitmask of layers this body is on.
func (*Body) SetPosition ¶
SetPosition sets the body's world-space position. If withPreviousPosition is true (the default), prevPosition is also set, zeroing the implicit velocity.
func (*Body) SetPreviousPosition ¶
SetPreviousPosition sets the body's previous position (Verlet velocity source).
func (*Body) SetPreviousRotation ¶
SetPreviousRotation sets the body's previous rotation.
func (*Body) SetRestitution ¶
SetRestitution sets the body's restitution (bounciness).
func (*Body) SetRotation ¶
SetRotation sets the body's rotation in radians.
func (*Body) SetRotationDegree ¶
SetRotationDegree sets the body's rotation in degrees.
func (*Body) SetStaticFriction ¶
SetStaticFriction sets the static friction coefficient.
func (*Body) SetVelocityLimit ¶
SetVelocityLimit sets the maximum velocity (0 = unlimited).
func (*Body) StaticFriction ¶
StaticFriction returns the body's static friction coefficient.
func (*Body) TotalInitialArea ¶
TotalInitialArea returns the sum of all meshes' initial areas.
func (*Body) TotalPolygonsArea ¶
TotalPolygonsArea returns the sum of all meshes' current polygon areas.
func (*Body) TotalPolygonsInitialArea ¶
TotalPolygonsInitialArea returns the sum of all meshes' initial polygon areas.
func (*Body) Update ¶
func (b *Body) Update()
Update is the per-step integration hook. The base implementation just resets lazy collisions; RigidBody and SoftBody override.
func (*Body) UpdateAABB ¶
func (b *Body) UpdateAABB()
UpdateAABB recomputes the body's AABB from all particle positions.
func (*Body) UpdateMeshTransforms ¶
func (b *Body) UpdateMeshTransforms()
UpdateMeshTransforms applies the body's position and rotation to all mesh particles. Matches QBody::UpdateMeshTransforms in qbody.cpp:227-251.
Critical: the prevGlobalPosition update differs by body type:
- RIGID: prev = current globalPosition (preserves velocity direction)
- SOFT/AREA: prev = new computed position (zeroes velocity for that step)
This is the Verlet velocity mechanism for particles.
func (*Body) VelocityLimit ¶
VelocityLimit returns the maximum velocity; 0 means unlimited.
type BodyMode ¶
type BodyMode int
BodyMode determines whether a body reacts to forces and collisions.
type BodyPair ¶
type BodyPair struct {
A, B *Body
}
BodyPair represents an unordered pair of bodies. Used by broadphase to report candidate collision pairs.
func (BodyPair) Canonicalize ¶
Canonicalize returns the pair in canonical order (by index in the world's bodies slice, which is stable). Used for deduplication in broadphase.
type BroadPhase ¶
type BroadPhase interface {
// Insert adds a body to the broadphase index.
Insert(b *Body)
// Remove removes a body from the broadphase index.
Remove(b *Body)
// Clear removes all bodies from the index.
Clear()
// Pairs returns the current set of candidate collision pairs.
// Called once per solver iteration. The returned slice is owned by
// the caller (the broadphase may reuse its internal buffer on the
// next call).
Pairs() []BodyPair
}
BroadPhase is the interface for broadphase collision pair generation. Implementations reduce O(n²) body pair checks to near-linear by partitioning bodies spatially.
The default implementation is Sweep-and-Prune (sapPairs in broadphase_internal.go). QSpatialHashing (ext/spatialhash) is an alternative. Users can provide custom implementations via World.SetBroadphase.
type CollisionBehavior ¶
type CollisionBehavior int
CollisionBehavior enumerates how a mesh participates in collision detection.
const ( // CollisionCircles treats particles as circles. Used when no polygon // is defined (e.g., a single-particle circle mesh). CollisionCircles CollisionBehavior = iota // CollisionPolygons treats the polygon as a solid convex/concave shape. // Used by rigid bodies. CollisionPolygons // CollisionPolyline treats the polygon as a deformable rope. Used by // soft bodies, where the polygon may self-intersect. CollisionPolyline )
type CollisionInfo ¶
type CollisionInfo struct {
// Position is the world-space contact position.
Position Vec2
// Body is the other body involved in the collision.
Body *Body
// Normal is the collision normal.
Normal Vec2
// Penetration is the overlap depth.
Penetration float32
}
CollisionInfo is passed to OnCollision event listeners.
type ConcurrencyConfig ¶
type ConcurrencyConfig struct {
// Enabled controls whether parallel narrowphase is active.
// Default: false (single-threaded, matching C++ original engine).
Enabled bool
// NumWorkers is the number of goroutines to use for parallel narrowphase.
// If 0, defaults to runtime.NumCPU().
NumWorkers int
}
ConcurrencyConfig controls parallel narrowphase execution.
type Contact ¶
type Contact struct {
// Position is the world-space contact point.
Position Vec2
// Particle is the incident particle involved in the collision.
// May be nil for ray-vs-polygon contacts that don't map to a particle.
Particle *Particle
// Normal is the contact normal, pointing from bodyB toward bodyA.
Normal Vec2
// Penetration is how far the two shapes overlap along Normal.
Penetration float32
// ReferenceParticles holds the 1-2 particles forming the reference
// edge. Used by Manifold.Solve to distribute response forces along
// the contact segment (barycentric weighting).
ReferenceParticles []*Particle
// Solved tracks whether this contact has already been processed by
// Manifold.Solve, to avoid double-application within an iteration.
Solved bool
}
Contact is the data structure produced by collision detection and consumed by collision resolution (Manifold). Matches QCollision::Contact in qcollision.h:53-91.
One Contact represents a single point where two bodies touch: the position in world space, the incident particle, the contact normal (pointing from bodyB toward bodyA), the penetration depth, and the reference-face particles used by the friction solver.
Contacts are pooled via ContactPool to avoid GC pressure — they are allocated and freed many times per physics step.
func GetCollisions ¶
func GetCollisions(bodyA, bodyB *Body, pool *ContactPool, applyHotSolvers bool) []*Contact
GetCollisions runs narrowphase collision detection between two bodies and returns a list of contacts.
Dispatches by the collision behavior of each body's meshes:
- Polygons × Polygons → PolygonAndPolygon
- Circles × Polygons → CircleAndPolygon
- Circles × Circles → CircleAndCircle
- Polyline × Polygons → CircleAndPolygon (hot-solved if applyHotSolvers)
- PolylineAndPolygon
When applyHotSolvers is true AND the body pair is Polyline×Polygons, the CircleAndPolygon contacts are immediately solved via a temp Manifold (hot-solving) BEFORE PolylineAndPolygon runs. This matches qworld.cpp:1017-1025. Hot-solving mutates body state during narrowphase, so it MUST NOT be used when parallel narrowphase is enabled — the caller is responsible for passing applyHotSolvers=false in that mode.
func (*Contact) Configure ¶
func (c *Contact) Configure( particle *Particle, position Vec2, normal Vec2, penetration float32, referenceParticles []*Particle, )
Configure resets an existing Contact with new values. Used by the ContactPool to recycle Contact objects without allocation. Matches QCollision::Contact::Configure in qcollision.h:80-87.
type ContactPool ¶
type ContactPool struct {
// contains filtered or unexported fields
}
ContactPool recycles *Contact objects to avoid GC pressure during collision solving. Contacts are created and discarded many times per physics step (once per candidate pair, per iteration), so pooling is essential for performance.
In the C++ engine (qcollision.h:93) this is a global static QObjectPool<Contact> shared across all QWorld instances — a porting hazard for concurrency (analysis doc §8.2 R4). In this Go port each World owns its own ContactPool, which:
- Enables future per-World concurrency (Phase 5)
- Avoids global state contamination between independent worlds
- Has minimal overhead — sync.Pool is optimized for this access pattern
Reference: analysis doc §7.5, §8.2 R4
func NewContactPool ¶
func NewContactPool() *ContactPool
NewContactPool creates an empty pool. The pool lazily allocates Contact objects on first Get and recycles them on Put.
func (*ContactPool) Get ¶
func (p *ContactPool) Get() *Contact
Get returns a *Contact from the pool, allocating if necessary. The returned Contact has all fields zeroed (matches the C++ contactPool FreeAll + Create pattern at qworld.cpp:123).
func (*ContactPool) Put ¶
func (p *ContactPool) Put(c *Contact)
Put returns a *Contact to the pool for reuse. The Contact's fields are cleared to avoid holding stale references (which would prevent GC of the referenced Particle/Body objects).
type Gizmo ¶
type Gizmo struct {
Type GizmoType
// Circle fields
Position Vec2
Radius float32
// Line fields
PointA Vec2
PointB Vec2
IsArrow bool
// Rect field
Rect AABB
}
Gizmo is a debug visualization primitive. Matches QGizmo in qgizmos.h.
Gizmos are recorded by the engine during collision solving when World.DebugGizmos() is true. Renderers (e.g., the Ebitengine example renderer) consume them for visual debugging.
func NewGizmoCircle ¶
NewGizmoCircle creates a circle gizmo.
func NewGizmoLine ¶
NewGizmoLine creates a line gizmo.
type Joint ¶
type Joint struct {
// contains filtered or unexported fields
}
Joint is a distance constraint between two rigid bodies. Matches QJoint in qjoint.h, qjoint.cpp.
Either bodyA or bodyB may be nil, in which case the corresponding anchor is treated as a fixed point in world space.
The joint enforces a target distance (`length`) between the two anchor points. When the current distance differs from the target, forces are applied to both bodies to close the gap. The `balance` parameter (0.0=A-side, 1.0=B-side, default 0.5) controls the force distribution.
Groove mode (`grooveEnabled=true`) makes the joint pull-only: it only enforces the constraint when the current distance exceeds the target (useful for "rope" or "tether" constraints).
func NewJoint ¶
func NewJoint(bodyA *RigidBody, anchorWorldPositionA, anchorWorldPositionB Vec2, bodyB *RigidBody) *Joint
NewJoint creates a joint between two bodies. If bodyB is nil, anchorB is treated as a fixed point in world space. Same for bodyA.
func NewPinJoint ¶
NewPinJoint creates a joint with zero length (pin joint).
func (*Joint) AnchorAGlobalPosition ¶
func (*Joint) AnchorAPosition ¶
func (*Joint) AnchorBGlobalPosition ¶
func (*Joint) AnchorBPosition ¶
func (*Joint) CollisionEnabled ¶
func (*Joint) GrooveEnabled ¶
func (*Joint) SetAnchorAPosition ¶
SetAnchorAPosition sets anchorA in world coordinates; internally stored as body-local if bodyA is set. Matches qjoint.h:154-161.
func (*Joint) SetAnchorBPosition ¶
SetAnchorBPosition sets anchorB in world coordinates.
func (*Joint) SetBalance ¶
func (*Joint) SetCollisionEnabled ¶
SetCollisionEnabled controls whether the jointed bodies collide. When false (default), a collision exception is registered so the bodies pass through each other. Matches QJoint::SetCollisionEnabled in qjoint.cpp:72-82.
func (*Joint) SetEnabled ¶
func (*Joint) SetGrooveEnabled ¶
func (*Joint) SetRigidity ¶
func (*Joint) Update ¶
func (j *Joint) Update()
Update solves the joint constraint.
For each step:
- Transform anchors from body-local to world-space
- Compute the current distance between anchors
- Compute the distance delta (target - current)
- Apply forces to both bodies proportional to the delta and rigidity
- Distribute forces based on `balance` (or mass/static status)
type Manifold ¶
type Manifold struct {
// contains filtered or unexported fields
}
Manifold holds collision data between two bodies and resolves it.
Key C++ conventions:
- bodyA/bodyB are ordered by pointer (smaller first) — NOT reference/incident
- referenceBody = owner of contact.referenceParticles (the polygon that was hit)
- incidentBody = owner of contact.particle (the penetrating particle)
- normal = points from referenceBody toward incidentBody
- refResponseForce = -responseForce (applied to referenceBody via ApplyForce/ApplyForceToParticleSegment)
- incResponseForce = +responseForce (applied to incidentBody via ApplyForce/ApplyForceAt)
- invMass = 1 / (bodyA.mass + bodyB.mass) — uses RAW masses, no zeroing for static
- isCollisionOneSide = true if either body can't give response (includes static!)
func (*Manifold) Solve ¶
func (m *Manifold) Solve()
Solve applies position correction to resolve overlaps.
func (*Manifold) SolveFrictionAndVelocities ¶
func (m *Manifold) SolveFrictionAndVelocities()
SolveFrictionAndVelocities applies restitution and friction.
type Mesh ¶
type Mesh struct {
// contains filtered or unexported fields
}
Mesh is the shape + topology container for a body.
A Mesh carries:
- Particles (the smallest building blocks; positioned by the body)
- Polygon (the subset of particles forming the collision boundary)
- Springs (distance constraints between particles — used by soft bodies)
- AngleConstraints (3-particle angle limits — used by soft bodies)
- SubConvexPolygons (concave polygon decomposed into convex pieces for SAT)
- PolygonBisectors (cached bisector vectors for collision response)
- UVMaps (triangle index lists for rendering)
The CollisionBehavior field determines which collision algorithm runs:
- CIRCLES — particles treated as circles (no polygon)
- POLYGONS — rigid body with a polygon (uses SAT + clipping)
- POLYLINE — soft body with a polygon (treated as a deformable rope)
func NewCircleMesh ¶
NewCircleMesh creates a single-particle mesh representing a circle.
func NewMeshFromData ¶
NewMeshFromData constructs a mesh from a MeshData struct. This is the universal factory — all other factories (rect, polygon) build a MeshData and delegate here.
func NewPolygonMesh ¶
func NewPolygonMesh(radius float32, sideCount int, centerPosition Vec2, polarGrid int, opts ...MeshFactoryOption) *Mesh
NewPolygonMesh creates a regular N-gon mesh. If polarGrid > 0, generates concentric rings of internal particles connected by springs.
func NewRectMesh ¶
func NewRectMesh(size, centerPosition, grid Vec2, opts ...MeshFactoryOption) *Mesh
NewRectMesh creates a 4-corner rectangle mesh. If grid is non-zero, generates an internal grid of particles with cross-diagonal springs (used for soft bodies). For rigid bodies, pass Vec2Zero for grid.
func (*Mesh) AddAngleConstraint ¶
func (m *Mesh) AddAngleConstraint(ac *AngleConstraint) *Mesh
AddAngleConstraint attaches an angle constraint to the mesh.
func (*Mesh) AddParticle ¶
AddParticle appends a particle to the mesh and sets its owner.
func (*Mesh) AngleConstraints ¶
func (m *Mesh) AngleConstraints() []*AngleConstraint
AngleConstraints returns the angle constraints owned by this mesh.
func (*Mesh) ApplyAngleConstraintsToPolygon ¶
func (m *Mesh) ApplyAngleConstraintsToPolygon()
ApplyAngleConstraintsToPolygon applies per-vertex angle constraints to the polygon.
Algorithm:
- Intersection test: check if the polygon is self-intersecting via pairwise segment intersection. If so, apply a shape-matching fallback (pull particles toward the rest shape with force factor 0.2), clear lastPolygonCornerAngles, and return.
- First-frame skip: if lastPolygonCornerAngles size doesn't match polygon size, initialize to zeros and set beginToSaveAngles=true. On the first frame, just save angles without applying constraints.
- Angle tracking with unwrap: compute the raw atan2 angle for each vertex, then compute angleDifference = AngleBetweenTwoVectors( AngleToUnitVector(angleRad), AngleToUnitVector(lastSaved)). The unwrapped angle is lastSaved + angleDifference. This prevents wrap-around jumps at ±π.
- Position-based correction: if angle > maxAngle or < minAngle, directly SetGlobalPosition on the neighbors (NOT ApplyForce). Force factor 0.5. Check pp.Enabled() and np.Enabled() (NOT p.Enabled()).
func (*Mesh) Circumference ¶
Circumference returns the total perimeter of the polygon (using local particle positions).
func (*Mesh) CollisionBehavior ¶
func (m *Mesh) CollisionBehavior() CollisionBehavior
CollisionBehavior returns the collision behavior, computing it lazily if a recomputation is pending.
func (*Mesh) GlobalPosition ¶
GlobalPosition returns the mesh's world-space position.
func (*Mesh) GlobalRotation ¶
GlobalRotation returns the mesh's world-space rotation.
func (*Mesh) InitialArea ¶
InitialArea returns the area computed from local particle positions, including both polygon area and circle areas (for particles with r > 0.5).
func (*Mesh) ParticleAt ¶
ParticleAt returns the particle at the given index.
func (*Mesh) ParticleCount ¶
ParticleCount returns the number of particles in the mesh.
func (*Mesh) ParticleIndex ¶
ParticleIndex returns the index of the given particle, or -1 if not found.
func (*Mesh) PolygonArea ¶
PolygonArea returns the polygon area (local or global).
func (*Mesh) RemoveParticle ¶
RemoveParticle removes the given particle from the mesh.
func (*Mesh) RemoveParticleAt ¶
RemoveParticleAt removes the particle at the given index and cascades the removal to polygon, springs, UV maps, and angle constraints.
C++ calls RemoveParticleFromPolygon, RemoveMatchingSprings, RemoveMatchingUVMaps, RemoveMatchingAngleConstraints before erasing the particle from the vector. Then sets dirty flags (collisionBehaviorNeedsUpdate, polygonBisectorsNeedsUpdate, inertiaNeedsUpdate, circumferenceNeedsUpdate) and updates static body transforms if applicable.
func (*Mesh) SetGlobalPosition ¶
SetGlobalPosition sets the mesh's world-space position.
func (*Mesh) SetPolygonForCollisionsDisabled ¶
SetPolygonForCollisionsDisabled disables the polygon for collisions, forcing the mesh to use circle-based collision on its particles.
func (*Mesh) SetPosition ¶
SetPosition sets the mesh's local position.
func (*Mesh) SetRotation ¶
SetRotation sets the mesh's local rotation.
func (*Mesh) SpringCount ¶
SpringCount returns the number of springs.
func (*Mesh) SubConvexPolygons ¶
SubConvexPolygons returns the cached convex decomposition.
func (*Mesh) UpdateCollisionBehavior ¶
func (m *Mesh) UpdateCollisionBehavior()
UpdateCollisionBehavior recomputes the collision behavior based on the owning body type and polygon presence. Matches QMesh::UpdateCollisionBehavior.
func (*Mesh) UpdateSubConvexPolygons ¶
UpdateSubConvexPolygons recomputes the convex decomposition of the mesh's polygon. If the polygon is convex, the decomposition is just the polygon itself. If concave, it's decomposed via polypartition.
NOTE: The C++ engine uses the vendored polypartition library directly. The Go port uses the mesh/polypartition sub-package, but to avoid a circular import (polypartition imports physics, physics can't import polypartition), the decomposition is performed by an external function set via SetConvexPartitioner. The World sets this up at initialization.
type MeshData ¶
type MeshData struct {
ParticlePositions []Vec2
ParticleRadValues []float32
ParticleInternalValues []bool
ParticleEnabledValues []bool
ParticleLazyValues []bool
SpringList [][2]int
InternalSpringList [][2]int
Polygon []int
UVMaps [][]int
Position Vec2
Rotation float32
}
MeshData is the serializable description of a mesh. Used as input to CreateWithMeshData and as the on-disk .qmesh format (Phase 3). Matches QMesh::MeshData in qmesh.h:104-145.
func GeneratePolygonMeshData ¶
func GeneratePolygonMeshData(radius float32, sideCount int, centerPosition Vec2, polarGrid int, particleRadius float32) MeshData
GeneratePolygonMeshData produces a MeshData for a regular N-gon of the given radius and side count. If polarGrid > 0, generates concentric rings of internal particles.
func GenerateRectangleMeshData ¶
GenerateRectangleMeshData produces a MeshData for a rectangle of the given size, centered at centerPosition. If grid.X or grid.Y > 1, an internal grid of particles is generated with cross-diagonal springs.
type MeshFactoryConfig ¶
type MeshFactoryConfig struct {
// contains filtered or unexported fields
}
MeshFactoryConfig holds optional parameters for mesh factory methods.
type MeshFactoryOption ¶
type MeshFactoryOption func(*MeshFactoryConfig)
MeshFactoryOption configures a mesh factory.
func WithParticleRadius ¶
func WithParticleRadius(r float32) MeshFactoryOption
WithParticleRadius sets the particle radius used by mesh factories.
func WithPolygons ¶
func WithPolygons(b bool) MeshFactoryOption
WithPolygons enables/disables polygon generation in mesh factories.
func WithSprings ¶
func WithSprings(b bool) MeshFactoryOption
WithSprings enables/disables spring generation in mesh factories.
type Particle ¶
type Particle struct {
// contains filtered or unexported fields
}
Particle is the smallest building block of a physics mesh.
In rigid bodies, particles are positioned collectively via body transformations (see Body.UpdateMeshTransforms). In soft bodies, particles move individually via Verlet integration and are connected by springs.
Velocities are implicit: a particle's velocity is (globalPosition - prevGlobalPosition) per step.
func NewParticle ¶
NewParticle constructs a Particle at local position (posX, posY) with the given radius. Matches QParticle(float posX, float posY, float radius).
func NewParticleFromVec ¶
NewParticleFromVec constructs a Particle at a Vec2 position.
func (*Particle) AddAccumulatedForce ¶
AddAccumulatedForce appends a force to the accumulated list. The accumulated forces are averaged and applied via ApplyAccumulatedForces. Used by spring solvers to prevent iteration-order bias.
func (*Particle) AddGlobalPosition ¶
AddGlobalPosition adds a vector to the particle's world-space position.
func (*Particle) AddPosition ¶
AddPosition adds a vector to the particle's local position.
func (*Particle) AddPreviousGlobalPosition ¶
AddPreviousGlobalPosition adds a vector to the particle's previous position.
func (*Particle) ApplyAccumulatedForces ¶
ApplyAccumulatedForces computes the arithmetic mean of accumulated forces and applies it via ApplyForce, then clears the list. Matches QParticle::ApplyAccumulatedForces in qparticle.cpp:201-213.
func (*Particle) ApplyForce ¶
ApplyForce applies an immediate force to the particle by translating its global position. Matches QParticle::ApplyForce in qparticle.cpp:168-175.
Safe to call before the physics step (e.g., in OnPreStep). Calling after the step may break the simulation — use SetForce/AddForce for next-step-safe force application.
func (*Particle) ClearAccumulatedForces ¶
ClearAccumulatedForces empties the accumulated forces list.
func (*Particle) ClearOneTimeCollisions ¶
func (p *Particle) ClearOneTimeCollisions()
ClearOneTimeCollisions empties both the current and previous one-time collision sets. Matches QParticle::ClearOneTimeCollisions.
func (*Particle) Enabled ¶
Enabled reports whether the particle is active. Disabled particles still get collision-tested but their manifolds are not solved, and their force/velocity integrations are skipped.
func (*Particle) GlobalPosition ¶
GlobalPosition returns the particle's world-space position.
func (*Particle) IgnoreGravity ¶
IgnoreGravity reports whether the particle is exempt from gravity. Set by QAreaBody when gravityFree is enabled.
func (*Particle) IsConnectedWithSpring ¶
IsConnectedWithSpring reports whether this particle is connected to `other` via a spring. Backed by a set for O(1) lookup.
func (*Particle) IsInternal ¶
IsInternal reports whether this is an internal (non-boundary) particle. Internal particles don't participate in collision detection but provide structural rigidity in soft-body grids.
func (*Particle) IsLazy ¶
IsLazy reports whether the particle's lazy feature is enabled. Lazy particles react once to a collision, then ignore the colliding body until they exit and re-enter the collision.
func (*Particle) OwnerMesh ¶
OwnerMesh returns the mesh that owns this particle, or nil if detached.
func (*Particle) Position ¶
Position returns the particle's local position relative to its owning mesh.
func (*Particle) PreviousGlobalPosition ¶
PreviousGlobalPosition returns the particle's previous world-space position. Used for implicit velocity: vel = globalPosition - prevGlobalPosition.
func (*Particle) ResetOneTimeCollisions ¶
func (p *Particle) ResetOneTimeCollisions()
ResetOneTimeCollisions moves the previous set into the current set, then clears the previous. Called once per step for lazy particles. Matches QParticle::ResetOneTimeCollisions.
func (*Particle) SetEnabled ¶
SetEnabled enables or disables the particle.
func (*Particle) SetForce ¶
SetForce sets the particle's queued force (applied at next step). Matches QParticle::SetForce in qparticle.cpp:176-184.
func (*Particle) SetGlobalPosition ¶
SetGlobalPosition sets the particle's world-space position and marks the AABB dirty. Matches QParticle::SetGlobalPosition in qparticle.cpp:77-95.
func (*Particle) SetIsInternal ¶
SetIsInternal marks the particle as internal (non-boundary).
func (*Particle) SetOwnerMesh ¶
SetOwnerMesh sets the mesh that owns this particle.
func (*Particle) SetPosition ¶
SetPosition sets the particle's local position. Matches qparticle.cpp:108-124.
func (*Particle) SetPreviousGlobalPosition ¶
SetPreviousGlobalPosition sets the particle's previous world-space position. Used by the Verlet integrator and by ApplyImpulse.
func (*Particle) SetRadius ¶
SetRadius sets the particle's collision radius. Matches qparticle.cpp:139-148.
func (*Particle) UpdateAABB ¶
func (p *Particle) UpdateAABB()
UpdateAABB recomputes the particle's AABB from its current global position and radius. Matches QParticle::UpdateAABB in qparticle.cpp:45-56.
type Raycast ¶
type Raycast struct {
// contains filtered or unexported fields
}
Raycast casts a ray into the world and reports collision contacts.
Two modes:
- Instance-based: register a Raycast with World.AddRaycast; contacts are auto-updated each step via UpdateContacts().
- Static one-shot: call RaycastTo() for a fire-and-forget query.
func NewRaycast ¶
NewRaycast creates a raycast.
func (*Raycast) CollidableLayersBit ¶
func (*Raycast) Contacts ¶
func (r *Raycast) Contacts() []RaycastContact
func (*Raycast) EnabledContainingBodies ¶
func (*Raycast) SetCollidableLayersBit ¶
func (*Raycast) SetEnabledContainingBodies ¶
func (*Raycast) SetPosition ¶
func (*Raycast) SetRayVector ¶
func (*Raycast) SetRotation ¶
func (*Raycast) UpdateContacts ¶
func (r *Raycast) UpdateContacts()
UpdateContacts re-computes the raycast contacts. Called automatically by World.Update for registered raycasts. Matches QRaycast::UpdateContacts in qraycast.cpp:86-90.
type RaycastContact ¶
RaycastContact is a single ray hit. Matches QRaycast::Contact.
func RaycastTo ¶
func RaycastTo(world *World, rayPosition, rayVector Vec2, collidableLayers int, enableContainingBodies bool) []RaycastContact
RaycastTo performs a one-shot raycast against the world.
Filters bodies by AABB and layer bits, then tests each body's meshes for ray-polygon or ray-circle intersection.
type RigidBody ¶
type RigidBody struct {
Body
// contains filtered or unexported fields
}
RigidBody is a non-deformable solid body simulated with Verlet integration.
Verlet integration: velocity is implicit, computed as (position - prevPosition). Forces are applied by translating position directly (and prevPosition for impulses). Rotation works the same way via prevRotation.
Key behaviors preserved from C++:
- Float-drift clamp: velocity components < 0.01 are zeroed (qrigidbody.cpp:146-153)
- Velocity limit clamping
- Air friction drag
- Gravity (custom or world)
- Force/angularForce accumulation (applied next step)
- ApplyImpulse modifies prevPosition (Verlet-style impulse)
func GetRigidBody ¶
GetRigidBody returns the *RigidBody that embeds the given *Body, or nil. This is the exported version of asRigidBody, for use by external packages (e.g., the examples' mouse drag handler).
func NewRigidBody ¶
func NewRigidBody() *RigidBody
NewRigidBody constructs a RigidBody with default values.
func (*RigidBody) AddAngularForce ¶
AddAngularForce adds to the queued angular force.
func (*RigidBody) AngularForce ¶
AngularForce returns the currently-queued angular force.
func (*RigidBody) ApplyForce ¶
ApplyForce applies an immediate force at the body's center (no torque).
func (*RigidBody) ApplyForceAt ¶
ApplyForce applies an immediate force at an offset. Translates the body by `force` and rotates by r · force.Perpendicular() / inertia.
Safe before the physics step (e.g., in OnPreStep). Calling after the step may break the simulation — use SetForce/AddForce for next-step-safe.
func (*RigidBody) ApplyImpulse ¶
ApplyImpulse applies an impulse by modifying prevPosition (Verlet-style). Matches QRigidBody::ApplyImpulse in qrigidbody.cpp:84-96.
func (*RigidBody) AsBody ¶
AsBody returns a *Body pointer for this RigidBody. Useful when an API requires a *Body (e.g., World.AddBody).
func (*RigidBody) FixedRotationEnabled ¶
FixedRotationEnabled reports whether rotation is locked.
func (*RigidBody) KinematicCollisionsEnabled ¶
KinematicCollisionsEnabled reports whether kinematic-kinematic collisions react.
func (*RigidBody) KinematicEnabled ¶
KinematicEnabled reports whether the body is kinematic.
func (*RigidBody) PostUpdate ¶
func (rb *RigidBody) PostUpdate()
PostUpdate is a no-op for rigid bodies. (PlatformerBody overrides.)
func (*RigidBody) SetAngularForce ¶
SetAngularForce sets the queued angular force. Matches QRigidBody::SetAngularForce in qrigidbody.cpp:102-107.
func (*RigidBody) SetFixedRotationEnabled ¶
SetFixedRotationEnabled controls whether rotation is locked.
func (*RigidBody) SetForce ¶
SetForce sets the queued force for the next step. Matches QRigidBody::SetForce in qrigidbody.cpp:67-72.
func (*RigidBody) SetKinematicCollisionsEnabled ¶
SetKinematicCollisionsEnabled controls kinematic-kinematic collision response.
func (*RigidBody) SetKinematicEnabled ¶
SetKinematicEnabled controls whether the body is kinematic.
func (*RigidBody) SetPositionAndCollide ¶
SetPositionAndCollide sets the position and immediately runs collision resolution against the world. Use this for teleport-style movement. Matches QRigidBody::SetPositionAndCollide in qrigidbody.cpp:41-48.
func (*RigidBody) Update ¶
func (rb *RigidBody) Update()
Update performs Verlet integration for one step.
CRITICAL: This method preserves the C++ float-drift clamp at lines 146-153 — velocity components < 0.01 are zeroed to fight float drift. Do NOT remove or adjust without re-running the parity suite.
type SAPBroadPhase ¶
type SAPBroadPhase struct {
// contains filtered or unexported fields
}
SAPBroadPhase is the default Sweep-and-Prune implementation.
func NewSAPBroadPhase ¶
func NewSAPBroadPhase() *SAPBroadPhase
NewSAPBroadPhase constructs an empty SAP broadphase.
func (*SAPBroadPhase) Insert ¶
func (s *SAPBroadPhase) Insert(b *Body)
Insert adds a body (if not already present).
func (*SAPBroadPhase) Pairs ¶
func (s *SAPBroadPhase) Pairs() []BodyPair
Pairs returns candidate collision pairs via Sweep-and-Prune.
type Side ¶
type Side int
Side enumerates the four cardinal directions, used by GetVectorSide. Matches the QSides enum in qvector.h:36-42.
func GetVectorSide ¶
GetVectorSide classifies a vector relative to a reference "up" direction. maxAngleDefiningSide defaults to π/4 (45°) in callers. Matches QVector::GetVectorSide in qvector.cpp:71-86.
type SoftBody ¶
type SoftBody struct {
Body
// contains filtered or unexported fields
}
SoftBody is a deformable body using mass-spring model with PBD. Matches QSoftBody in qsoftbody.h, qsoftbody.cpp.
Soft bodies have:
- Per-particle Verlet integration (each particle moves independently)
- Springs connecting particles (structural rigidity)
- Optional area-preserving (pressure-based volume conservation)
- Optional shape matching (pulls particles toward rest shape)
- Optional self-collisions (particles collide with each other)
The simulation model is MASS_SPRING (vs RIGID_BODY for rigid bodies). This affects how the World.Update loop dispatches the body's Update.
func NewSoftBody ¶
func NewSoftBody() *SoftBody
NewSoftBody constructs a SoftBody with default values.
func (*SoftBody) ApplyForce ¶
ApplyForce applies a force to all particles in the soft body. Matches QSoftBody::ApplyForce in qsoftbody.cpp:74-91.
func (*SoftBody) ApplyShapeMatching ¶
func (sb *SoftBody) ApplyShapeMatching()
ApplyShapeMatching pulls particles toward their rest shape.
Computes the average position and rotation of the current particles, then computes target positions by rotating the rest (local) positions by that rotation. Applies a quadratic force toward each target.
func (*SoftBody) AreaPreservingEnabled ¶
AreaPreservingEnabled reports whether area preserving is active.
func (*SoftBody) AreaPreservingRate ¶
AreaPreservingRate returns the rate at which the target area is applied.
func (*SoftBody) AreaPreservingRigidity ¶
AreaPreservingRigidity returns the rigidity of area-preserving constraints.
func (*SoftBody) ParticleSpecificMass ¶
ParticleSpecificMass returns the per-particle mass (if enabled).
func (*SoftBody) ParticleSpecificMassEnabled ¶
ParticleSpecificMassEnabled reports whether per-particle mass is active.
func (*SoftBody) PassivationOfInternalSpringsEnabled ¶
PassivationOfInternalSpringsEnabled reports whether internal springs are passive.
func (*SoftBody) PostUpdate ¶
func (sb *SoftBody) PostUpdate()
PostUpdate is a no-op for soft bodies.
func (*SoftBody) PreserveAreas ¶
func (sb *SoftBody) PreserveAreas()
PreserveAreas applies the area-preserving pressure force.
Computes the difference between the target area and the current polygon area, then pushes each polygon vertex along its edge normal to restore the target area. Includes the area stability hysteresis and the ±5× area clamp from the C++ engine.
func (*SoftBody) SelfCollisionsEnabled ¶
SelfCollisionsEnabled reports whether particles self-collide.
func (*SoftBody) SelfCollisionsSpecifiedRadius ¶
SelfCollisionsSpecifiedRadius returns the self-collision particle radius.
func (*SoftBody) SetAreaPreservingEnabled ¶
SetAreaPreservingEnabled enables or disables area preserving. When enabled, the target area is computed from the initial polygon area.
func (*SoftBody) SetAreaPreservingRate ¶
SetAreaPreservingRate sets the area preserving rate (0.0–1.0).
func (*SoftBody) SetAreaPreservingRigidity ¶
SetAreaPreservingRigidity sets the area preserving rigidity.
func (*SoftBody) SetParticleSpecificMass ¶
SetParticleSpecificMass sets the per-particle mass.
func (*SoftBody) SetParticleSpecificMassEnabled ¶
SetParticleSpecificMassEnabled enables/disables per-particle mass.
func (*SoftBody) SetPassivationOfInternalSpringsEnabled ¶
SetPassivationOfInternalSpringsEnabled enables/disables internal spring passivation.
func (*SoftBody) SetRigidity ¶
SetRigidity sets the body's rigidity (affects spring stiffness).
func (*SoftBody) SetSelfCollisionsEnabled ¶
SetSelfCollisionsEnabled enables or disables particle self-collisions.
func (*SoftBody) SetSelfCollisionsSpecifiedRadius ¶
SetSelfCollisionsSpecifiedRadius sets the self-collision particle radius.
func (*SoftBody) SetShapeMatchingEnabled ¶
SetShapeMatchingEnabled enables/disables shape matching. withoutInternals controls whether internal particles are included.
func (*SoftBody) SetShapeMatchingFixedPosition ¶
SetShapeMatchingFixedPosition sets the fixed target position.
func (*SoftBody) SetShapeMatchingFixedRotation ¶
SetShapeMatchingFixedRotation sets the fixed target rotation.
func (*SoftBody) SetShapeMatchingFixedTransformEnabled ¶
SetShapeMatchingFixedTransformEnabled enables/disables fixed target transform.
func (*SoftBody) SetShapeMatchingRate ¶
SetShapeMatchingRate sets the shape matching rate (0.0–1.0).
func (*SoftBody) SetTargetPreservationArea ¶
SetTargetPreservationArea sets the explicit target area.
func (*SoftBody) ShapeMatchingEnabled ¶
ShapeMatchingEnabled reports whether shape matching is active.
func (*SoftBody) ShapeMatchingFixedPosition ¶
ShapeMatchingFixedPosition returns the fixed target position.
func (*SoftBody) ShapeMatchingFixedRotation ¶
ShapeMatchingFixedRotation returns the fixed target rotation.
func (*SoftBody) ShapeMatchingFixedTransformEnabled ¶
ShapeMatchingFixedTransformEnabled reports whether a fixed target transform is used.
func (*SoftBody) ShapeMatchingRate ¶
ShapeMatchingRate returns the shape matching rate.
func (*SoftBody) TargetPreservationArea ¶
TargetPreservationArea returns the target area for area preserving.
type Spring ¶
type Spring struct {
// contains filtered or unexported fields
}
Spring is a distance constraint between two particles. Matches QSpring in qspring.h, qspring.cpp.
Springs are used both internally by soft-body meshes (to maintain structural rigidity) and externally as world springs (e.g., mouse drag). The Update method applies corrective forces to both particles to bring them toward the rest length.
Two application paths:
- Direct (internalsException=false): ApplyForce on each particle immediately.
- Accumulated (internalsException=true): AddAccumulatedForce, then the caller must call ApplyAccumulatedForces later. This prevents iteration order bias when many springs share particles.
func NewSpring ¶
NewSpring creates a spring between two particles, auto-calculating the rest length from the current distance.
func NewSpringWithLength ¶
NewSpringWithLength creates a spring with an explicit rest length.
func (*Spring) DistanceLimitEnabled ¶
DistanceLimitEnabled reports whether the distance limit feature is active.
func (*Spring) IsInternal ¶
IsInternal reports whether this is an internal spring (affects area-preserving).
func (*Spring) MaximumDistanceFactor ¶
MaximumDistanceFactor returns the max distance factor.
func (*Spring) MinimumDistanceFactor ¶
MinimumDistanceFactor returns the min distance factor (relative to rest length).
func (*Spring) SetDistanceLimitEnabled ¶
SetDistanceLimitEnabled enables/disables the distance limit. When enabled, the spring applies full-strength (rigidity=1.0) correction when the current distance falls outside [length*minFactor, length*maxFactor].
func (*Spring) SetEnabled ¶
SetEnabled enables or disables the spring.
func (*Spring) SetIsInternal ¶
SetIsInternal marks the spring as internal.
func (*Spring) SetMaximumDistanceFactor ¶
SetMaximumDistanceFactor sets the max distance factor.
func (*Spring) SetMinimumDistanceFactor ¶
SetMinimumDistanceFactor sets the min distance factor.
func (*Spring) SetParticleA ¶
SetParticleA sets the first particle.
func (*Spring) SetParticleB ¶
SetParticleB sets the second particle.
func (*Spring) SetRigidity ¶
SetRigidity sets the spring's rigidity (0.0-1.0).
func (*Spring) Update ¶
Update applies spring constraints and updates particle positions. Matches QSpring::Update in qspring.cpp:50-166.
Parameters:
- rigidity: override rigidity (multiplied with the spring's own rigidity)
- internalsException: if true and spring is internal, use the accumulated-force path
- isWorldSpring: if true, skip particles owned by rigid/static bodies
type Vec2 ¶
type Vec2 struct {
X, Y float32
}
Vec2 is a 2D float32 vector. Matches QVector in qvector.h.
Operations preserve the C++ engine's behavior, including:
- Normalized() returns Vec2Zero() for zero-length vectors (never NaN)
- The Y axis points down, matching QVector::Down() = (0, 1)
Reference: QuarkPhysics/qvector.h, qvector.cpp
func AngleToUnitVector ¶
AngleToUnitVector returns the unit vector pointing in the direction of radianAngle. Matches QVector::AngleToUnitVector in qvector.cpp.
func ComputeFriction ¶
func ComputeFriction(bodyA, bodyB *Body, normal Vec2, penetration float32, relativeVelocity Vec2) Vec2
ComputeFriction calculates the friction force for a collision.
Uses Coulomb friction: tangent = relativeVelocity projected onto the contact plane; if |jt| < penetration * staticFriction, use static friction, otherwise use dynamic friction.
func GetAveragePositionAndRotation ¶
GetAveragePositionAndRotation computes the average position and rotation of a set of particles. Used by shape matching to find the target transform.
The rotation is computed by finding the angle that best aligns the current particle positions with their local (rest) positions.
func GetBisectorUnitVector ¶
GetBisectorUnitVector returns the unit bisector vector of the angle formed at pointB by rays (pointB→pointA) and (pointB→pointC). Matches QVector::GeteBisectorUnitVector in qvector.cpp:88-119.
The C++ implementation:
fromPrev = pointB - pointA
toNext = pointC - pointB
prevToNext = pointC - pointA
prevToNextPerp = prevToNext.Perpendicular()
bisectorUnit = prevToNextPerp.Normalized()
if fromPrev · prevToNextPerp < 0:
if checkPointsAreCCW:
toCenterPos = prevToNext*0.5 - fromPrev
if toCenterPos · bisectorUnit < 0: bisectorUnit = -bisectorUnit
else:
if checkPointsAreCCW:
toCenterPos = prevToNext*0.5 - fromPrev
if toCenterPos · bisectorUnit > 0: bisectorUnit = -bisectorUnit
else:
bisectorUnit = bisectorUnit (no-op)
return -bisectorUnit
func GetMatchingParticlePositions ¶
func GetMatchingParticlePositions(particles []*Particle, targetPosition Vec2, targetRotation float32) []Vec2
GetMatchingParticlePositions computes the target positions for shape matching. Each particle's LOCAL position is rotated by -targetRotation and translated to targetPosition.
func LineIntersectionLine ¶
LineIntersectionLine computes the intersection of two line segments. Returns Vec2NaN() if no intersection. Matches QCollision::LineIntersectionLine.
func Vec2NaN ¶
func Vec2NaN() Vec2
Vec2NaN returns a vector with NaN components, used as a sentinel for "no intersection" in LineIntersectionLine.
func Vec2Up ¶
func Vec2Up() Vec2
Vec2Up returns (0, -1). Matches QVector::Up (Y is inverted: up is negative).
func (Vec2) Dot ¶
Dot returns the dot product of v and other. Matches QVector::Dot in qvector.h:161-163.
func (Vec2) Equal ¶
Equal reports whether v and other have identical components. Note: uses exact equality, matching qvector.h:138-140.
func (Vec2) IsNaN ¶
IsNaN reports whether both components are NaN. Matches QVector::isNaN in qvector.h:183-188 (returns true only if BOTH x and y are NaN).
func (Vec2) Length ¶
Length returns |v|. If you only need to compare lengths, use LengthSquared to avoid the sqrt. Matches QVector::Length in qvector.h:164-166.
func (Vec2) LengthSquared ¶
LengthSquared returns |v|². Cheaper than Length (no sqrt). Matches QVector::LengthSquared in qvector.h:179-181.
func (Vec2) Normalized ¶
Normalized returns the unit vector in the direction of v. Returns Vec2Zero() if v is zero-length — never returns NaN. Matches QVector::Normalized in qvector.h:167-175.
func (Vec2) Perpendicular ¶
Perpendicular returns the vector (v.Y, -v.X), rotated 90° clockwise. Matches QVector::Perpendicular in qvector.h:176-178.
type World ¶
type World struct {
// contains filtered or unexported fields
}
World manages a physics simulation. Matches QWorld in qworld.h, qworld.cpp.
The World owns all bodies, joints, springs, raycasts, and the contact pool. One call to Update() advances the simulation by one step.
func NewWorld ¶
func NewWorld(opts ...WorldOption) *World
NewWorld constructs a World with the given options.
func (*World) AddAreaBody ¶
AddAreaBody convenience: adds an AreaBody to the world and registers it.
func (*World) AddBody ¶
AddBody adds a body to the world and links it back. Matches QWorld::AddBody.
func (*World) AddCollisionException ¶
AddCollisionException marks two bodies as never colliding.
func (*World) AddRaycast ¶
AddRaycast registers a raycast for auto-updating each step.
func (*World) AddRigidBody ¶
AddRigidBody convenience: adds a RigidBody to the world and registers it.
func (*World) AddSoftBody ¶
AddSoftBody convenience: adds a SoftBody to the world and registers it.
func (*World) Broadphase ¶
func (w *World) Broadphase() BroadPhase
Broadphase returns the custom broadphase implementation, or nil.
func (*World) BroadphaseEnabled ¶
BroadphaseEnabled reports whether broadphase is enabled.
func (*World) CheckCollisionException ¶
CheckCollisionException reports whether two bodies have a collision exception.
func (*World) CollideWithWorld ¶
CollideWithWorld runs collision detection and resolution for a single body against all others. Used by RigidBody.SetPositionAndCollide and QPlatformerBody. Matches QWorld::CollideWithWorld in qworld.cpp:588-604.
func (*World) ContactPool ¶
func (w *World) ContactPool() *ContactPool
ContactPool returns the world's contact pool (for Manifold).
func (*World) DebugGizmos ¶
DebugGizmos reports whether debug gizmo recording is enabled.
func (*World) IterationCount ¶
IterationCount returns the solver iteration count.
func (*World) JointCount ¶
JointCount returns the number of joints.
func (*World) RaycastCount ¶
RaycastCount returns the number of registered raycasts.
func (*World) RemoveBody ¶
RemoveBody removes a body from the world.
func (*World) RemoveBodyAt ¶
RemoveBodyAt removes the body at the given index.
func (*World) RemoveCollisionException ¶
RemoveCollisionException removes a collision exception.
func (*World) RemoveJoint ¶
RemoveJoint removes a joint from the world.
func (*World) RemoveMatchingCollisionExceptions ¶
RemoveMatchingCollisionExceptions removes all exceptions involving body.
func (*World) RemoveRaycast ¶
RemoveRaycast removes a raycast from the world.
func (*World) RemoveSpring ¶
RemoveSpring removes a spring from the world.
func (*World) SetBroadphase ¶
func (w *World) SetBroadphase(bp BroadPhase) *World
SetBroadphase sets a custom broadphase implementation.
func (*World) SetBroadphaseEnabled ¶
SetBroadphaseEnabled enables or disables broadphase.
func (*World) SetDebugGizmos ¶
SetDebugGizmos enables or disables debug gizmo recording.
func (*World) SetEnabled ¶
SetEnabled enables or disables the world.
func (*World) SetGravity ¶
SetGravity sets the world's gravity vector.
func (*World) SetIterationCount ¶
SetIterationCount sets the solver iteration count.
func (*World) SetSleepingEnabled ¶
SetSleepingEnabled enables or disables sleeping.
func (*World) SetSoftBodyCollisionHysteresis ¶
SetSoftBodyCollisionHysteresis sets the global hysteresis factor. Matches qworld.h:301. Range [0,1].
func (*World) SetTimeScale ¶
SetTimeScale sets the world's time scale.
func (*World) SleepingEnabled ¶
SleepingEnabled reports whether sleeping is enabled.
func (*World) SoftBodyCollisionHysteresis ¶
SoftBodyCollisionHysteresis returns the global hysteresis factor for soft-body-vs-soft-body collisions. Matches qworld.h:181. Default 0.2.
func (*World) SpringCount ¶
SpringCount returns the number of world-level springs.
func (*World) TestCollisionWithWorld ¶
TestCollisionWithWorld runs collision detection (no solving) and returns the manifolds. Used by QPlatformerBody probes.
func (*World) Update ¶
func (w *World) Update()
Update advances the simulation by one step. Matches QWorld::Update in qworld.cpp:63-434
- Per-body Update (Verlet integration)
- OnPreStep events
- Broadphase prep
- Iteration loop: narrowphase + Solve + SolveFrictionAndVelocities
- Global AABB update
- Sleeping
- OnStep events
func (*World) UpdateConstraints ¶
func (w *World) UpdateConstraints()
UpdateConstraints solves all soft body springs, angle constraints, world springs, and joints. Matches QWorld::UpdateConstraints in qworld.cpp:1175-1236.
Called once per solver iteration. For soft bodies, springs and angle constraints use the accumulated-force pipeline to prevent iteration order bias: forces are accumulated per-particle, then averaged and applied at the end of each constraint type's pass.
type WorldOption ¶
type WorldOption func(*World)
WorldOption configures a World at construction.
func WithBroadphase ¶
func WithBroadphase(b bool) WorldOption
WithBroadphase enables or disables broadphase (default enabled).
func WithBroadphaseImpl ¶
func WithBroadphaseImpl(bp BroadPhase) WorldOption
WithBroadphaseImpl sets a custom broadphase implementation.
func WithConcurrency ¶
func WithConcurrency(config ConcurrencyConfig) WorldOption
WithConcurrency enables parallel narrowphase with the given config.
func WithDebugGizmos ¶
func WithDebugGizmos(b bool) WorldOption
WithDebugGizmos enables or disables debug gizmo recording.
func WithGravity ¶
func WithGravity(g Vec2) WorldOption
WithGravity sets the world's gravity vector.
func WithIterations ¶
func WithIterations(n int) WorldOption
WithIterations sets the solver iteration count (default 4).
func WithSleeping ¶
func WithSleeping(b bool) WorldOption
WithSleeping enables or disables sleeping (default enabled).