Let’s dive into Famo.us physics by exploring the two most fundamental concepts: particles and forces.
In this section, we’ll cover how to …
If you’ve already built an application using Famo.us, it’s likely you’ve encountered the Scrollview
module, which lays out a collection of renderables that can be scrolled through via mouse or touch actions. But did you know that Scrollview
uses the principles of physics to work its magic? Let’s start with a simple example that shows how:
// @famous-block
// @famous-block-option preset famous-0.3.0-globals
// @famous-block-option preset famous-0.3.0-globals
var Engine = famous.core.Engine;
var Surface = famous.core.Surface;
var Scrollview = famous.views.Scrollview;
var mainContext = Engine.createContext();
var scrollview = new Scrollview({
drag: 0.0001,
friction: 0.005,
edgeDamp: 1,
edgePeriod: 300,
speedLimit: 5
});
var surfaces = [];
scrollview.sequenceFrom(surfaces);
for (var i = 0, temp; i < 25; i++) {
temp = new Surface({
size: [undefined, 50],
properties: {
backgroundColor: "hsl(" + (i * 360 / 40) + ", 100%, 50%)",
lineHeight: "200px",
textAlign: "center"
}
});
temp.pipe(scrollview);
surfaces.push(temp);
}
mainContext.add(scrollview);
Look closely at the scrollview options. As it turns out, drag
, friction
, edgeDamp
, edgePeriod
, and speedLimit
are all physics-based constraints that control the exact behavior of the scrollview instance. By adjusting those values, the module behaves in subtly different ways:
Open your browser’s developer tools in device-emulation mode, and try tinkering with these values. Notice how a very low edgeDamp
— say 0.1
— gives us a springy effect when the scrollview reaches the top or bottom edge. And notice how much harder the collection is to scroll through when we set drag
to a higher value, say 0.001
.
We’ve learned that Scrollview
uses physics, but how exactly? Let’s quickly explore a few of Scrollview
’s internals to find out. (Then we’ll get to playing around with the physics modules directly.)
Under the hood, Scrollview
makes use of a special type of Famo.us object called a particle, attached to multiple physics forces, in order to produce its animation. When you begin scrolling through a scrollview’s collection, that particle is assigned a velocity calculated from differences in sampled cursor position. That velocity is modulated by the forces that have been attached to the particle. As the particle’s position changes, so does the scrollview’s current position.
The scrollview particle is affected by three forces in total:
With this new understanding in mind, take a look again at the example above. The scrollview constructor options, it turns out, get handed directly to these physics objects, which take care of the low-level calculations. The Scrollview reads the current state from the physics system, and updates the position of its renderables accordingly. We’ll make use of a similar technique as we learn to use the Particle
module directly.
What is a “particle” exactly? Conceptually, a particle is just a point in space which may have an accompanying velocity and mass. In Famo.us terms, Particle
is simply a module that you can load into your Famo.us application:
var Particle = famous.core.Particle;
var particle = new Particle({
position: [0, 0, 0]
});
Particles themselves are not visible. They are just representations of position, velocity, and mass, which can be used to calculate how things should move around on the screen.
Let’s create a quick demo that will make this concept more tangible.
Let’s build a simple Famo.us app that makes use of a particle. We’ll create a “planet” that slowly moves through space. To represent our planet on the screen, we’ll use a simple Surface instance. (Our planet will be a bit strange, being square-shaped, but you’ll get the idea.)
// @famous-block
// @famous-block-option preset famous-0.3.0-globals
// @famous-block-group particle1
var Engine = famous.core.Engine
var Surface = famous.core.Surface
var Modifier = famous.core.Modifier
var PhysicsEngine = famous.physics.PhysicsEngine
var Particle = famous.physics.bodies.Particle
var context = Engine.createContext();
var physics = new PhysicsEngine();
var planetSurface = new Surface({
properties: {
backgroundColor: 'blue'
}
});
var planetParticle = new Particle({
position: [0, 0, 0]
});
physics.addBody(planetParticle);
var planetModifier = new Modifier({
size: [100, 100],
align: [0.5, 0.5],
origin: [0.5, 0.5],
transform: function() {
return planetParticle.getTransform();
}
});
planetParticle.setVelocity([0.1, 0.1, 0]);
context.add(planetModifier).add(planetSurface);
// @famous-block
// @famous-block-option preset famous-0.3.0-globals
// @famous-block-group particle1
// @famous-block-filename main.html
Refresh this example to see the particle.
To use Famo.us physics modules, we need to include the Famo.us physics engine, which is responsible for orchestrating particles and forces. Then, we take the following steps:
planetSurface
.planetParticle
, which will represent the planet’s position in space.x
, y
, and z
).When you run this code, you should see the square, blue planet slowly move from the center to the right side of the screen.
Now let’s make things a bit more interesting by incorporating forces. Forces are similar to particles: They aren’t visible, but they can affect the position of particles, which, as we’ve seen, can in turn assign a position to renderables. Famo.us comes with a suite of several forces that you can plug right into your application:
Drag
, which can dampen a particle’s velocity over timeRepulsion
, which can influence particles to move away from specified points in spaceSpring
, which can act as an elastic tether that connects one particle to anotherUse the force! Let’s expand slightly on the previous example by adding a Drag force to the planet particle in order to decelerate it over time:
// @famous-block
// @famous-block-option preset famous-0.3.0-globals
// @famous-block-group force1
var Engine = famous.core.Engine
var Surface = famous.core.Surface
var Modifier = famous.core.Modifier
var PhysicsEngine = famous.physics.PhysicsEngine
var Particle = famous.physics.bodies.Particle
var Drag = famous.physics.forces.Drag;
var context = Engine.createContext();
var physics = new PhysicsEngine();
var planetSurface = new Surface({
properties: {
backgroundColor: 'blue'
}
});
var planetParticle = new Particle({
position: [0, 0, 0]
});
physics.addBody(planetParticle);
var planetModifier = new Modifier({
size: [100, 100],
align: [0.5, 0.5],
origin: [0.5, 0.5],
transform: function() {
return planetParticle.getTransform();
}
});
var dragForce = new Drag({
strength: 0.001
});
physics.attach(dragForce, planetParticle);
planetParticle.setVelocity([0.1, 0, 0]);
context.add(planetModifier).add(planetSurface);
// @famous-block
// @famous-block-option preset famous-0.3.0-globals
// @famous-block-group force1
// @famous-block-filename main.html
Refresh this example to see the animation.
Again, we need to tell the physics engine about the force in order for it to apply its effects to the particle. But unlike particles, where we used the .addBody()
method to register it, with forces we need to use the .attach()
method. .attach()
takes a force as its first argument, and a particle to which to apply that force as the second argument.
Now, when we run the example, the particle is slowed down by the drag force until it completely stops. The “planet” comes to a standstill before reaching the edge of the screen.
The Famo.us physics engine is capable of managing the actions of many particles and forces at once. In fact, we can connect multiple particles to one another using forces. Let’s finish up by creating a gravitational effect that connects two particles: a square satellite to revolve around our square planet. (We at Famo.us like to think of the following demo as the “Hello world!” of using the physics engine.)
// @famous-block
// @famous-block-option preset famous-0.3.0-globals
// @famous-block-option preset famous-0.3.0-globals
var Engine = famous.core.Engine
var Surface = famous.core.Surface
var Modifier = famous.core.Modifier
var PhysicsEngine = famous.physics.PhysicsEngine
var Particle = famous.physics.bodies.Particle
var RepulsionForce = famous.physics.forces.Repulsion
var context = Engine.createContext();
var physics = new PhysicsEngine();
var planetSurface = new Surface({
properties: {
backgroundColor: 'blue'
}
});
var planetParticle = new Particle();
physics.addBody(planetParticle);
var planetModifier = new Modifier({
size: [100, 100],
align: [0.5, 0.5],
origin: [0.5, 0.5],
transform: function() {
return planetParticle.getTransform();
}
});
var satelliteSurface = new Surface({
properties: {
backgroundColor: 'gray'
}
});
var satelliteParticle = new Particle({
position: [0, -100, 0]
});
physics.addBody(satelliteParticle);
var satelliteModifier = new Modifier({
size: [25, 25],
align: [0.5, 0.5],
origin: [0.5, 0.5],
transform: function() {
return satelliteParticle.getTransform();
}
});
var gravity = new RepulsionForce({
strength: -2
});
physics.attach(gravity, satelliteParticle, planetParticle);
satelliteParticle.setVelocity([0.1, 0, 0]);
context.add(planetModifier).add(planetSurface);
context.add(satelliteModifier).add(satelliteSurface);
First, we need add a brand new set of objects to represent our satellite: a satelliteSurface
to display, a satelliteParticle
to communicate with the physics engine, and satelliteModifier
to connect the two. (Make a mental note about this pattern: When using physics in Famo.us, you’ll find yourself hooking up Particle
-Modifier
-Surface
links again and again. This composition of objects might make a good candidate for creating your own wrapper object.)
We also introduce a new type of force in this expanded example: Repulsion. Repulsion can influence a physics particle to move or stay away from a particlar point in space, with a given strength
. In this case, however, we’re going to give that Repulsion force a negative value for strength
so that it behaves as an “attraction” – namely gravity. By default, the Repulsion module uses the formula for gravity to give its effects, so you can use it right out of the box.
One other modification is needed to set up an interrelation between the satellite and the planet: We pass a third argument to the physics engine’s .attach()
method, which is the anchor. This tells the physics engine that we want to anchor the satelliteParticle
to the planetParticle
’s position using the gravity
repulsion force.
When we set the satellite into motion with a constant velocity, the attractive force of gravity keeps it locked into orbit.
Copyright © 2013-2015 Famous Industries, Inc.