Skip to content
William Mcmurray edited this page Sep 17, 2018 · 4 revisions

Downloading

You can download Goblin Physics via GitHub, npm, or bower.

Environment

The rest of this guide will assume one of the following setups.

In-Browser

<!DOCTYPE html>
<html>
    <head>
        <script type="text/javascript" src="goblin.min.js"></script>
        <script type="text/javascript">
        /* Rest of script goes here */
        </script>
    </head>
</html>

Node.js

var Goblin = require( 'goblinphysics' );
/* Rest of script goes here */

Creating the world

Goblin simulates physics inside of a World. This is an object which holds all of the active physics bodies, enforces constraints, and provides an interface for ray casting. To create a new World you must specify a Broadphase, Narrowphase, and Solver. Currently there is only one choice for each of these.

var world = new Goblin.World( new Goblin.SAPBroadphase(), new Goblin.NarrowPhase(), new Goblin.IterativeSolver() );

Adding a rigid body

(see Shapes) Let's add a box to the scene. Rigid bodies are created by passing in the desired shape and a mass.

var box_shape = new Goblin.BoxShape( 0.5, 0.5, 0.5 ), // dimensions are half width, half height, and half depth, or a box 1x1x1
    mass = 5,
    box = new Goblin.RigidBody( box_shape, mass );
world.addRigidBody( box );

Stepping the simulation

Goblin performs a discrete time stepping over an interval you specify. For best results it is recommended that the time interval remains constant. A common frame rate target is 60 frames per second so let's choose that as our time step.

world.step( 1 / 60 );

Getting output

Because Goblin doesn't have any built-in method to visualize the objects in a World, we can instead create an event listener that is called after every step and use that to display the box's position. The entire script so far looks like

var world = new Goblin.World( new Goblin.SAPBroadphase(), new Goblin.NarrowPhase(), new Goblin.IterativeSolver() );

var box_shape = new Goblin.BoxShape( 0.5, 0.5, 0.5 ), // dimensions are half width, half height, and half depth, or a box 1x1x1
    mass = 5,
    box = new Goblin.RigidBody( box_shape, mass );
world.addRigidBody( box );

world.addListener(
    'stepEnd',
    function() {
        console.log( box.position );
    }
);

world.step( 1 / 60 ); // `stepEnd` listener outputs { x: 0, y: -0.0027222222222222222, z: 0 }

Running at full speed

The above code only steps the simulation forward one time, so stepEnd is only fired once and only one log message is generated. It's probable that you want the simulation to continue running, and can be done by repeatedly calling world.step either by window.requestAnimationFrame, setInterval, or from some existing game loop in your code. If you were to modify the above code to run at 60fps you will flood your console with 60 messages every second - far too quick to read it. Let's apply two changes then: use setInterval to consistently step the simulation and also rate-limit the console logs.

world.addListener(
    'stepEnd',
    function( ticks ) {
        // `ticks` is automatically passed in from the `World` object and is how many steps the simulation has run
        if ( ticks % 60 === 0 ) { // we're going to run this at 60fps so log after every 60 ticks
            console.log( box.position );
        }
    }
);

setInterval(
    function() {
        world.step( 1 / 60 );
    },
    1000 / 60
);

/*
Output should look something like
{ x: 0, y: -4.981666666666662, z: 0 }
{ x: 0, y: -19.763333333333346, z: 0 }
{ x: 0, y: -44.34500000000007, z: 0 }
{ x: 0, y: -78.72666666666682, z: 0 }
{ x: 0, y: -122.90833333333362, z: 0 }
{ x: 0, y: -176.89000000000044, z: 0 }
{ x: 0, y: -240.67166666666728, z: 0 }
{ x: 0, y: -314.25333333333384, z: 0 }
{ x: 0, y: -397.635, z: 0 }
{ x: 0, y: -490.81666666666575, z: 0 }
*/

Static objects

A single falling box doesn't demonstrate much; why not add another one that is fixed in space and doesn't move. A static body is created in the same manner but with its mass set to Infinity. note if you are accustomed to using a mass of 0 for static objects you may continue to do so in Goblin, but if you access static_body.mass it will return Infinity instead of 0

var static_box = new Goblin.RigidBody( box_shape, Infinity );
static_box.position.set( 0, -5, 0 ); // Set the static box's position 5 units down
world.addRigidBody( static_box );

/*
New output will look similar to the following as `box` lands and rests upon `static_box`
{ x: 0.007924498538291701,
  y: -4.052558665792757,
  z: 0.008497660189857396 }
{ x: 0.027225084996458277,
  y: -3.9879167297290534,
  z: 0.03142705949956938 }
{ x: 0.025493448656967628,
  y: -3.9711158765224117,
  z: 0.0498384488356314 }
{ x: 0.019870361507126195,
  y: -3.964066676214855,
  z: 0.055374699445868696 }
*/

Next steps

Congratulations on getting a basic world setup and running. You probably don't find the console output too exciting and want to see what is happening. Continue to Integrating with Three.js

Clone this wiki locally