physics

package
v0.3.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 24, 2025 License: BSD-3-Clause Imports: 5 Imported by: 1

README

XYZ Physics Engine

This physics engine is a scenegraph-based 3D physics simulator for creating virtual environments. It provides a Body node for rigid body physics, along with some basic geometrical shapes thereof. The physics scene contains just the bare physics bodies and other elements, which can be updated independent of any visualization.

Currently, it provides collision detection and basic forward Euler physics updating, but it does not yet compute any forces for the interactions among the bodies. Ultimately we hope to figure out how the Bullet system works and get that running here, in a clean and simple implementation.

Incrementally, we will start with a basic explicitly driven form of physics that is sufficient to get started, and build from there.

The world visualization sub-package generates an xyz 3D scenegraph based on the physics bodies, and updates this visualization efficiently as the physics is updated. world2d provides a 2D projection of the 3D physics world, using corresponding SVG nodes. This can provide simpler representations for map-like layouts etc.

See physics example for an implemented example that shows how to do everything.

Organizing the World

It is most efficient to create a relatively deep tree with Group nodes that collect nearby Body objects at multiple levels of spatial scale. Bounding Boxes are computed at every level of Group, and pruning is done at every level, so large chunks of the tree can be eliminated easily with this strategy.

Also, Nodes must be specifically flagged as being Dynamic -- otherwise they are assumed to be static -- and each type should be organized into separate top-level Groups (there can be multiple of each, but don't mix Dynamic and Static). Static nodes are never collided against each-other. Ideally, all the Dynamic nodes are in separate top-level, or at least second-to-top level groups -- this eliminates redundant A vs. B and B vs. A collisions and focuses each collision on the most relevant information.

Updating Modes

There are two major modes of updating: Scripted or Physics -- scripted requires a program to control what happens on every time step, while physics uses computed forces from contacts, plus joint constraints, to update velocities (not yet supported). The update modes are just about which methods you call.

The Group has a set of World* methods that should be used on the top-level world Group node node to do all the init and update steps. The update loops automatically exclude non Dynamic nodes.

  • WorldInit -- everyone calls this at the start to set the initial config

  • WorldRelToAbs -- for scripted mode when updating relative positions, rotations.

  • WorldStep -- for either scripted or physics modes, to update state from current velocities.

  • WorldCollide -- returns list of potential collision contacts based on projected motion, focusing on dynamic vs. static and dynamic vs. dynamic bodies, with optimized tree filtering. This is the first pass for collision detection.

Scripted Mode

For Scripted mode, each update step typically involves manually updating the Rel.Pos and .Quat fields on Body objects to update their relative positions. This field is a State type and has MoveOnAxis and RotateOnAxis (and a number of other rotation methods). The Move methods update the LinVel field to reflect any delta in movement.

It is also possible to manually set the Abs.LinVel and Abs.AngVel fields and call Step to update.

For collision detection, it is essential to have the Abs.LinVel field set to anticipate the effects of motion and determine likely future impacts. The RelToAbs update call does this automatically, and if you're instead using Step the LinVel is already set. Both calls will automatically compute an updated BBox and VelBBox.

It is up to the user to manage the list of potential collisions, e.g., by setting velocity to 0 or bouncing back etc.

Physics Mode

The good news so far is that the full physics version as in Bullet is actually not too bad. The core update step is a super simple forward Euler, intuitive update (just add velocity to position, with a step size factor). The remaining work is just in computing the forces to update those velocities. Bullet uses a hybrid approach that is clearly described in the Mirtich thesis, which combines impulses with a particular way of handling joints, due originally to Featherstone. Impulses are really simple conceptually: when two objects collide, they bounce back off of each other in proportion to their Bounce (coefficient of restitution) factor -- these collision impact forces dominate everything else, and aren't that hard to compute (similar conceptually to the marbles example in GoGi). The joint constraint stuff is a bit more complicated but not the worst. Everything can be done incrementally. And the resulting system will avoid the brittle nature of the full constraint-based approach taken in ODE, which caused a lot of crashes and instability in cemer.

One of the major problems with the impulse-based approach: it causes otherwise "still" objects to jiggle around and slip down planes, seems eminently tractable with special-case code that doesn't seem too hard.

more info: https://caseymuratori.com/blog_0003

Documentation

Index

Constants

View Source
const (
	// DynsTopGps is passed to WorldCollide when all dynamic objects are in separate top groups
	DynsTopGps = true

	// DynsSubGps is passed to WorldCollide when all dynamic objects are in separate groups under top
	// level (i.e., one level deeper)
	DynsSubGps
)
View Source
const AngMotionMax = math.Pi / 4

AngMotionMax is maximum angular motion that can be taken per update

Variables

This section is empty.

Functions

func AsNode

func AsNode(n tree.Node) (Node, *NodeBase)

AsNode converts a tree.Node to a Node interface and a [Node3DBase] object, or nil if not possible.

Types

type BBox

type BBox struct {

	// bounding box in world coords (Axis-Aligned Bounding Box = AABB)
	BBox math32.Box3

	// velocity-projected bounding box in world coords: extend BBox to include future position of moving bodies -- collision must be made on this basis
	VelBBox math32.Box3

	// bounding sphere in local coords
	BSphere math32.Sphere

	// area
	Area float32

	// volume
	Volume float32
}

BBox contains bounding box and other gross object properties

func (*BBox) IntersectsVelBox

func (bb *BBox) IntersectsVelBox(oth *BBox) bool

IntersectsVelBox returns true if two velocity-projected bounding boxes intersect

func (*BBox) SetBounds

func (bb *BBox) SetBounds(min, max math32.Vector3)

SetBounds sets BBox from min, max and updates other factors based on that

func (*BBox) UpdateFromBBox

func (bb *BBox) UpdateFromBBox()

UpdateFromBBox updates other values from BBox

func (*BBox) VelNilProject

func (bb *BBox) VelNilProject()

VelNilProject is for static items -- just copy the BBox

func (*BBox) VelProject

func (bb *BBox) VelProject(vel math32.Vector3, step float32)

VelProject computes the velocity-projected bounding box for given velocity and step size

func (*BBox) XForm

func (bb *BBox) XForm(q math32.Quat, pos math32.Vector3)

XForm transforms bounds with given quat and position offset to convert to world coords

type Body

type Body interface {
	Node

	// AsBodyBase returns the body as a BodyBase
	AsBodyBase() *BodyBase
}

Body is the common interface for all body types

type BodyBase

type BodyBase struct {
	NodeBase

	// rigid body properties, including mass, bounce, friction etc
	Rigid Rigid

	// visualization name -- looks up an entry in the scene library that provides the visual representation of this body
	Vis string

	// default color of body for basic InitLibrary configuration
	Color string
}

BodyBase is the base type for all specific Body types

func NewBodyBase

func NewBodyBase(parent ...tree.Node) *BodyBase

NewBodyBase returns a new BodyBase with the given optional parent: BodyBase is the base type for all specific Body types

func (*BodyBase) AsBody

func (bb *BodyBase) AsBody() Body

func (*BodyBase) AsBodyBase

func (bb *BodyBase) AsBodyBase() *BodyBase

func (*BodyBase) GroupBBox

func (bb *BodyBase) GroupBBox()

func (*BodyBase) SetColor

func (t *BodyBase) SetColor(v string) *BodyBase

SetColor sets the [BodyBase.Color]: default color of body for basic InitLibrary configuration

func (*BodyBase) SetRigid

func (t *BodyBase) SetRigid(v Rigid) *BodyBase

SetRigid sets the [BodyBase.Rigid]: rigid body properties, including mass, bounce, friction etc

func (*BodyBase) SetVis

func (t *BodyBase) SetVis(v string) *BodyBase

SetVis sets the [BodyBase.Vis]: visualization name -- looks up an entry in the scene library that provides the visual representation of this body

type BodyPoint

type BodyPoint struct {
	Body  Body
	Point math32.Vector3
}

BodyPoint contains a Body and a Point on that body

type Box

type Box struct {
	BodyBase

	// size of box in each dimension (units arbitrary, as long as they are all consistent -- meters is typical)
	Size math32.Vector3
}

Box is a box body shape

func NewBox

func NewBox(parent ...tree.Node) *Box

NewBox returns a new Box with the given optional parent: Box is a box body shape

func (*Box) InitAbs

func (bx *Box) InitAbs(par *NodeBase)

func (*Box) RelToAbs

func (bx *Box) RelToAbs(par *NodeBase)

func (*Box) SetBBox

func (bx *Box) SetBBox()

func (*Box) SetSize

func (t *Box) SetSize(v math32.Vector3) *Box

SetSize sets the [Box.Size]: size of box in each dimension (units arbitrary, as long as they are all consistent -- meters is typical)

func (*Box) Step

func (bx *Box) Step(step float32)

type Capsule

type Capsule struct {
	BodyBase

	// height of the cylinder portion of the capsule
	Height float32

	// radius of the top hemisphere
	TopRad float32

	// radius of the bottom hemisphere
	BotRad float32
}

Capsule is a generalized cylinder body shape, with hemispheres at each end, with separate radii for top and bottom.

func NewCapsule

func NewCapsule(parent ...tree.Node) *Capsule

NewCapsule returns a new Capsule with the given optional parent: Capsule is a generalized cylinder body shape, with hemispheres at each end, with separate radii for top and bottom.

func (*Capsule) InitAbs

func (cp *Capsule) InitAbs(par *NodeBase)

func (*Capsule) RelToAbs

func (cp *Capsule) RelToAbs(par *NodeBase)

func (*Capsule) SetBBox

func (cp *Capsule) SetBBox()

func (*Capsule) SetBotRad

func (t *Capsule) SetBotRad(v float32) *Capsule

SetBotRad sets the [Capsule.BotRad]: radius of the bottom hemisphere

func (*Capsule) SetHeight

func (t *Capsule) SetHeight(v float32) *Capsule

SetHeight sets the [Capsule.Height]: height of the cylinder portion of the capsule

func (*Capsule) SetTopRad

func (t *Capsule) SetTopRad(v float32) *Capsule

SetTopRad sets the [Capsule.TopRad]: radius of the top hemisphere

func (*Capsule) Step

func (cp *Capsule) Step(step float32)

type Contact

type Contact struct {

	// one body
	A Body

	// the other body
	B Body

	// normal pointing from center of B to center of A
	NormB math32.Vector3

	// point on spherical shell of B where A is contacting
	PtB math32.Vector3

	// distance from PtB along NormB to contact point on spherical shell of A
	Dist float32
}

Contact is one pairwise point of contact between two bodies. Contacts are represented in spherical terms relative to the spherical BBox of A and B.

func (*Contact) UpdateDist added in v0.2.0

func (c *Contact) UpdateDist()

UpdateDist updates the distance information for the contact

type Contacts

type Contacts []*Contact

Contacts is a slice list of contacts

func BodyVelBBoxIntersects

func BodyVelBBoxIntersects(a, b Node) Contacts

BodyVelBBoxIntersects returns the list of potential contact nodes between a and b (could be the same or different groups) that have intersecting velocity-projected bounding boxes. In general a should be dynamic bodies and b either dynamic or static. This is the broad first-pass filtering.

func (*Contacts) New

func (cs *Contacts) New(a, b Body) *Contact

New adds a new contact to the list

type Cylinder

type Cylinder struct {
	BodyBase

	// height of the cylinder
	Height float32

	// radius of the top -- set to 0 for a cone
	TopRad float32

	// radius of the bottom
	BotRad float32
}

Cylinder is a generalized cylinder body shape, with separate radii for top and bottom. A cone has a zero radius at one end.

func NewCylinder

func NewCylinder(parent ...tree.Node) *Cylinder

NewCylinder returns a new Cylinder with the given optional parent: Cylinder is a generalized cylinder body shape, with separate radii for top and bottom. A cone has a zero radius at one end.

func (*Cylinder) InitAbs

func (cy *Cylinder) InitAbs(par *NodeBase)

func (*Cylinder) RelToAbs

func (cy *Cylinder) RelToAbs(par *NodeBase)

func (*Cylinder) SetBBox

func (cy *Cylinder) SetBBox()

func (*Cylinder) SetBotRad

func (t *Cylinder) SetBotRad(v float32) *Cylinder

SetBotRad sets the [Cylinder.BotRad]: radius of the bottom

func (*Cylinder) SetHeight

func (t *Cylinder) SetHeight(v float32) *Cylinder

SetHeight sets the [Cylinder.Height]: height of the cylinder

func (*Cylinder) SetTopRad

func (t *Cylinder) SetTopRad(v float32) *Cylinder

SetTopRad sets the [Cylinder.TopRad]: radius of the top -- set to 0 for a cone

func (*Cylinder) Step

func (cy *Cylinder) Step(step float32)

type Group

type Group struct {
	NodeBase
}

Group is a container of bodies, joints, or other groups it should be used strategically to partition the space and its BBox is used to optimize tree-based collision detection. Use a group for the top-level World node as well.

func NewGroup

func NewGroup(parent ...tree.Node) *Group

NewGroup returns a new Group with the given optional parent: Group is a container of bodies, joints, or other groups it should be used strategically to partition the space and its BBox is used to optimize tree-based collision detection. Use a group for the top-level World node as well.

func (*Group) GroupBBox

func (gp *Group) GroupBBox()

func (*Group) InitAbs

func (gp *Group) InitAbs(par *NodeBase)

func (*Group) RayBodyIntersections

func (gp *Group) RayBodyIntersections(ray math32.Ray) []*BodyPoint

RayBodyIntersections returns a list of bodies whose bounding box intersects with the given ray, with the point of intersection

func (*Group) RelToAbs

func (gp *Group) RelToAbs(par *NodeBase)

func (*Group) Step

func (gp *Group) Step(step float32)

func (*Group) WorldCollide

func (gp *Group) WorldCollide(dynTop bool) []Contacts

WorldCollide does first pass filtering step of collision detection based on separate dynamic vs. dynamic and dynamic vs. static groups. If dynTop is true, then each Dynamic group is separate at the top level -- otherwise they are organized at the next group level. Contacts are organized by dynamic group, when non-nil, for easier processing.

func (*Group) WorldDynGroupBBox

func (gp *Group) WorldDynGroupBBox()

WorldDynGroupBBox does a GroupBBox on all dynamic nodes

func (*Group) WorldInit

func (gp *Group) WorldInit()

WorldInit does the full tree InitAbs and GroupBBox updates

func (*Group) WorldRelToAbs

func (gp *Group) WorldRelToAbs()

WorldRelToAbs does a full RelToAbs update for all Dynamic groups, for Scripted mode updates with manual updating of Rel values.

func (*Group) WorldStep

func (gp *Group) WorldStep(step float32)

WorldStep does a full Step update for all Dynamic nodes, for either physics or scripted mode, based on current velocities.

type Node

type Node interface {
	tree.Node

	// AsNodeBase returns a generic NodeBase for our node -- gives generic
	// access to all the base-level data structures without needing interface methods.
	AsNodeBase() *NodeBase

	// AsBody returns a generic Body interface for our node -- nil if not a Body
	AsBody() Body

	// GroupBBox sets bounding boxes for groups based on groups or bodies.
	// called in a FuncDownMeLast traversal.
	GroupBBox()

	// InitAbs sets current Abs physical state parameters from Initial values
	// which are local, relative to parent -- is passed the parent (nil = top).
	// Body nodes should also set their bounding boxes.
	// Called in a FuncDownMeFirst traversal.
	InitAbs(par *NodeBase)

	// RelToAbs updates current world Abs physical state parameters
	// based on Rel values added to updated Abs values at higher levels.
	// Abs.LinVel is updated from the resulting change from prior position.
	// This is useful for manual updating of relative positions (scripted movement).
	// It is passed the parent (nil = top).
	// Body nodes should also update their bounding boxes.
	// Called in a FuncDownMeFirst traversal.
	RelToAbs(par *NodeBase)

	// Step computes one update of the world Abs physical state parameters,
	// using *current* velocities -- add forces prior to calling.
	// Use this for physics-based state updates.
	// Body nodes should also update their bounding boxes.
	Step(step float32)
}

Node is the common interface for all nodes.

type NodeBase

type NodeBase struct {
	tree.NodeBase

	// Dynamic is whether this node can move. If it is false, then this is a Static node.
	// Any top-level group that is not Dynamic is immediately pruned from further consideration,
	// so top-level groups should be separated into Dynamic and Static nodes at the start.
	Dynamic bool

	// initial position, orientation, velocity in *local* coordinates (relative to parent)
	Initial State `display:"inline"`

	// current relative (local) position, orientation, velocity -- only change these values, as abs values are computed therefrom
	Rel State `display:"inline"`

	// current absolute (world) position, orientation, velocity
	Abs State `set:"-" edit:"-" display:"inline"`

	// bounding box in world coordinates (aggregated for groups)
	BBox BBox `set:"-"`
}

NodeBase is the basic node, which has position, rotation, velocity and computed bounding boxes, etc. There are only three different kinds of Nodes: Group, Body, and Joint

func NewNodeBase

func NewNodeBase(parent ...tree.Node) *NodeBase

NewNodeBase returns a new NodeBase with the given optional parent: NodeBase is the basic node, which has position, rotation, velocity and computed bounding boxes, etc. There are only three different kinds of Nodes: Group, Body, and Joint

func (*NodeBase) AsBody

func (nb *NodeBase) AsBody() Body

func (*NodeBase) AsNodeBase

func (nb *NodeBase) AsNodeBase() *NodeBase

func (*NodeBase) InitAbsBase

func (nb *NodeBase) InitAbsBase(par *NodeBase)

InitAbsBase is the base-level version of InitAbs -- most nodes call this. InitAbs sets current Abs physical state parameters from Initial values which are local, relative to parent -- is passed the parent (nil = top). Body nodes should also set their bounding boxes. Called in a FuncDownMeFirst traversal.

func (*NodeBase) RelToAbsBase

func (nb *NodeBase) RelToAbsBase(par *NodeBase)

RelToAbsBase is the base-level version of RelToAbs -- most nodes call this. note: Group WorldRelToAbs ensures only called on Dynamic nodes. RelToAbs updates current world Abs physical state parameters based on Rel values added to updated Abs values at higher levels. Abs.LinVel is updated from the resulting change from prior position. This is useful for manual updating of relative positions (scripted movement). It is passed the parent (nil = top). Body nodes should also update their bounding boxes. Called in a FuncDownMeFirst traversal.

func (*NodeBase) SetDynamic added in v0.2.0

func (t *NodeBase) SetDynamic(v bool) *NodeBase

SetDynamic sets the [NodeBase.Dynamic]: Dynamic is whether this node can move. If it is false, then this is a Static node. Any top-level group that is not Dynamic is immediately pruned from further consideration, so top-level groups should be separated into Dynamic and Static nodes at the start.

func (*NodeBase) SetInitAngVel

func (nb *NodeBase) SetInitAngVel(vel math32.Vector3) *NodeBase

SetInitAngVel sets the initial angular velocity

func (*NodeBase) SetInitLinVel

func (nb *NodeBase) SetInitLinVel(vel math32.Vector3) *NodeBase

SetInitLinVel sets the initial linear velocity

func (*NodeBase) SetInitPos

func (nb *NodeBase) SetInitPos(pos math32.Vector3) *NodeBase

SetInitPos sets the initial position

func (*NodeBase) SetInitQuat

func (nb *NodeBase) SetInitQuat(quat math32.Quat) *NodeBase

SetInitQuat sets the initial rotation as a Quaternion

func (*NodeBase) SetInitial

func (t *NodeBase) SetInitial(v State) *NodeBase

SetInitial sets the [NodeBase.Initial]: initial position, orientation, velocity in *local* coordinates (relative to parent)

func (*NodeBase) SetRel

func (t *NodeBase) SetRel(v State) *NodeBase

SetRel sets the [NodeBase.Rel]: current relative (local) position, orientation, velocity -- only change these values, as abs values are computed therefrom

func (*NodeBase) StepBase

func (nb *NodeBase) StepBase(step float32)

StepBase is base-level version of Step -- most nodes call this. note: Group WorldRelToAbs ensures only called on Dynamic nodes. Computes one update of the world Abs physical state parameters, using *current* velocities -- add forces prior to calling. Use this for physics-based state updates. Body nodes should also update their bounding boxes.

type Rigid

type Rigid struct {

	// 1/mass -- 0 for no mass
	InvMass float32

	// COR or coefficient of restitution -- how elastic is the collision i.e., final velocity / initial velocity
	Bounce float32 `min:"0" max:"1"`

	// friction coefficient -- how much friction is generated by transverse motion
	Friction float32

	// record of computed force vector from last iteration
	Force math32.Vector3

	// Last calculated rotational inertia matrix in local coords
	RotInertia math32.Matrix3
}

Rigid contains the full specification of a given object's basic physics properties including position, orientation, velocity. These

func (*Rigid) Defaults

func (ps *Rigid) Defaults()

Defaults sets defaults only if current values are nil

type Sphere

type Sphere struct {
	BodyBase

	// radius
	Radius float32
}

Sphere is a spherical body shape.

func NewSphere

func NewSphere(parent ...tree.Node) *Sphere

NewSphere returns a new Sphere with the given optional parent: Sphere is a spherical body shape.

func (*Sphere) InitAbs

func (sp *Sphere) InitAbs(par *NodeBase)

func (*Sphere) RelToAbs

func (sp *Sphere) RelToAbs(par *NodeBase)

func (*Sphere) SetBBox

func (sp *Sphere) SetBBox()

func (*Sphere) SetRadius

func (t *Sphere) SetRadius(v float32) *Sphere

SetRadius sets the [Sphere.Radius]: radius

func (*Sphere) Step

func (sp *Sphere) Step(step float32)

type State

type State struct {

	// position of center of mass of object
	Pos math32.Vector3

	// rotation specified as a Quat
	Quat math32.Quat

	// linear velocity
	LinVel math32.Vector3

	// angular velocity
	AngVel math32.Vector3
}

State contains the basic physical state including position, orientation, velocity. These are only the values that can be either relative or absolute -- other physical state values such as Mass should go in Rigid.

func (*State) Defaults

func (ps *State) Defaults()

Defaults sets defaults only if current values are nil

func (*State) EulerRotation

func (ps *State) EulerRotation() math32.Vector3

EulerRotation returns the current rotation in Euler angles (degrees).

func (*State) EulerRotationRad

func (ps *State) EulerRotationRad() math32.Vector3

EulerRotationRad returns the current rotation in Euler angles (radians).

func (*State) FromRel

func (ps *State) FromRel(rel, par *State)

FromRel sets state from relative values compared to a parent state

func (*State) Move

func (ps *State) Move(delta math32.Vector3)

Move moves (translates) Pos by given amount, and sets the LinVel to the given delta -- this can be useful for Scripted motion to track movement.

func (*State) MoveOnAxis

func (ps *State) MoveOnAxis(x, y, z, dist float32)

MoveOnAxis moves (translates) the specified distance on the specified local axis, relative to the current rotation orientation. The axis is normalized prior to aplying the distance factor. Sets the LinVel to motion vector.

func (*State) MoveOnAxisAbs

func (ps *State) MoveOnAxisAbs(x, y, z, dist float32)

MoveOnAxisAbs moves (translates) the specified distance on the specified local axis, in absolute X,Y,Z coordinates (does not apply the Quat rotation factor. The axis is normalized prior to aplying the distance factor. Sets the LinVel to motion vector.

func (*State) RotateEuler

func (ps *State) RotateEuler(x, y, z float32)

RotateEuler rotates by given Euler angles (in degrees) relative to existing rotation.

func (*State) RotateEulerRad

func (ps *State) RotateEulerRad(x, y, z, angle float32)

RotateEulerRad rotates by given Euler angles (in radians) relative to existing rotation.

func (*State) RotateOnAxis

func (ps *State) RotateOnAxis(x, y, z, angle float32)

RotateOnAxis rotates around the specified local axis the specified angle in degrees.

func (*State) RotateOnAxisRad

func (ps *State) RotateOnAxisRad(x, y, z, angle float32)

RotateOnAxisRad rotates around the specified local axis the specified angle in radians.

func (*State) SetAxisRotation

func (ps *State) SetAxisRotation(x, y, z, angle float32)

SetAxisRotation sets rotation from local axis and angle in degrees.

func (*State) SetAxisRotationRad

func (ps *State) SetAxisRotationRad(x, y, z, angle float32)

SetAxisRotationRad sets rotation from local axis and angle in radians.

func (*State) SetEulerRotation

func (ps *State) SetEulerRotation(x, y, z float32)

SetEulerRotation sets the rotation in Euler angles (degrees).

func (*State) SetEulerRotationRad

func (ps *State) SetEulerRotationRad(x, y, z float32)

SetEulerRotationRad sets the rotation in Euler angles (radians).

func (*State) StepByAngVel

func (ps *State) StepByAngVel(step float32)

StepByAngVel steps the Quat rotation from angular velocity

func (*State) StepByLinVel

func (ps *State) StepByLinVel(step float32)

StepByLinVel steps the Pos from the linear velocity

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL