Skip to content
This repository has been archived by the owner on Dec 15, 2019. It is now read-only.

Behaviors

Jasper edited this page Apr 22, 2014 · 13 revisions

Behaviors follow the Factory Pattern. Please read about the factory pattern to learn about creation, declaration, and extending behaviors.

See also: API Reference on Behaviors

Behaviors (or Behaviours) are the "how" of a physics simulation. They are rules applied to the world that act on bodies during every timestep to simulate specific physical laws. A world without any behaviors will act as an infinite, frictionless vacuum. (No behaviors are included in the core library, they are available as extensions)

The most familiar example of a behavior is adding "gravity" to a simulation. What is most often meant by "gravity" is a constant acceleration in the downward (positive "y") direction. Because of the frequent need for this, a "constant-acceleration" behavior is available as an extension.

Example:

// add some gravity
var gravity = Physics.behavior('constant-acceleration', {
    acc: { x : 0, y: 0.0004 } // this is the default
});
world.add( gravity );
// later... flip the world upside down!
gravity.setAcceleration({ x: 0, y: -0.0004 });

Some behaviors act as "detectors", which don't modify bodies directly. Instead they detect specific events and announce them to the world's pubsub system so other behaviors can take appropriate actions. One example of this is collision detection and response. There are separate behaviors for collision detection, collision response, and even so-called "sweep and prune" optimization algorithms.

Applying behaviors to a sub-set of bodies

By default, behaviors will apply to every body added to the world.

Most behaviors have a .applyTo() method that can be used to control which bodies the behavior is applied to. The method accepts an array of bodies.

Example:

var boxes = [];
// add bodies to the boxes array...

// only apply gravity to the bodies in the boxes array
var accel = Physics.behavior('constant-acceleration')
    .applyTo( boxes );

world.add( accel );

Hint: Queries can help collect sub-sets of bodies easily!

Creating a custom Behavior

The most basic form of a behavior simply involves creating a .behave() method. If a behavior includes a .behave() method, it will automatically get subscribed to the world's integrate:positions event. The integrate:positions event is the last stage of integration, and a good time to apply accelerations to bodies.

The .behave() method is speed-critical, and therefore, usage of Scratchpads is strongly recommended if creating temporary objects.

The .behave() method will be passed an event object which includes: .bodies array containing the world's bodies, and .dt a number representing the timestep size. The constant-acceleration behavior is a good example of this basic implementation:

(full source)

// ...
// Apply an acceleration to each body in the world
behave: function( data ){

    var bodies = this.getTargets();

    for ( var i = 0, l = bodies.length; i < l; ++i ){
        
        bodies[ i ].accelerate( this._acc );
    }
}
// ...

In more complex situations, it may be necessary to subscribe to a different part of the integration phase, or subscribe multiple callbacks. To do this, it is necessary to override the methods .connect() and .disconnect() where subscribing/unsubscribing can be completely controlled.

The body-collision-detection behavior is a good example of this. The subscription depends on configuration options:

(full source)

// ...
// connect to a world
connect: function( world ){

    if ( this.options.checkAll ){

        world.subscribe( 'integrate:velocities', this.checkAll, this );

    } else {

        world.subscribe( 'collisions:candidates', this.check, this );
    }
},
// disconnect from a world (cleanup)
disconnect: function( world ){

    if ( this.options.checkAll ){

        world.unsubscribe( 'integrate:velocities', this.checkAll );

    } else {

        world.unsubscribe( 'collisions:candidates', this.check );
    }
}
// ...

Constant Acceleration

Use the constant-acceleration behavior to add a constant acceleration to all bodies in the world. Accepts the following configuration parameters (and defaults):

// the acceleration vector
acc: { x : 0, y: 0.0004 }

Newtonian acceleration

Use the newtonian behavior to create an inverse square attraction between all bodies in the world. Accepts the following configuration parameters (and defaults):

// the strength of the attraction (negative for repulsion)
strength: 1

Rigid constraints

Use the rigid-constraint-manager behavior to manage verlet distance constraints between bodies in the world.

NB: requires a verlet compatible integrator to be used by the world.

Accepts the following configuration parameters (and defaults):

// set a default target length
targetLength: 20

Initialize:

var rcm = Physics.behavior('rigid-constraint-manager');
world.add( rcm );

To add a constraint between two bodies:

var targetLength = 20;
// store the constraint data for later
var constraint = rcm.constrain( bodyA, bodyB, targetLength );

To remove a constraint:

rcm.remove( constraint );

// or to remove all constraints...
rcm.drop();

Edge collision detection

Use the edge-collision-detection to detect collisions of bodies with the edges of a bounding box (AABB).

NB: this is only the detection of collisions with edges. To have a collision response, use it with the body-collision-response behavior.

For more about collisions, see the Collision documentation.

Accepts the following configuration parameters (and defaults):

// the AABB for the edges
aabb: null,
// the restitution of the edges (bounciness)
restitution: 0.99,
// the coefficient of friction of the edges
cof: 1.0

Body Collision Detection

Use the body-collision-detection behavior to detect collision between bodies.

NB: this is only the detection of collisions between bodies. To have a collision response, use it with the body-collision-response behavior.

For more about collisions, see the Collision documentation.

Accepts the following configuration parameters (and defaults):

// force check every pair of bodies in the world
checkAll: false

Collision detection is computationally expensive, this behavior is best used as a "narrow phase" collision detection, and paired with the sweep-prune behavior for a "broad phase" collision detection.

Sweep and Prune Broad Phase Collision Detection

Use the sweep-prune behavior for an optimized broad phase collision detection between bodies.

NB: this is meant to be used in tandem with body-collision-detection, and body-impulse-response (if collision response is desired).

For more about collisions, see the Collision documentation.

No configuration.

Body Impulse Response

Use the body-impulse-response for an impulse response between detected colliding bodies.

NB: this is meant to be used in tandem with body-collision-detection, and optionally sweep-prune.

For more about collisions, see the Collision documentation.

No configuration.

Clone this wiki locally