Liquidfun links

This commit is contained in:
viktorljung
2015-09-09 18:04:17 +01:00
parent 8833377855
commit 67f7a30ca6
184 changed files with 52115 additions and 2 deletions
@@ -0,0 +1,274 @@
# Introduction
<img src="liquidfun-logo-square-small.png" alt="LiquidFun logo" style="float:right;"/>
[About](#about)<br/>
[Prerequisites](#pre)<br/>
[About this manual](#atm)<br/>
[Feedback and reporting bugs](#frb)<br/>
[Core concepts](#cc)<br/>
[Modules](#mo)<br/>
[Units](#un)<br/>
[Factories and definitions](#fd)<br/>
<a name="About"></a><br/>
## About
LiquidFun is based on Erin Catto's [Box2D library](http://www.box2d.org), which
provides 2D, rigid-body simulation in games. LiquidFun extends Box2D to provide
[particle physics and fluid dynamics](md__chapter11__particles.html).
Programmers can use LiquidFun in their games to make objects move in realistic
ways and make the game world more interactive. From the game engine's point of
view, a physics engine is just a system for procedural animation.
LiquidFun is written in portable C++. Most of the types defined in the engine
begin with the b2 prefix. Hopefully this is sufficient to avoid name clashing
with your game engine.
<a name="pre"></a><br/>
## Prerequisites
In this manual I'll assume you are familiar with basic physics concepts, such
as mass, force, torque, and impulses. If not, please first consult Google
search and Wikipedia.
LiquidFun is based on the Box2D library, which was created as part of a
physics tutorial at the Game Developer Conference. You can get these tutorials
from the download section of Box2D.org.
Since LiquidFun is written in C++, you are expected to be experienced in C++
programming. LiquidFun should not be your first C++ programming project! You
should be comfortable with compiling, linking, and debugging.
Caution
LiquidFun should not be your first C++ project. Please learn C++
programming, compiling, linking, and debugging before working with LiquidFun.
There are many resources for this on the net.
<a name="atm"></a><br/>
## About this manual
This manual covers the majority of the LiquidFun API. However, not every
aspect is covered. You are encouraged to look at the testbed included with
LiquidFun to learn more. Also, the LiquidFun code base has comments formatted
for Doxygen, so it is easy to create a hyper-linked API document.
This manual is only updated with new releases. The version in source control
is likely to be out of date.
<a name="frb"></a><br/>
## Feedback and Reporting Bugs
If you have a question or feedback about LiquidFun, please leave a comment in
the forum. This is also a great place for community discussion.
LiquidFun issues are tracked using a Google code project. This is a great way
to track issues and ensures that your issue will not be lost in the depths of
the forums.
Please file bugs and feature requests here:
[http://github.com/google/liquidfun/issues](http://github.com/google/liquidfun/issues)
You can help to ensure your issue gets fixed if you provide sufficient
detail. A testbed example that reproduces the problem is ideal. You can read
about the testbed later in this document.
<a name="cc"></a><br/>
## Core Concepts
LiquidFun works with several fundamental concepts and objects. We briefly
define these objects here and more details are given later in this
document.<br/>
<br/>
### shape
A shape is 2D geometrical object, such as a circle or polygon.<br/>
### rigid body
A chunk of matter that is so strong that the distance between any two bits of
matter on the chunk is constant. They are hard like a diamond. In the
following discussion we use body interchangeably with rigid body.<br/>
### fixture
A fixture binds a shape to a body and adds material properties such as
density, friction, and restitution. A fixture puts a shape into the collision
system (broad-phase) so that it can collide with other shapes.<br/>
### constraint
A constraint is a physical connection that removes degrees of freedom from
bodies. A 2D body has 3 degrees of freedom (two translation coordinates and
one rotation coordinate). If we take a body and pin it to the wall (like a
pendulum) we have constrained the body to the wall. At this point the body can
only rotate about the pin, so the constraint has removed 2 degrees of
freedom.<br/>
### contact constraint
A special constraint designed to prevent penetration of rigid bodies and to
simulate friction and restitution. You do not create contact constraints; they
are created automatically by LiquidFun.<br/>
### joint
This is a constraint used to hold two or more bodies together. LiquidFun
supports several joint types: revolute, prismatic, distance, and more. Some
joints may have limits and motors.<br/>
### joint limit
A joint limit restricts the range of motion of a joint. For example, the human
elbow only allows a certain range of angles.<br/>
### joint motor
A joint motor drives the motion of the connected bodies according to the
joint's degrees of freedom. For example, you can use a motor to drive the
rotation of an elbow.<br/>
### world
A physics world is a collection of bodies, fixtures, and constraints that
interact together. LiquidFun supports the creation of multiple worlds, but
this is usually not necessary or desirable.<br/>
### solver
The physics world has a solver that is used to advance time and to resolve
contact and joint constraints. The LiquidFun solver is a high performance
iterative solver that operates in order N time, where N is the number of
constraints.<br/>
### continuous collision
The solver advances bodies in time using discrete time steps. Without
intervention this can lead to tunneling.<br/>
<br/>
<img align="center" src="image_0.png" alt="Tunneling" height="293"
width="275"><br/>
LiquidFun contains specialized algorithms to deal with tunneling. First, the
collision algorithms can interpolate the motion of two bodies to find the
first time of impact (TOI). Second, there is a sub-stepping solver that moves
bodies to their first time of impact and then resolves the collision.
<a name="mo"></a><br/>
## Modules
LiquidFun is composed of three modules: Common, Collision, and Dynamics. The
Common module has code for allocation, math, and settings. The Collision
module defines shapes, a broad-phase, and collision functions/queries. Finally
the Dynamics module provides the simulation world, bodies, fixtures, and
joints.<br/>
<br/>
<img align="center" src="image_1.png" alt="Modules" height="229" width="217">
<a name="un"></a><br/>
## Units
LiquidFun works with floating point numbers and tolerances have to be used to
make LiquidFun perform well. These tolerances have been tuned to work well
with meters-kilogram-second (MKS) units. In particular, LiquidFun has been
tuned to work well with moving shapes between 0.1 and 10 meters. So this means
objects between soup cans and buses in size should work well. Static shapes
may be up to 50 meters long without trouble.
Being a 2D physics engine, it is tempting to use pixels as your units.
Unfortunately this will lead to a poor simulation and possibly weird behavior.
An object of length 200 pixels would be seen by LiquidFun as the size of a 45
story building.
Caution
LiquidFun is tuned for MKS units. Keep the size of moving objects
roughly between 0.1 and 10 meters. You'll need to use some scaling system when
you render your environment and actors. The LiquidFun testbed does this by
using an OpenGL viewport transform. DO NOT USE PIXELS.
It is best to think of LiquidFun bodies as moving billboards upon which you
attach your artwork. The billboard may move in a unit system of meters, but
you can convert that to pixel coordinates with a simple scaling factor. You
can then use those pixel coordinates to place your sprites, etc. You can also
account for flipped coordinate axes.
LiquidFun uses radians for angles. The body rotation is stored in radians and
may grow unbounded. Consider normalizing the angle of your bodies if the
magnitude of the angle becomes too large (use b2Body::SetAngle).
Caution
LiquidFun uses radians, not degrees.
<a name="fd"></a><br/>
## Factories and Definitions
Fast memory management plays a central role in the design of the LiquidFun
API. So when you create a b2Body or a b2Joint, you need to call the factory
functions on b2World. You should never try to allocate these types in another
manner.
There are creation functions:
&nbsp;&nbsp;&nbsp;`b2Body* b2World::CreateBody(const b2BodyDef* def)`<br/>
&nbsp;&nbsp;&nbsp;`b2Joint* b2World::CreateJoint(const b2JointDef* def)`<br/>
&nbsp;&nbsp;&nbsp;`And there are corresponding destruction functions:`<br/>
&nbsp;&nbsp;&nbsp;`void b2World::DestroyBody(b2Body* body)`<br/>
&nbsp;&nbsp;&nbsp;`void b2World::DestroyJoint(b2Joint* joint)`<br/>
When you create a body or joint, you need to provide a definition. These
definitions contain all the information needed to build the body or joint. By
using this approach we can prevent construction errors, keep the number of
function parameters small, provide sensible defaults, and reduce the number of
accessors.
Since fixtures (shapes) must be parented to a body, they are created and
destroyed using a factory method on b2Body:
&nbsp;&nbsp;&nbsp;`b2Fixture* b2Body::CreateFixture(const b2FixtureDef*
def)`<br/>
&nbsp;&nbsp;&nbsp;`void b2Body::DestroyFixture(b2Fixture* fixture)`<br/>
There is also shortcut to create a fixture directly from the shape and density.
&nbsp;&nbsp;&nbsp;`b2Fixture* b2Body::CreateFixture(const b2Shape* shape,
float32 density)`<br/>
Factories do not retain references to the definitions. So you can create
definitions on the stack and keep them in temporary resources.
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
[ ][Chapter02]
[ ][Chapter03]
[ ][Chapter04]
[ ][Chapter05]
[ ][Chapter06]
[ ][Chapter07]
[ ][Chapter08]
[ ][Chapter09]
[ ][Chapter10]
[ ][Chapter11]
[ ][Chapter12]
[ ][Chapter13]
[ ][Chapter14]
[ ][Chapter15]
[Chapter02]: md__chapter02__hello__box2_d.html
[Chapter03]: md__chapter03__common.html
[Chapter04]: md__chapter04__collision__module.html
[Chapter05]: md__chapter05__dynamics__module.html
[Chapter06]: md__chapter06__bodies.html
[Chapter07]: md__chapter07__fixtures.html
[Chapter08]: md__chapter08__joints.html
[Chapter09]: md__chapter09__contacts.html
[Chapter10]: md__chapter10__world.html
[Chapter11]: md__chapter11__particles.html
[Chapter12]: md__chapter12__loose__ends.html
[Chapter13]: md__chapter13__debug__drawing.html
[Chapter14]: md__chapter14__limitations.html
[Chapter15]: md__chapter15__references.html
@@ -0,0 +1,290 @@
# Hello LiquidFun
[About](#about)<br/>
[Creating a world](#cr)<br/>
[Creating a ground box](#cgb)<br/>
[Creating a dynamic body](#cdb)<br/>
[Simulating the World (of LiquidFun)](#stw)<br>
[Cleanup](#cl)<br>
[The testbed](#tb)<br>
<br/>
<a name="about">
## About
In the distribution of LiquidFun is a Hello World project. The program creates
a large ground box and a small dynamic box. This code does not contain any
graphics. All you will see is text output in the console of the box's position
over time.
This is a good example of how to get up and running with LiquidFun.
<a name="cr"></a><br/>
## Creating a World
Every LiquidFun program begins with the creation of a b2World object. b2World
is the physics hub that manages memory, objects, and simulation. You can
allocate the physics world on the stack, heap, or data section.
It is easy to create a LiquidFun world. First, we define the gravity vector.
b2Vec2 gravity(0.0f, -10.0f);
Now we create the world object. Note that we are creating the world on the
stack, so the world must remain in scope.
b2World world(gravity);
So now we have our physics world, let's start adding some stuff to it.
<a name="cgb"></a><br/>
## Creating a Ground Box
Bodies are built using the following steps:
1. Define a body with position, damping, etc.
2. Use the world object to create the body.
3. Define fixtures with a shape, friction, density, etc.
4. Create fixtures on the body.
For step 1 we create the ground body. For this we need a body definition. With
the body definition we specify the initial position of the ground body.
&nbsp;&nbsp;&nbsp;`b2BodyDef groundBodyDef;`<br/>
&nbsp;&nbsp;&nbsp;`groundBodyDef.position.Set(0.0f, -10.0f);`<br/>
For step 2 the body definition is passed to the world object to create the
ground body. The world object does not keep a reference to the body
definition. Bodies are static by default. Static bodies don't collide with
other static bodies and are immovable.
&nbsp;&nbsp;&nbsp;`b2Body* groundBody = world.CreateBody(&groundBodyDef);`<br/>
For step 3 we create a ground polygon. We use the SetAsBox shortcut to form
the ground polygon into a box shape, with the box centered on the origin of
the parent body.
&nbsp;&nbsp;&nbsp;`b2PolygonShape groundBox;`<br/>
&nbsp;&nbsp;&nbsp;`groundBox.SetAsBox(50.0f, 10.0f);`<br/>
The SetAsBox function takes the **half**-**width** and **half**-**height**
(extents). So in this case the ground box is 100 units wide (x-axis) and 20
units tall (y-axis). LiquidFun is tuned for meters, kilograms, and seconds. So
you can consider the extents to be in meters. LiquidFun generally works best
when objects are the size of typical real world objects. For example, a barrel
is about 1 meter tall. Due to the limitations of floating point arithmetic,
using LiquidFun to model the movement of glaciers or dust particles is not a
good idea.
We finish the ground body in step 4 by creating the shape fixture. For this
step we have a shortcut. We do not have a need to alter the default fixture
material properties, so we can pass the shape directly to the body without
creating a fixture definition. Later we will see how to use a fixture
definition for customized material properties. The second parameter is the
shape density in kilograms per meter squared. A static body has zero mass by
definition, so the density is not used in this case.
&nbsp;&nbsp;&nbsp;`groundBody->CreateFixture(&groundBox, 0.0f);`
LiquidFun does not keep a reference to the shape. It clones the data into a
new b2Shape object.
Note that every fixture must have a parent body, even fixtures that are
static. However, you can attach all static fixtures to a single static body.
When you attach a shape to a body using a fixture, the shapes coordinates
become local to the body. So when the body moves, so does the shape. A
fixtures world transform is inherited from the parent body. A fixture does
not have a transform independent of the body. So we dont move a shape
around on the body. Moving or modifying a shape that is on a body is not
supported. The reason is simple: a body with morphing shapes is not a rigid
body, but LiquidFun is a rigid body engine. Many of the assumptions made in
LiquidFun are based on the rigid body model. If this is violated many things
will break
<a name="cdb"></a><br/>
## Creating a Dynamic Body
So now we have a ground body. We can use the same technique to create a
dynamic body. The main difference, besides dimensions, is that we must
establish the dynamic body's mass properties.
First we create the body using CreateBody. By default bodies are static, so we
should set the b2BodyType at construction time to make the body dynamic.
&nbsp;&nbsp;&nbsp;`b2BodyDef bodyDef;`<br/>
&nbsp;&nbsp;&nbsp;`bodyDef.type = b2_dynamicBody;`<br/>
&nbsp;&nbsp;&nbsp;`bodyDef.position.Set(0.0f, 4.0f);`<br/>
&nbsp;&nbsp;&nbsp;`b2Body* body = world.CreateBody(&bodyDef);`<br/>
Caution
You must set the body type to b2_dynamicBody if you want the body to move in response to forces.
Next we create and attach a polygon shape using a fixture definition. First we
create a box shape:
&nbsp;&nbsp;&nbsp;`b2PolygonShape dynamicBox;`<br/>
&nbsp;&nbsp;&nbsp;`dynamicBox.SetAsBox(1.0f, 1.0f);`<br/>
Next we create a fixture definition using the box. Notice that we set density
to 1. The default density is zero. Also, the friction on the shape is set to
0.3.
&nbsp;&nbsp;&nbsp;`b2FixtureDef fixtureDef;`<br/>
&nbsp;&nbsp;&nbsp;`fixtureDef.shape = &dynamicBox;`<br/>
&nbsp;&nbsp;&nbsp;`fixtureDef.density = 1.0f;`<br/>
&nbsp;&nbsp;&nbsp;`fixtureDef.friction = 0.3f;`<br/>
Caution
A dynamic body should have at least one fixture with a non-zero density. Otherwise you will get strange behavior.
Using the fixture definition we can now create the fixture. This automatically
updates the mass of the body. You can add as many fixtures as you like to a
body. Each one contributes to the total mass.
&nbsp;&nbsp;&nbsp;`body->CreateFixture(&fixtureDef);`<br/>
That's it for initialization. We are now ready to begin simulating.
<a name="stw"></a><br/>
## Simulating the World (of LiquidFun)
So we have initialized the ground box and a dynamic box. Now we are ready to
set Newton loose to do his thing. We just have a couple more issues to
consider.
LiquidFun uses a computational algorithm called an integrator. Integrators
simulate the physics equations at discrete points of time. This goes along
with the traditional game loop where we essentially have a flip book of
movement on the screen. So we need to pick a time step for LiquidFun.
Generally physics engines for games like a time step at least as fast as 60Hz
or 1/60 seconds. You can get away with larger time steps, but you will have to
be more careful about setting up the definitions for your world. We also don't
like the time step to change much. A variable time step produces variable
results, which makes it difficult to debug. So don't tie the time step to your
frame rate (unless you really, really have to). Without further ado, here is
the time step.
&nbsp;&nbsp;&nbsp;`float32 timeStep = 1.0f / 60.0f;`<br/>
In addition to the integrator, LiquidFun also uses a larger bit of code called
a constraint solver. The constraint solver solves all the constraints in the
simulation, one at a time. A single constraint can be solved perfectly.
However, when we solve one constraint, we slightly disrupt other constraints.
To get a good solution, we need to iterate over all constraints a number of
times.
There are two phases in the constraint solver: a velocity phase and a position
phase. In the velocity phase the solver computes the impulses necessary for
the bodies to move correctly. In the position phase the solver adjusts the
positions of the bodies to reduce overlap and joint detachment. Each phase has
its own iteration count. In addition, the position phase may exit iterations
early if the errors are small.
The suggested iteration count for LiquidFun is 8 for velocity and 3 for
position. You can tune this number to your liking, just keep in mind that this
has a trade-off between performance and accuracy. Using fewer iterations
increases performance but accuracy suffers. Likewise, using more iterations
decreases performance but improves the quality of your simulation. For this
simple example, we don't need much iteration. Here are our chosen iteration
counts.
&nbsp;&nbsp;&nbsp;`int32 velocityIterations = 6;`<br/>
&nbsp;&nbsp;&nbsp;`int32 positionIterations = 2;`<br/>
Note that the time step and the iteration count are completely unrelated. An
iteration is not a sub-step. One solver iteration is a single pass over all
the constraints within a time step. You can have multiple passes over the
constraints within a single time step.
We are now ready to begin the simulation loop. In your game the simulation
loop can be merged with your game loop. In each pass through your game loop
you call b2World::Step. Just one call is usually enough, depending on your
frame rate and your physics time step.
The Hello World program was designed to be simple, so it has no graphical
output. The code prints out the position and rotation of the dynamic body.
Here is the simulation loop that simulates 60 time steps for a total of 1
second of simulated time.
&nbsp;&nbsp;&nbsp;`for (int32 i = 0; i < 60; ++i)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;` world.Step(timeStep,
velocityIterations, positionIterations);`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;` b2Vec2 position =
body->GetPosition();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;` float32 angle =
body->GetAngle();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`printf("%4.2f %4.2f %4.2f\n", position.x,
position.y, angle);`<br/>
&nbsp;&nbsp;&nbsp;`}`
The output shows the box falling and landing on the ground box. Your output
should look like this:
0.00 4.00 0.00
0.00 3.99 0.00
0.00 3.98 0.00
...
0.00 1.25 0.00
0.00 1.13 0.00
0.00 1.01 0.00
<a name="cl"></a><br/>
## Cleanup
When a world leaves scope or is deleted by calling delete on a pointer, all
the memory reserved for bodies, fixtures, and joints is freed. This is done to
improve performance and make your life easier. However, you will need to
nullify any body, fixture, or joint pointers you have because they will become
invalid.
<a name="tb"></a><br/>
## The Testbed
Once you have conquered the HelloWorld example, you should start looking at
LiquidFun's testbed. The testbed is a unit-testing framework and demo
environment. Here are some of the features:
* Camera with pan and zoom.
* Mouse picking of shapes attached to dynamic bodies.
* Extensible set of tests.
* GUI for selecting tests, parameter tuning, and debug drawing options.
* Pause and single step simulation.
* Text rendering
<img align="center" src="image_2.gif" alt="Modules" height="300"
width="336"><br/>
The testbed has many examples of LiquidFun usage in the test cases and the
framework itself. I encourage you to explore and tinker with the testbed as
you learn LiquidFun.
Note: the testbed is written using freeglut and GLUI. The testbed is not part
of the LiquidFun library. The LiquidFun library is agnostic about rendering.
As shown by the HelloWorld example, you don't need a renderer to use LiquidFun.
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,93 @@
# Common
[About](#about)<br/>
[Settings](#settings)<br/>
[Memory Management](#mm)<br/>
[Math](#math)
<a name="about">
## About
The Common module contains settings, memory management, and vector math.
<a name="settings">
## Settings
The header b2Settings.h contains:
* Types such as int32 and float32
* Constants
* Allocation wrappers
* The version number
### Types
LiquidFun defines various types such as float32, int8, etc. to make it easy to
determine the size of structures.
### Constants
LiquidFun defines several constants. These are all documented in b2Settings.h.
Normally you do not need to adjust these constants.
LiquidFun uses floating point math for collision and simulation. Due to
round-off error some numerical tolerances are defined. Some tolerances are
absolute and some are relative. Absolute tolerances use MKS units.
### Allocation wrappers
The settings file defines b2Alloc and b2Free for large allocations. You may
forward these calls to your own memory management system.
### Version
The b2Version structure holds the current version so you can query this at
run-time.
<a name="mm">
## Memory Management
A large number of the decisions about the design of LiquidFun were based on
the need for quick and efficient use of memory. In this section I will discuss
how and why LiquidFun allocates memory.
LiquidFun tends to allocate a large number of small objects (around 50-300
bytes). Using the system heap through malloc or new for small objects is
inefficient and can cause fragmentation. Many of these small objects may have
a short life span, such as contacts, but can persist for several time steps.
So we need an allocator that can efficiently provide heap memory for these
objects.
LiquidFun's solution is to use a small object allocator (SOA) called
b2BlockAllocator. The SOA keeps a number of growable pools of varying sizes.
When a request is made for memory, the SOA returns a block of memory that best
fits the requested size. When a block is freed, it is returned to the pool.
Both of these operations are fast and cause little heap traffic.
Since LiquidFun uses a SOA, you should never new or malloc a body, fixture, or
joint. However, you do have to allocate a b2World on your own. The b2World
class provides factories for you to create bodies, fixtures, and joints. This
allows LiquidFun to use the SOA and hide the gory details from you. Never,
call delete or free on a body, fixture, or joint.
While executing a time step, LiquidFun needs some temporary workspace memory.
For this, it uses a stack allocator called b2StackAllocator to avoid per-step
heap allocations. You don't need to interact with the stack allocator, but
it's good to know it's there.
<a name="math">
## Math
LiquidFun includes a simple small vector and matrix module. This has been
designed to suit the internal needs of LiquidFun and the API. All the members
are exposed, so you may use them freely in your application.
The math library is kept simple to make LiquidFun easy to port and maintain.
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,438 @@
# Collision Module
[About](#about)<br/>
[Shapes](#shapes)<br/>
[Unary Geometric Queries](#un)<br/>
[Binary Functions](#bf)<br/>
[Dynamic Tree](#dt)<br/>
[Broad-Phase](#bp)<br/>
<a name="about">
## About
The Collision module contains shapes and functions that operate on them. The
module also contains a dynamic tree and broad-phase to acceleration collision
processing of large systems.
The collision module is designed to be usable outside of the dynamic system.
For example, you can use the dynamic tree for other aspects of your game
besides physics.
However, the main purpose of LiquidFun is to provide a rigid body physics
engine, so the using the collision module by itself may feel limited for some
applications. Likewise, I will not make a strong effort to document it or
polish the APIs.
<a name="shapes">
## Shapes
Shapes describe collision geometry and may be used independently of physics
simulation. At a minimum, you should understand how to create shapes that can
be later attached to rigid bodies.
LiquidFun shapes implement the b2Shape base class. The base class defines
functions to:
* Test a point for overlap with the shape.
* Perform a ray cast against the shape.
* Compute the shape's AABB.
* Compute the mass properties of the shape.
In addition, each shape has a type member and a radius. The radius even
applies to polygons, as discussed below.
Keep in mind that a shape does not know about bodies and stand apart from the
dynamics system. Shapes are stored in a compact form that is optimized for
size and performance. As such, shapes are not easily moved around. You have to
manually set the shape vertex positions to move a shape. However, when a shape
is attached to a body using a fixture, the shapes move rigidly with the host
body. In summary:
* When a shape is **not** attached to a body, you can view its vertices as
being expressed in world-space.
* When a shape is attached to a body, you can view its vertices as being
expressed in local coordinates.
### Circle Shapes
Circle shapes have a position and radius. Circles are solid. You cannot make
a hollow circle using the circle shape.
&nbsp;&nbsp;&nbsp;`b2CircleShape circle;`<br/>
&nbsp;&nbsp;&nbsp;`circle.m_p.Set(2.0f, 3.0f);`<br/>
&nbsp;&nbsp;&nbsp;`circle.m_radius = 0.5f;`<br/>
### Polygon Shapes
Polygon shapes are solid convex polygons. A polygon is convex when all line
segments connecting two points in the interior do not cross any edge of the
polygon. Polygons are solid and never hollow. A polygon must have 3 or more
vertices.
<img align="center" src="image_3.gif" alt="Polygon shapes" height="125"
width="223"><br/>
Polygon vertices are stored with a counter clockwise winding (CCW). We must be
careful because the notion of CCW is with respect to a right-handed coordinate
system with the z-axis pointing out of the plane. This might turn out to be
clockwise on your screen, depending on your coordinate system conventions.
<img align="center" src="image_4.png" alt="Polygon vertices" height="176"
width="347"><br/>
The polygon members are public, but you should use initialization functions to
create a polygon. The initialization functions create normal vectors and
perform validation.
You can create a polygon shape by passing in a vertex array. The maximal size
of the array is controlled by b2_maxPolygonVertices which has a default value
of 8. This is sufficient to describe most convex polygons.
The b2PolygonShape::Set function automatically computes the convex hull and
establishes the proper winding order. This function is fast when the number of
vertices is low. If you increase b2_maxPolygonVertices, then the convex hull
computation might become slow. Also note that the convex hull function may
eliminate and/or re-order the points you provide.
&nbsp;&nbsp;&nbsp;`// This defines a triangle in CCW order.`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 vertices[3];`<br/>
&nbsp;&nbsp;&nbsp;`vertices[0].Set(0.0f, 0.0f);`<br/>
&nbsp;&nbsp;&nbsp;`vertices[1].Set(1.0f, 0.0f);`<br/>
&nbsp;&nbsp;&nbsp;`vertices[2].Set(0.0f, 1.0f);`<br/>
&nbsp;&nbsp;&nbsp;`int32 count = 3;`<br/>
&nbsp;&nbsp;&nbsp;`b2PolygonShape polygon;`<br/>
&nbsp;&nbsp;&nbsp;`polygon.Set(vertices, count);`<br/>
The polygon shape has some convenience functions to create boxes.
&nbsp;&nbsp;&nbsp;`void SetAsBox(float32 hx, float32 hy);`<br/>
&nbsp;&nbsp;&nbsp;`void SetAsBox(float32 hx, float32 hy, const b2Vec2& center,
float32 angle);`<br/>
Polygons inherit a radius from b2Shape. The radius creates a skin around the
polygon. The skin is used in stacking scenarios to keep polygons slightly
separated. This allows continuous collision to work against the core polygon.
<img align="center" src="image_5.png" alt="Polygon skin" height="270"
width="300"><br/>
The polygon skin helps prevent tunneling by keeping the polygons separated.
This results in small gaps between the shapes. Your visual representation can
be larger than the polygon to hide any gaps.
<img align="center" src="image_6.png" alt="Polygons collide" height="109"
width="322"><br/>
### Edge Shapes
Edge shapes are line segments. These are provided to assist in making a
free-form static environment for your game. A major limitation of edge shapes
is that they can collide with circles and polygons but not with themselves.
The collision algorithms used by LiquidFun require that at least one of two
colliding shapes have volume. Edge shapes have no volume, so edge-edge
collision is not possible.
&nbsp;&nbsp;&nbsp;`// This an edge shape.`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 v1(0.0f, 0.0f);`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 v2(1.0f, 0.0f);`<br/>
&nbsp;&nbsp;&nbsp;`b2EdgeShape edge;`<br/>
&nbsp;&nbsp;&nbsp;`edge.Set(v1, v2);`<br/>
In many cases a game environment is constructed by connecting several edge
shapes end-to-end. This can give rise to an unexpected artifact when a polygon
slides along the chain of edges. In the figure below we see a box colliding
with an internal vertex. These *ghost* collisions are caused when the polygon
collides with an internal vertex generating an internal collision normal.
<img align="center" src="image_7.png" alt="Ghost collision" height="154"
width="315"><br/>
If edge1 did not exist this collision would seem fine. With edge1 present, the
internal collision seems like a bug. But normally when LiquidFun collides two
shapes, it views them in isolation.
Fortunately, the edge shape provides a mechanism for eliminating ghost
collisions by storing the adjacent *ghost *vertices. LiquidFun uses these
ghost vertices to prevent internal collisions.
<img align="center" src="image_8.png" alt="Ghost vertices" height="153"
width="332"><br/>
&nbsp;&nbsp;&nbsp;`// This is an edge shape with ghost vertices.`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 v0(1.7f, 0.0f);`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 v1(1.0f, 0.25f);`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 v2(0.0f, 0.0f);`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 v3(-1.7f, 0.4f);`<br/>
&nbsp;&nbsp;&nbsp;`b2EdgeShape edge;`<br/>
&nbsp;&nbsp;&nbsp;`edge.Set(v1, v2);`<br/>
&nbsp;&nbsp;&nbsp;`edge.m_hasVertex0 = true;`<br/>
&nbsp;&nbsp;&nbsp;`edge.m_hasVertex3 = true;`<br/>
&nbsp;&nbsp;&nbsp;`edge.m_vertex0 = v0;`<br/>
&nbsp;&nbsp;&nbsp;`edge.m_vertex3 = v3;`<br/>
In general stitching edges together this way is a bit wasteful and tedious.
This brings us to chain shapes.
### Chain Shapes
The chain shape provides an efficient way to connect many edges together to
construct your static game worlds. Chain shapes automatically eliminate ghost
collisions and provide two-sided collision.
<img align="center" src="image_9.png" alt="Chain shape" height="165"
width="305"><br/>
&nbsp;&nbsp;&nbsp;`// This a chain shape with isolated vertices`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 vs[4];`<br/>
&nbsp;&nbsp;&nbsp;`vs[0].Set(1.7f, 0.0f);`<br/>
&nbsp;&nbsp;&nbsp;`vs[1].Set(1.0f, 0.25f);`<br/>
&nbsp;&nbsp;&nbsp;`vs[2].Set(0.0f, 0.0f);`<br/>
&nbsp;&nbsp;&nbsp;`vs[3].Set(-1.7f, 0.4f);`<br/>
&nbsp;&nbsp;&nbsp;`b2ChainShape chain;`<br/>
&nbsp;&nbsp;&nbsp;`chain.CreateChain(vs, 4);`<br/>
You may have a scrolling game world and would like to connect several chains
together. You can connect chains together using ghost vertices, like we did
with b2EdgeShape.
&nbsp;&nbsp;&nbsp;`// Install ghost vertices`<br/>
&nbsp;&nbsp;&nbsp;`chain.SetPrevVertex(b2Vec2(3.0f, 1.0f));`<br/>
&nbsp;&nbsp;&nbsp;`chain.SetNextVertex(b2Vec2(-2.0f, 0.0f));`<br/>
You may also create loops automatically.
&nbsp;&nbsp;&nbsp;`// Create a loop. The first and last vertices are
connected.`<br/>
&nbsp;&nbsp;&nbsp;`b2ChainShape chain;`<br/>
&nbsp;&nbsp;&nbsp;`chain.CreateLoop(vs, 4);`<br/>
Self-intersection of chain shapes is not supported. It might work, it might
not. The code that prevents ghost collisions assumes there are no
self-intersections of the chain. Also, very close vertices can cause problems.
Make sure all your edges are longer than b2_linearSlop (5mm).
<img align="center" src="image_10.png" alt="No self-intersection" height="178"
width="335"><br/>
Each edge in the chain is treated as a child shape and can be accessed by
index. When a chain shape is connected to a body, each edge gets its own
bounding box in the broad-phase collision tree.
&nbsp;&nbsp;&nbsp;`// Visit each child edge.`<br/>
&nbsp;&nbsp;&nbsp;`for (int32 i = 0; i < chain.GetChildCount(); ++i)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2EdgeShape edge;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`chain.GetChildEdge(&edge, i);`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`…`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
<a name="un">
## Unary Geometric Queries
You can perform a couple of geometric queries on a single shape.
### Shape Point Test
You can test a point for overlap with a shape. You provide a transform for the
shape and a world point.
&nbsp;&nbsp;&nbsp;`b2Transfrom transform;`<br/>
&nbsp;&nbsp;&nbsp;`transform.SetIdentity();`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 point(5.0f, 2.0f);`<br/>
&nbsp;&nbsp;&nbsp;`bool hit = shape->TestPoint(transform, point);`<br/>
Edge and chain shapes always return false, even if the chain is a loop.
### Shape Ray Cast
You can cast a ray at a shape to get the point of first intersection and
normal vector. No hit will register if the ray starts inside the shape. A
child index is included for chain shapes because the ray cast will only check
a single edge at a time.
&nbsp;&nbsp;&nbsp;`b2Transfrom transform;`<br/>
&nbsp;&nbsp;&nbsp;`transform.SetIdentity();`<br/>
&nbsp;&nbsp;&nbsp;`b2RayCastInput input;`<br/>
&nbsp;&nbsp;&nbsp;`input.p1.Set(0.0f, 0.0f, 0.0f);`<br/>
&nbsp;&nbsp;&nbsp;`input.p2.Set(1.0f, 0.0f, 0.0f);`<br/>
&nbsp;&nbsp;&nbsp;`input.maxFraction = 1.0f;`<br/>
&nbsp;&nbsp;&nbsp;`int32 childIndex = 0;`<br/>
&nbsp;&nbsp;&nbsp;`b2RayCastOutput output;`<br/>
&nbsp;&nbsp;&nbsp;`bool hit = shape->RayCast(&output, input, transform,
childIndex);`<br/>
&nbsp;&nbsp;&nbsp;`if (hit)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Vec2 hitPoint = input.p1 +
output.fraction * (input.p2 input.p1);`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`…`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
<a name="bf">
## Binary Functions
The Collision module contains bilateral functions that take a pair of shapes
and compute some results. These include:
* Overlap
* Contact manifolds
* Distance
* Time of impact
### Overlap
You can test two shapes for overlap using this function:
&nbsp;&nbsp;&nbsp;`b2Transform xfA = …, xfB = …;`<br/>
&nbsp;&nbsp;&nbsp;`bool overlap = b2TestOverlap(shapeA, indexA, shapeB,
indexB, xfA, xfB);`<br/>
Again you must provide child indices to for the case of chain shapes.
### Contact Manifolds
LiquidFun has functions to compute contact points for overlapping shapes. If
we consider circle-circle or circle-polygon, we can only get one contact point
and normal. In the case of polygon-polygon we can get two points. These points
share the same normal vector so LiquidFun groups them into a manifold
structure. The contact solver takes advantage of this to improve stacking
stability.
<img align="center" src="image_11.png" alt="Manifold structure" height="300"
width="419"><br/>
Normally you dont need to compute contact manifolds directly, however you
will likely use the results produced in the simulation.
The b2Manifold structure holds a normal vector and up to two contact points.
The normal and points are held in local coordinates. As a convenience for the
contact solver, each point stores the normal and tangential (friction)
impulses.
The data stored in b2Manifold is optimized for internal use. If you need this
data, it is usually best to use the b2WorldManifold structure to generate the
world coordinates of the contact normal and points. You need to provide a
b2Manifold and the shape transforms and radii.
&nbsp;&nbsp;&nbsp;`b2WorldManifold worldManifold;`<br/>
&nbsp;&nbsp;&nbsp;`worldManifold.Initialize(&manifold, transformA,
shapeA.m_radius, transformB, shapeB.m_radius);`<br/>
&nbsp;&nbsp;&nbsp;`for (int32 i = 0; i < manifold.pointCount; ++i)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Vec2 point =
worldManifold.points[i];`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`…`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
Notice that the world manifold uses the point count from the original manifold.
During simulation shapes may move and the manifolds may change. Points may be
added or removed. You can detect this using b2GetPointStates.
&nbsp;&nbsp;&nbsp;`b2PointState state1[2], state2[2];`<br/>
&nbsp;&nbsp;&nbsp;`b2GetPointStates(state1, state2, &manifold1,
&manifold2);`<br/>
&nbsp;&nbsp;&nbsp;`if (state1[0] == b2_removeState)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`// process event`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
### Distance
The b2Distance function can be used to compute the distance between two
shapes. The distance function needs both shapes to be converted into a
b2DistanceProxy. There is also some caching used to warm start the distance
function for repeated calls. You can see the details in b2Distance.h.
<img align="center" src="image_12.png" alt="Distance" height="134"
width="271"><br/>
### Time of Impact
If two shapes are moving fast, they may *tunnel* through each other in a
single time step.
<img align="center" src="image_13.png" alt="Time-of-impact tunneling"
height="133" width="234"><br/>
The b2TimeOfImpact function is used to determine the time when two moving
shapes collide. This is called the *time of impact *(TOI). The main purpose of
b2TimeOfImpact is for tunnel prevention. In particular, it is designed to
prevent moving objects from tunneling outside of static level geometry.
This function accounts for rotation and translation of both shapes, however if
the rotations are large enough, then the function may miss a collision.
However the function will still report a non-overlapped time and will capture
all translational collisions.
The time of impact function identities an initial separating axis and ensures
the shapes do not cross on that axis. This might miss collisions that are
clear at the final positions. While this approach may miss some collisions, it
is very fast and adequate for tunnel prevention.
<img align="center" src="image_14.png" alt="Captured collision" height="169"
width="297"><br/>
<img align="center" src="image_15.png" alt="Missed collision" height="172"
width="297"><br/>
It is difficult to put a restriction on the rotation magnitude. There may be
cases where collisions are missed for small rotations. Normally, these missed
rotational collisions should not harm game play. They tend to be glancing
collisions.
The function requires two shapes (converted to b2DistanceProxy) and two
b2Sweep structures. The sweep structure defines the initial and final
transforms of the shapes.
You can use fixed rotations to perform a *shape cast*. In this case, the time
of impact function will not miss any collisions.
<a name="dt">
## Dynamic Tree
The b2DynamicTree class is used by LiquidFun to organize large numbers of
shapes efficiently. The class does not know about shapes. Instead it operates
on axis-aligned bounding boxes (AABBs) with user data pointers.
The dynamic tree is a hierarchical AABB tree. Each internal node in the tree
has two children. A leaf node is a single user AABB. The tree uses rotations
to keep the tree balanced, even in the case of degenerate input.
The tree structure allows for efficient ray casts and region queries. For
example, you may have hundreds of shapes in your scene. You could perform a
ray cast against the scene in a brute force manner by ray casting each shape.
This would be inefficient because it does not take advantage of shapes being
spread out. Instead, you can maintain a dynamic tree and perform ray casts
against the tree. This traverses the ray through the tree skipping large
numbers of shapes.
A region query uses the tree to find all leaf AABBs that overlap a query AABB.
This is faster than a brute force approach because many shapes can be skipped.
<img align="center" src="image_16.png" alt="Ray cast" height="249"
width="248"><br/>
<img align="center" src="image_17.png" alt="Region query" height="210"
width="231"><br/>
Normally you will not use the dynamic tree directly. Rather you will go
through the b2World class for ray casts and region queries. If you plan to
instantiate your own dynamic tree, you can learn how to use it by looking at
how LiquidFun uses it.
<a name="bp">
## Broad-phase
Collision processing in a physics step can be divided into narrow-phase and
broad-phase. In the narrow-phase we compute contact points between pairs of
shapes. Imagine we have N shapes. Using brute force, we would need to perform
the narrow-phase for N*N/2 pairs.
The b2BroadPhase class reduces this load by using a dynamic tree for pair
management. This greatly reduces the number of narrow-phase calls.
Normally you do not interact with the broad-phase directly. Instead, LiquidFun
creates and manages a broad-phase internally. Also, b2BroadPhase is designed
with LiquidFuns simulation loop in mind, so it is likely not suited for
other use cases.
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,37 @@
# Dynamics Module
[Overview](#ov)<br/>
<a name="ov">
## Overview
The Dynamics module is the most complex part of LiquidFun and is the part you
likely interact with the most. The Dynamics module sits on top of the Common
and Collision modules, so you should be somewhat familiar with those by now.
The Dynamics module contains:
* fixture class
* rigid body class
* contact class
* joint classes
* world class
* listener classes
There are many dependencies between these classes so it is difficult to
describe one class without referring to another. In the following, you may see
some references to classes that have not been described yet. Therefore, you
may want to quickly skim this chapter before reading it closely.
The dynamics module is covered in the following chapters.
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,363 @@
# Bodies
[About](#about)<br/>
[Body Definition](#bd)<br/>
[Body Factory](#bf)<br/>
[Using a Body](#ub)<br/>
<a name="about">
## About
Bodies have position and velocity. You can apply forces, torques, and impulses
to bodies. Bodies can be static, kinematic, or dynamic. Here are the body type
definitions:
### b2_staticBody
A static body does not move under simulation and behaves as if it has infinite
mass. Internally, LiquidFun stores zero for the mass and the inverse mass.
Static bodies can be moved manually by the user. A static body has zero
velocity. Static bodies do not collide with other static or kinematic bodies.
### b2_kinematicBody
A kinematic body moves under simulation according to its velocity. Kinematic
bodies do not respond to forces. They can be moved manually by the user, but
normally a kinematic body is moved by setting its velocity. A kinematic body
behaves as if it has infinite mass, however, LiquidFun stores zero for the
mass and the inverse mass. Kinematic bodies do not collide with other
kinematic or static bodies.
### b2_dynamicBody
A dynamic body is fully simulated. They can be moved manually by the user, but
normally they move according to forces. A dynamic body can collide with all
body types. A dynamic body always has finite, non-zero mass. If you try to set
the mass of a dynamic body to zero, it will automatically acquire a mass of
one kilogram and it wont rotate.
Bodies are the backbone for fixtures (shapes). Bodies carry fixtures and move
them around in the world. Bodies are always rigid bodies in LiquidFun. That
means that two fixtures attached to the same rigid body never move relative to
each other and fixtures attached to the same body dont collide.
Fixtures have collision geometry and density. Normally, bodies acquire their
mass properties from the fixtures. However, you can override the mass
properties after a body is constructed.
You usually keep pointers to all the bodies you create. This way you can query
the body positions to update the positions of your graphical entities. You
should also keep body pointers so you can destroy them when you are done with
them.
<a name="bd">
## Body Definition
Before a body is created you must create a body definition (b2BodyDef). The
body definition holds the data needed to create and initialize a body.
LiquidFun copies the data out of the body definition; it does not keep a
pointer to the body definition. This means you can recycle a body definition
to create multiple bodies.
Lets go over some of the key members of the body definition.
### Body Type
As discussed at the beginning of this chapter, there are three different body
types: static, kinematic, and dynamic. You should establish the body type at
creation because changing the body type later is expensive.
&nbsp;&nbsp;&nbsp;`bodyDef.type = b2_dynamicBody;`<br/>
Setting the body type is mandatory.
### Position and Angle
The body definition gives you the chance to initialize the position of the
body on creation. This has far better performance than creating the body at
the world origin and then moving the body.
Caution
Do not create a body at the origin and then move it. If you create
several bodies at the origin, then performance will suffer.
A body has two main points of interest. The first point is the body's origin.
Fixtures and joints are attached relative to the body's origin. The second
point of interest is the center of mass. The center of mass is determined from
mass distribution of the attached shapes or is explicitly set with b2MassData.
Much of LiquidFun's internal computations use the center of mass position. For
example b2Body stores the linear velocity for the center of mass.
When you are building the body definition, you may not know where the center
of mass is located. Therefore you specify the position of the body's origin.
You may also specify the body's angle in radians, which is not affected by the
position of the center of mass. If you later change the mass properties of the
body, then the center of mass may move on the body, but the origin position
does not change and the attached shapes and joints do not move.
&nbsp;&nbsp;&nbsp;`bodyDef.position.Set(0.0f, 2.0f); // the body's origin
position.`<br/>
&nbsp;&nbsp;&nbsp;`bodyDef.angle = 0.25f * b2_pi; // the body's angle in
radians.`<br/>
A rigid body is also a frame of reference. You can define fixtures and joints
in that frame. Those fixtures and joint anchors never move in the local frame
of the body.
### Damping
Damping is used to reduce the world velocity of bodies. Damping is different
than friction because friction only occurs with contact. Damping is not a
replacement for friction and the two effects should be used together.
Damping parameters should be between 0 and infinity, with 0 meaning no
damping, and infinity meaning full damping. Normally you will use a damping
value between 0 and 0.1. I generally do not use linear damping because it
makes bodies look floaty.
&nbsp;&nbsp;&nbsp;`bodyDef.linearDamping = 0.0f;`<br/>
&nbsp;&nbsp;&nbsp;`bodyDef.angularDamping = 0.01f;`<br/>
Damping is approximated for stability and performance. At small damping values
the damping effect is mostly independent of the time step. At larger damping
values, the damping effect will vary with the time step. This is not an issue
if you use a fixed time step (recommended).
### Gravity Scale
You can use the gravity scale to adjust the gravity on a single body. Be
careful though, increased gravity can decrease stability.
&nbsp;&nbsp;&nbsp;`// Set the gravity scale to zero so this body will
float`<br/>
&nbsp;&nbsp;&nbsp;`bodyDef.gravityScale = 0.0f;`<br/>
### Sleep Parameters
What does sleep mean? Well it is expensive to simulate bodies, so the less we
have to simulate the better. When a body comes to rest we would like to stop
simulating it.
When LiquidFun determines that a body (or group of bodies) has come to rest,
the body enters a sleep state which has very little CPU overhead. If a body is
awake and collides with a sleeping body, then the sleeping body wakes up.
Bodies will also wake up if a joint or contact attached to them is destroyed.
You can also wake a body manually.
The body definition lets you specify whether a body can sleep and whether a
body is created sleeping.
&nbsp;&nbsp;&nbsp;`bodyDef.allowSleep = true;`<br/>
&nbsp;&nbsp;&nbsp;`bodyDef.awake = true;`<br/>
### Fixed Rotation
You may want a rigid body, such as a character, to have a fixed rotation. Such
a body should not rotate, even under load. You can use the fixed rotation
setting to achieve this:
&nbsp;&nbsp;&nbsp;`bodyDef.fixedRotation = true;`<br/>
The fixed rotation flag causes the rotational inertia and its inverse to be
set to zero.
### Bullets
Game simulation usually generates a sequence of images that are played at some
frame rate. This is called discrete simulation. In discrete simulation, rigid
bodies can move by a large amount in one time step. If a physics engine
doesn't account for the large motion, you may see some objects incorrectly
pass through each other. This effect is called tunneling.
By default, LiquidFun uses continuous collision detection (CCD) to prevent
dynamic bodies from tunneling through static bodies. This is done by sweeping
shapes from their old position to their new positions. The engine looks for
new collisions during the sweep and computes the time of impact (TOI) for
these collisions. Bodies are moved to their first TOI and then halted for the
remainder of the time step.
Normally CCD is not used between dynamic bodies. This is done to keep
performance reasonable. In some game scenarios you need dynamic bodies to use
CCD. For example, you may want to shoot a high speed bullet at a stack of
dynamic bricks. Without CCD, the bullet might tunnel through the bricks.
Fast moving objects in LiquidFun can be labeled as bullets. Bullets will
perform CCD with both static and dynamic bodies. You should decide what bodies
should be bullets based on your game design. If you decide a body should be
treated as a bullet, use the following setting.
&nbsp;&nbsp;&nbsp;`bodyDef.bullet = true;`<br/>
The bullet flag only affects dynamic bodies.
LiquidFun performs continuous collision sequentially, so bullets may miss fast
moving bodies.
### Activation
You may wish a body to be created but not participate in collision or
dynamics. This state is similar to sleeping except the body will not be woken
by other bodies and the body's fixtures will not be placed in the broad-phase.
This means the body will not participate in collisions, ray casts, etc.
You can create a body in an inactive state and later re-activate it.
&nbsp;&nbsp;&nbsp;`bodyDef.active = true;`<br/>
Joints may be connected to inactive bodies. These joints will not be
simulated. You should be careful when you activate a body that its joints are
not distorted.
### User Data
User data is a void pointer. This gives you a hook to link your application
objects to bodies. You should be consistent to use the same object type for
all body user data.
&nbsp;&nbsp;&nbsp;`b2BodyDef bodyDef;`<br/>
&nbsp;&nbsp;&nbsp;`bodyDef.userData = &myActor;`<br/>
<a name="bf">
## Body Factory
Bodies are created and destroyed using a body factory provided by the world
class. This lets the world create the body with an efficient allocator and add
the body to the world data structure.
Bodies can be dynamic or static depending on the mass properties. Both body
types use the same creation and destruction methods.
&nbsp;&nbsp;&nbsp;`b2Body* dynamicBody = myWorld->CreateBody(&bodyDef);`<br/>
&nbsp;&nbsp;&nbsp;`... do stuff …`<br/>
&nbsp;&nbsp;&nbsp;`myWorld->DestroyBody(dynamicBody);`<br/>
&nbsp;&nbsp;&nbsp;`dynamicBody = NULL;`<br/>
Caution
You should never use new or malloc to create a body. The world won't
know about the body and the body won't be properly initialized.
Static bodies do not move under the influence of other bodies. You may
manually move static bodies, but you should be careful so that you don't
squash dynamic bodies between two or more static bodies. Friction will not
work correctly if you move a static body. Static bodies never collide with
static or kinematic bodies. It is faster to attach several shapes to a static
body than to create several static bodies with a single shape on each one.
Internally, LiquidFun sets the mass and inverse mass of static bodies to zero.
This makes the math work out so that most algorithms don't need to treat
static bodies as a special case.
LiquidFun does not keep a reference to the body definition or any of the data
it holds (except user data pointers). So you can create temporary body
definitions and reuse the same body definitions.
LiquidFun allows you to avoid destroying bodies by deleting your b2World
object, which does all the cleanup work for you. However, you should be
mindful to nullify body pointers that you keep in your game engine.
When you destroy a body, the attached fixtures and joints are automatically
destroyed. This has important implications for how you manage shape and joint
pointers.
<a name="ub">
## Using a Body
After creating a body, there are many operations you can perform on the body.
These include setting mass properties, accessing position and velocity,
applying forces, and transforming points and vectors.
### Mass Data
Every body has a mass (scalar), center of mass (2-vector), and rotational
inertia (scalar). For static bodies, the mass and rotational inertia are set
to zero. When a body has fixed rotation, its rotational inertia is zero.
Normally the mass properties of a body are established automatically when
fixtures are added to the body. You can also adjust the mass of a body at
run-time. This is usually done when you have special game scenarios that
require altering the mass.
&nbsp;&nbsp;&nbsp;`void SetMassData(const b2MassData* data);`<br/>
After setting a body's mass directly, you may wish to revert to the natural
mass dictated by the fixtures. You can do this with:
&nbsp;&nbsp;&nbsp;`void ResetMassData();`<br/>
The body's mass data is available through the following functions:
&nbsp;&nbsp;&nbsp;`float32 GetMass() const;`
&nbsp;&nbsp;&nbsp;`float32 GetInertia() const;`
&nbsp;&nbsp;&nbsp;`const b2Vec2& GetLocalCenter() const;`
&nbsp;&nbsp;&nbsp;`void GetMassData(b2MassData* data) const;`
### State Information
There are many aspects to the body's state. You can access this state data
efficiently through the following functions:
&nbsp;&nbsp;&nbsp;`void SetType(b2BodyType type);`
&nbsp;&nbsp;&nbsp;`b2BodyType GetType();`
&nbsp;&nbsp;&nbsp;`void SetBullet(bool flag);`
&nbsp;&nbsp;&nbsp;`bool IsBullet() const;`
&nbsp;&nbsp;&nbsp;`void SetSleepingAllowed(bool flag);`
&nbsp;&nbsp;&nbsp;`bool IsSleepingAllowed() const;`
&nbsp;&nbsp;&nbsp;`void SetAwake(bool flag);`
&nbsp;&nbsp;&nbsp;`bool IsAwake() const;`
&nbsp;&nbsp;&nbsp;`void SetActive(bool flag);`
&nbsp;&nbsp;&nbsp;`bool IsActive() const;`
&nbsp;&nbsp;&nbsp;`void SetFixedRotation(bool flag);`
&nbsp;&nbsp;&nbsp;`bool IsFixedRotation() const;`
### Position and Velocity
You can access the position and rotation of a body. This is common when
rendering your associated game actor. You can also set the position, although
this is less common since you will normally use LiquidFun to simulate movement.
&nbsp;&nbsp;&nbsp;`bool SetTransform(const b2Vec2& position, float32
angle);`<br/>
&nbsp;&nbsp;&nbsp;`const b2Transform& GetTransform() const;`<br/>
&nbsp;&nbsp;&nbsp;`const b2Vec2& GetPosition() const;`<br/>
&nbsp;&nbsp;&nbsp;`float32 GetAngle() const;`<br/>
You can access the center of mass position in local and world coordinates.
Much of the internal simulation in LiquidFun uses the center of mass. However,
you should normally not need to access it. Instead you will usually work with
the body transform. For example, you may have a body that is square. The body
origin might be a corner of the square, while the center of mass is located at
the center of the square.
&nbsp;&nbsp;&nbsp;`const b2Vec2& GetWorldCenter() const;`<br/>
&nbsp;&nbsp;&nbsp;`const b2Vec2& GetLocalCenter() const;`<br/>
You can access the linear and angular velocity. The linear velocity is for the
center of mass. Therefore, the linear velocity may change if the mass
properties change.
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,201 @@
# Fixtures
[About](#about)<br/>
[Fixture Creation](#fc)<br/>
[Sensors](#se)<br/>
<a name="about">
## About
Recall that shapes dont know about bodies and may be used independently of
the physics simulation. Therefore LiquidFun provides the b2Fixture class to
attach shapes to bodies. A body may have zero or more fixtures. A body with
multiple fixtures is sometimes called a *compound body.*
Fixtures hold the following:
* a single shape
* broad-phase proxies
* density, friction, and restitution
* collision filtering flags
* back pointer to the parent body
* user data
* sensor flag
These are described in the following sections.
<a name="fc">
## Fixture Creation
Fixtures are created by initializing a fixture definition and then passing the
definition to the parent body.
&nbsp;&nbsp;&nbsp;`b2FixtureDef fixtureDef;`<br/>
&nbsp;&nbsp;&nbsp;`fixtureDef.shape = &myShape;`<br/>
&nbsp;&nbsp;&nbsp;`fixtureDef.density = 1.0f;`<br/>
&nbsp;&nbsp;&nbsp;`b2Fixture* myFixture =
myBody->CreateFixture(&fixtureDef);`<br/>
This creates the fixture and attaches it to the body. You do not need to store
the fixture pointer since the fixture will automatically be destroyed when the
parent body is destroyed. You can create multiple fixtures on a single body.
You can destroy a fixture on the parent body. You may do this to model a
breakable object. Otherwise you can just leave the fixture alone and let the
body destruction take care of destroying the attached fixtures.
&nbsp;&nbsp;&nbsp;`myBody->DestroyFixture(myFixture);`<br/>
### Density
The fixture density is used to compute the mass properties of the parent body.
The density can be zero or positive. You should generally use similar
densities for all your fixtures. This will improve stacking stability.
The mass of a body is not adjusted when you set the density. You must call
ResetMassData for this to occur.
&nbsp;&nbsp;&nbsp;`fixture->SetDensity(5.0f);`<br/>
&nbsp;&nbsp;&nbsp;`body->ResetMassData();`<br/>
### Friction
Friction is used to make objects slide along each other realistically.
LiquidFun supports static and dynamic friction, but uses the same parameter
for both. Friction is simulated accurately in LiquidFun and the friction
strength is proportional to the normal force (this is called Coulomb
friction). The friction parameter is usually set between 0 and 1, but can be
any non-negative value. A friction value of 0 turns off friction and a value
of 1 makes the friction strong. When the friction force is computed between
two shapes, LiquidFun must combine the friction parameters of the two parent
fixtures. This is done with the geometric mean:
&nbsp;&nbsp;&nbsp;`float32 friction;`<br/>
&nbsp;&nbsp;&nbsp;`friction = sqrtf(fixtureA->friction *
fixtureB->friction);`<br/>
So if one fixture has zero friction then the contact will have zero friction.
You can override the default mixed friction using b2Contact::SetFriction. This
is usually done in the b2ContactListener callback.
### Restitution
Restitution is used to make objects bounce. The restitution value is usually
set to be between 0 and 1. Consider dropping a ball on a table. A value of
zero means the ball won't bounce. This is called an inelastic collision. A
value of one means the ball's velocity will be exactly reflected. This is
called a perfectly elastic collision. Restitution is combined using the
following formula.
&nbsp;&nbsp;&nbsp;`float32 restitution;`<br/>
&nbsp;&nbsp;&nbsp;`restitution = b2Max(fixtureA->restitution,
fixtureB->restitution);`<br/>
Restitution is combined this way so that you can have a bouncy super ball
without having a bouncy floor.
You can override the default mixed restitution using
b2Contact::SetRestitution. This is usually done in the b2ContactListener
callback.
When a shape develops multiple contacts, restitution is simulated
approximately. This is because LiquidFun uses an iterative solver. LiquidFun
also uses inelastic collisions when the collision velocity is small. This is
done to prevent jitter. See b2_velocityThreshold in b2Settings.h.
### Filtering
Collision filtering allows you to prevent collision between fixtures. For
example, say you make a character that rides a bicycle. You want the bicycle
to collide with the terrain and the character to collide with the terrain, but
you don't want the character to collide with the bicycle (because they must
overlap). LiquidFun supports such collision filtering using categories and
groups.
LiquidFun supports 16 collision categories. For each fixture you can specify
which category it belongs to. You also specify what other categories this
fixture can collide with. For example, you could specify in a multiplayer game
that all players don't collide with each other and monsters don't collide with
each other, but players and monsters should collide. This is done with masking
bits. For example:
&nbsp;&nbsp;&nbsp;`playerFixtureDef.filter.categoryBits = 0x0002;`<br/>
&nbsp;&nbsp;&nbsp;`monsterFixtureDef.filter.categoryBits = 0x0004;`<br/>
&nbsp;&nbsp;&nbsp;`playerFixtureDef.filter.maskBits = 0x0004;`<br/>
&nbsp;&nbsp;&nbsp;`monsterFixtureDef.filter.maskBits = 0x0002;`<br/>
Here is the rule for a collision to occur:
&nbsp;&nbsp;&nbsp;`uint16 catA = fixtureA.filter.categoryBits;`<br/>
&nbsp;&nbsp;&nbsp;`uint16 maskA = fixtureA.filter.maskBits;`<br/>
&nbsp;&nbsp;&nbsp;`uint16 catB = fixtureB.filter.categoryBits;`<br/>
&nbsp;&nbsp;&nbsp;`uint16 maskB = fixtureB.filter.maskBits;`<br/>
&nbsp;&nbsp;&nbsp;`if ((catA & maskB) != 0 && (catB & maskA) != 0)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; `// fixtures can collide`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
Collision groups let you specify an integral group index. You can have all
fixtures with the same group index always collide (positive index) or never
collide (negative index). Group indices are usually used for things that are
somehow related, like the parts of a bicycle. In the following example,
fixture1 and fixture2 always collide, but fixture3 and fixture4 never collide.
&nbsp;&nbsp;&nbsp;`fixture1Def.filter.groupIndex = 2;`<br/>
&nbsp;&nbsp;&nbsp;`fixture2Def.filter.groupIndex = 2;`<br/>
&nbsp;&nbsp;&nbsp;`fixture3Def.filter.groupIndex = -8;`<br/>
&nbsp;&nbsp;&nbsp;`fixture4Def.filter.groupIndex = -8;`<br/>
Collisions between fixtures of different group indices are filtered according
the category and mask bits. In other words, group filtering has higher
precedence than category filtering.
Note that additional collision filtering occurs in LiquidFun. Here is a list:
* A fixture on a static body can only collide with a dynamic body.
* A fixture on a kinematic body can only collide with a dynamic body.
* Fixtures on the same body never collide with each other.
* You can optionally enable/disable collision between fixtures on bodies
connected by a joint.
Sometimes you might need to change collision filtering after a fixture has
already been created. You can get and set the b2Filter structure on an
existing fixture using b2Fixture::GetFilterData and b2Fixture::SetFilterData.
Note that changing the filter data will not add or remove contacts until the
next time step (see the World class).
<a name="se">
## Sensors
Sometimes game logic needs to know when two fixtures overlap yet there should
be no collision response. This is done by using sensors. A sensor is a fixture
that detects collision but does not produce a response.
You can flag any fixture as being a sensor. Sensors may be static, kinematic,
or dynamic. Remember that you may have multiple fixtures per body and you can
have any mix of sensors and solid fixtures. Also, sensors only form contacts
when at least one body is dynamic, so you will not get a contact for kinematic
versus kinematic, kinematic versus static, or static versus static.
Sensors do not generate contact points. There are two ways to get the state of
a sensor:
1. `b2Contact::IsTouching`
2. `b2ContactListener::BeginContact and EndContact`
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,434 @@
# Joints
[About](#about)<br/>
[Joint Definition](#jd)<br/>
[Joint Factory](#jf)<br/>
[Using Joints](#uj)<br/>
<a name="about">
## About
Joints are used to constrain bodies to the world or to each other. Typical
examples in games include ragdolls, teeters, and pulleys. Joints can be
combined in many different ways to create interesting motions.
Some joints provide limits so you can control the range of motion. Some joint
provide motors which can be used to drive the joint at a prescribed speed
until a prescribed force/torque is exceeded.
Joint motors can be used in many ways. You can use motors to control position
by specifying a joint velocity that is proportional to the difference between
the actual and desired position. You can also use motors to simulate joint
friction: set the joint velocity to zero and provide a small, but significant
maximum motor force/torque. Then the motor will attempt to keep the joint from
moving until the load becomes too strong.
<a name="jd">
## Joint Definition
Each joint type has a definition that derives from b2JointDef. All joints are
connected between two different bodies. One body may static. Joints between
static and/or kinematic bodies are allowed, but have no effect and use some
processing time.
You can specify user data for any joint type and you can provide a flag to
prevent the attached bodies from colliding with each other. This is actually
the default behavior and you must set the collideConnected Boolean to allow
collision between to connected bodies.
Many joint definitions require that you provide some geometric data. Often a
joint will be defined by anchor points. These are points fixed in the attached
bodies. LiquidFun requires these points to be specified in local coordinates.
This way the joint can be specified even when the current body transforms
violate the joint constraint --- a common occurrence when a game is saved and
reloaded. Additionally, some joint definitions need to know the default
relative angle between the bodies. This is necessary to constrain rotation
correctly.
Initializing the geometric data can be tedious, so many joints have
initialization functions that use the current body transforms to remove much
of the work. However, these initialization functions should usually only be
used for prototyping. Production code should define the geometry directly.
This will make joint behavior more robust.
The rest of the joint definition data depends on the joint type. We cover
these now.
<a name="jf">
## Joint Factory
Joints are created and destroyed using the world factory methods. This brings
up an old issue:
Caution
Don't try to create a joint on the stack or on the heap using new or malloc. You must create and destroy bodies and joints using the create and destroy methods of the b2World class.
Here's an example of the lifetime of a revolute joint:
&nbsp;&nbsp;&nbsp;`b2RevoluteJointDef jointDef;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.bodyA = myBodyA;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.bodyB = myBodyB;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.anchorPoint = myBodyA->GetCenterPosition();`<br/>
&nbsp;&nbsp;&nbsp;`b2RevoluteJoint* joint =
(b2RevoluteJoint*)myWorld->CreateJoint(&jointDef);`<br/>
&nbsp;&nbsp;&nbsp;`… do stuff …`<br/>
&nbsp;&nbsp;&nbsp;`myWorld->DestroyJoint(joint);`<br/>
&nbsp;&nbsp;&nbsp;`joint = NULL;`<br/>
It is always good to nullify your pointer after they are destroyed. This will
make the program crash in a controlled manner if you try to reuse the pointer.
The lifetime of a joint is not simple. Heed this warning well:
Caution
Joints are destroyed when an attached body is destroyed.
This precaution is not always necessary. You may organize your game engine so
that joints are always destroyed before the attached bodies. In this case you
don't need to implement the listener class. See the section on Implicit
Destruction for details.
<a name="uj">
## Using Joints
Many simulations create the joints and don't access them again until they are
destroyed. However, there is a lot of useful data contained in joints that you
can use to create a rich simulation.
First of all, you can get the bodies, anchor points, and user data from a
joint.
&nbsp;&nbsp;&nbsp;`b2Body* GetBodyA();`
&nbsp;&nbsp;&nbsp;`b2Body* GetBodyB();`
&nbsp;&nbsp;&nbsp;`b2Vec2 GetAnchorA();`
&nbsp;&nbsp;&nbsp;`b2Vec2 GetAnchorB();`
&nbsp;&nbsp;&nbsp;`void* GetUserData();`
All joints have a reaction force and torque. This the reaction force applied
to body 2 at the anchor point. You can use reaction forces to break joints or
trigger other game events. These functions may do some computations, so don't
call them if you don't need the result.
&nbsp;&nbsp;&nbsp;`b2Vec2 GetReactionForce();`<br/>
&nbsp;&nbsp;&nbsp;`float32 GetReactionTorque();`<br/>
### Distance Joint
One of the simplest joint is a distance joint which says that the distance
between two points on two bodies must be constant. When you specify a distance
joint the two bodies should already be in place. Then you specify the two
anchor points in world coordinates. The first anchor point is connected to
body 1, and the second anchor point is connected to body 2. These points imply
the length of the distance constraint.
<img align="center" src="image_18.gif" alt="Distance joint" height="118"
width="155"><br/>
Here is an example of a distance joint definition. In this case we decide to
allow the bodies to collide.
&nbsp;&nbsp;&nbsp;`b2DistanceJointDef jointDef;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.Initialize(myBodyA, myBodyB, worldAnchorOnBodyA,
worldAnchorOnBodyB);`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.collideConnected = true;`<br/>
The distance joint can also be made soft, like a spring-damper connection. See
the Web example in the testbed to see how this behaves.
Softness is achieved by tuning two constants in the definition: frequency and
damping ratio. Think of the frequency as the frequency of a harmonic
oscillator (like a guitar string). The frequency is specified in Hertz.
Typically the frequency should be less than a half the frequency of the time
step. So if you are using a 60Hz time step, the frequency of the distance
joint should be less than 30Hz. The reason is related to the Nyquist frequency.
The damping ratio is non-dimensional and is typically between 0 and 1, but can
be larger. At 1, the damping is critical (all oscillations should vanish).
&nbsp;&nbsp;&nbsp;`jointDef.frequencyHz = 4.0f;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.dampingRatio = 0.5f;`<br/>
### Revolute Joint
A revolute joint forces two bodies to share a common anchor point, often
called a hinge point. The revolute joint has a single degree of freedom: the
relative rotation of the two bodies. This is called the joint angle.
<img align="center" src="image_19.gif" alt="Revolute joint" height="97"
width="139"><br/>
To specify a revolute you need to provide two bodies and a single anchor point
in world space. The initialization function assumes that the bodies are
already in the correct position.
In this example, two bodies are connected by a revolute joint at the first
body's center of mass.
&nbsp;&nbsp;&nbsp;`b2RevoluteJointDef jointDef;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.Initialize(myBodyA, myBodyB,
myBodyA->GetWorldCenter());`<br/>
The revolute joint angle is positive when bodyB rotates CCW about the angle
point. Like all angles in LiquidFun, the revolute angle is measured in
radians. By convention the revolute joint angle is zero when the joint is
created using Initialize(), regardless of the current rotation of the two
bodies.
In some cases you might wish to control the joint angle. For this, the
revolute joint can optionally simulate a joint limit and/or a motor.
A joint limit forces the joint angle to remain between a lower and upper
bound. The limit will apply as much torque as needed to make this happen. The
limit range should include zero, otherwise the joint will lurch when the
simulation begins.
A joint motor allows you to specify the joint speed (the time derivative of
the angle). The speed can be negative or positive. A motor can have infinite
force, but this is usually not desirable. Recall the eternal question:
*"What happens when an irresistible force meets an immovable object?"*
I can tell you it's not pretty. So you can provide a maximum torque for the
joint motor. The joint motor will maintain the specified speed unless the
required torque exceeds the specified maximum. When the maximum torque is
exceeded, the joint will slow down and can even reverse.
You can use a joint motor to simulate joint friction. Just set the joint speed
to zero, and set the maximum torque to some small, but significant value. The
motor will try to prevent the joint from rotating, but will yield to a
significant load.
Here's a revision of the revolute joint definition above; this time the joint
has a limit and a motor enabled. The motor is setup to simulate joint friction.
b2RevoluteJointDef jointDef;
jointDef.Initialize(bodyA, bodyB, myBodyA->GetWorldCenter());
jointDef.lowerAngle = -0.5f * b2_pi; // -90 degrees
jointDef.upperAngle = 0.25f * b2_pi; // 45 degrees
jointDef.enableLimit = true;
jointDef.maxMotorTorque = 10.0f;
jointDef.motorSpeed = 0.0f;
jointDef.enableMotor = true;
You can access a revolute joint's angle, speed, and motor torque.
&nbsp;&nbsp;&nbsp;`float32 GetJointAngle() const;`<br/>
&nbsp;&nbsp;&nbsp;`float32 GetJointSpeed() const;`<br/>
&nbsp;&nbsp;&nbsp;`float32 GetMotorTorque() const;`<br/>
You also update the motor parameters each step.
&nbsp;&nbsp;&nbsp;`void SetMotorSpeed(float32 speed);`<br/>
&nbsp;&nbsp;&nbsp;`void SetMaxMotorTorque(float32 torque);`<br/>
Joint motors have some interesting abilities. You can update the joint speed
every time step so you can make the joint move back-and-forth like a sine-wave
or according to whatever function you want.
&nbsp;&nbsp;&nbsp;`... Game Loop Begin ...`<br/>
&nbsp;&nbsp;&nbsp;`myJoint->SetMotorSpeed(cosf(0.5f * time));`<br/>
&nbsp;&nbsp;&nbsp;`... Game Loop End ...`<br/>
You can also use joint motors to track a desired joint angle. For example:
&nbsp;&nbsp;&nbsp;`... Game Loop Begin ...`<br/>
&nbsp;&nbsp;&nbsp;`float32 angleError = myJoint->GetJointAngle() -
angleTarget;`<br/>
&nbsp;&nbsp;&nbsp;`float32 gain = 0.1f;`<br/>
&nbsp;&nbsp;&nbsp;`myJoint->SetMotorSpeed(-gain * angleError);`<br/>
&nbsp;&nbsp;&nbsp;`... Game Loop End ...`<br/>
Generally your gain parameter should not be too large. Otherwise your joint
may become unstable.
### Prismatic Joint
A prismatic joint allows for relative translation of two bodies along a
specified axis. A prismatic joint prevents relative rotation. Therefore, a
prismatic joint has a single degree of freedom.
<img align="center" src="image_20.gif" alt="Prismatic joint" height="134"
width="165"><br/>
The prismatic joint definition is similar to the revolute joint description;
just substitute translation for angle and force for torque. Using this analogy
provides an example prismatic joint definition with a joint limit and a
friction motor:
&nbsp;&nbsp;&nbsp;`b2PrismaticJointDef jointDef;`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 worldAxis(1.0f, 0.0f);`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.Initialize(myBodyA, myBodyB,
myBodyA->GetWorldCenter(), worldAxis);`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.lowerTranslation = -5.0f;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.upperTranslation = 2.5f;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.enableLimit = true;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.maxMotorForce = 1.0f;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.motorSpeed = 0.0f;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.enableMotor = true;`<br/>
The revolute joint has an implicit axis coming out of the screen. The
prismatic joint needs an explicit axis parallel to the screen. This axis is
fixed in the two bodies and follows their motion.
Like the revolute joint, the prismatic joint translation is zero when the
joint is created using Initialize(). So be sure zero is between your lower and
upper translation limits.
Using a prismatic joint is similar to using a revolute joint. Here are the
relevant member functions:
&nbsp;&nbsp;&nbsp;`float32 GetJointTranslation() const;`
&nbsp;&nbsp;&nbsp;`float32 GetJointSpeed() const;`
&nbsp;&nbsp;&nbsp;`float32 GetMotorForce() const;`
&nbsp;&nbsp;&nbsp;`void SetMotorSpeed(float32 speed);`
&nbsp;&nbsp;&nbsp;`void SetMotorForce(float32 force);`
### Pulley Joint
A pulley is used to create an idealized pulley. The pulley connects two bodies
to ground and to each other. As one body goes up, the other goes down. The
total length of the pulley rope is conserved according to the initial
configuration.
length1 + length2 == constant
You can supply a ratio that simulates a block and tackle. This causes one side
of the pulley to extend faster than the other. At the same time the constraint
force is smaller on one side than the other. You can use this to create
mechanical leverage.
length1 + ratio * length2 == constant
For example, if the ratio is 2, then length1 will vary at twice the rate of
length2. Also the force in the rope attached to body1 will have half the
constraint force as the rope attached to body2.
<img align="center" src="image_21.gif" alt="Pulley joint" height="213"
width="237"><br/>
Pulleys can be troublesome when one side is fully extended. The rope on the
other side will have zero length. At this point the constraint equations
become singular (bad). You should configure collision shapes to prevent this.
Here is an example pulley definition:
&nbsp;&nbsp;&nbsp;`b2Vec2 anchor1 = myBody1->GetWorldCenter();`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 anchor2 = myBody2->GetWorldCenter();`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 groundAnchor1(p1.x, p1.y + 10.0f);`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 groundAnchor2(p2.x, p2.y + 12.0f);`<br/>
&nbsp;&nbsp;&nbsp;`float32 ratio = 1.0f;`<br/>
&nbsp;&nbsp;&nbsp;`b2PulleyJointDef jointDef;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.Initialize(myBody1, myBody2, groundAnchor1,
groundAnchor2, anchor1, anchor2, ratio);`<br/>
Pulley joints provide the current lengths.
&nbsp;&nbsp;&nbsp;`float32 GetLengthA() const;`<br/>
&nbsp;&nbsp;&nbsp;`float32 GetLengthB() const;`<br/>
### Gear Joint
If you want to create a sophisticated mechanical contraption you might want to
use gears. In principle you can create gears in LiquidFun by using compound
shapes to model gear teeth. This is not very efficient and might be tedious to
author. You also have to be careful to line up the gears so the teeth mesh
smoothly. LiquidFun has a simpler method of creating gears: the gear joint.
<img align="center" src="image_22.gif" alt="Gear joint" height="188"
width="179"><br/>
The gear joint can only connect revolute and/or prismatic joints.
Like the pulley ratio, you can specify a gear ratio. However, in this case the
gear ratio can be negative. Also keep in mind that when one joint is a
revolute joint (angular) and the other joint is prismatic (translation), and
then the gear ratio will have units of length or one over length.
coordinate1 + ratio * coordinate2 == constant
Here is an example gear joint. The bodies myBodyA and myBodyB are any bodies
from the two joints, as long as they are not the same bodies.
&nbsp;&nbsp;&nbsp;`b2GearJointDef jointDef;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.bodyA = myBodyA;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.bodyB = myBodyB;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.joint1 = myRevoluteJoint;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.joint2 = myPrismaticJoint;`<br/>
&nbsp;&nbsp;&nbsp;`jointDef.ratio = 2.0f * b2_pi / myLength;`<br/>
Note that the gear joint depends on two other joints. This creates a fragile
situation. What happens if those joints are deleted?
Caution
Always delete gear joints before the revolute/prismatic joints on the gears. Otherwise your code will crash in a bad way due to the orphaned joint pointers in the gear joint. You should also delete the gear joint before you delete any of the bodies involved.
### Mouse Joint
The mouse joint is used in the testbed to manipulate bodies with the mouse. It
attempts to drive a point on a body towards the current position of the
cursor. There is no restriction on rotation.
The mouse joint definition has a target point, maximum force, frequency, and
damping ratio. The target point initially coincides with the bodys anchor
point. The maximum force is used to prevent violent reactions when multiple
dynamic bodies interact. You can make this as large as you like. The frequency
and damping ratio are used to create a spring/damper effect similar to the
distance joint.
Many users have tried to adapt the mouse joint for game play. Users often
want to achieve precise positioning and instantaneous response. The mouse
joint doesnt work very well in that context. You may wish to consider using
kinematic bodies instead.
### Wheel Joint
The wheel joint restricts a point on bodyB to a line on bodyA. The wheel joint
also provides a suspension spring. See b2WheelJoint.h and Car.h for details.
<img align="center" src="image_23.png" alt="Wheel joint" height="286"
width="157"><br/>
### Weld Joint
The weld joint attempts to constrain all relative motion between two bodies.
See the Cantilever.h in the testbed to see how the weld joint behaves.
It is tempting to use the weld joint to define breakable structures. However,
the LiquidFun solver is iterative so the joints are a bit soft. So chains of
bodies connected by weld joints will flex.
Instead it is better to create breakable bodies starting with a single body
with multiple fixtures. When the body breaks, you can destroy a fixture and
recreate it on a new body. See the Breakable example in the testbed.
### Rope Joint
The rope joint restricts the maximum distance between two points. This can be
useful to prevent chains of bodies from stretching, even under high load. See
b2RopeJoint.h and RopeJoint.h for details.
### Friction Joint
The friction joint is used for top-down friction. The joint provides 2D
translational friction and angular friction. See b2FrictionJoint.h and
ApplyForce.h for details.
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,364 @@
# Contacts
[About](#about)<br/>
[Contact Class](#cc)<br/>
[Accessing Contacts](#ac)<br/>
[Contact Listener](#cl)<br/>
[Contact Filtering](#cf)<br/>
<a name="about"></a>
## About
Contacts are objects created by LiquidFun to manage collision between two
fixtures. If the fixture has children, such as a chain shape, then a contact
exists for each relevant child. There are different kinds of contacts, derived
from b2Contact, for managing contact between different kinds of fixtures. For
example there is a contact class for managing polygon-polygon collision and
another contact class for managing circle-circle collision.
Here is some terminology associated with contacts.
### contact point
A contact point is a point where two shapes touch. LiquidFun approximates
contact with a small number of points.
### contact normal
A contact normal is a unit vector that points from one shape to another. By
convention, the normal points from fixtureA to fixtureB.
### contact separation
Separation is the opposite of penetration. Separation is negative when shapes
overlap. It is possible that future versions of LiquidFun will create contact
points with positive separation, so you may want to check the sign when
contact points are reported.
### contact manifold
Contact between two convex polygons may generate up to 2 contact points. Both
of these points use the same normal, so they are grouped into a contact
manifold, which is an approximation of a continuous region of contact.
### normal impulse
The normal force is the force applied at a contact point to prevent the shapes
from penetrating. For convenience, LiquidFun works with impulses. The normal
impulse is just the normal force multiplied by the time step.
### tangent impulse
The tangent force is generated at a contact point to simulate friction. For
convenience, this is stored as an impulse.
### contact ids
LiquidFun tries to re-use the contact force results from a time step as the
initial guess for the next time step. LiquidFun uses contact ids to match
contact points across time steps. The ids contain geometric features indices
that help to distinguish one contact point from another.
Contacts are created when two fixtures AABBs overlap. Sometimes collision
filtering will prevent the creation of contacts. Contacts are destroyed with
the AABBs cease to overlap.
So you might gather that there may be contacts created for fixtures that are
not touching (just their AABBs). Well, this is correct. It's a "chicken or egg"
problem. We don't know if we need a contact object until one is created
to analyze the collision. We could delete the contact right away if the shapes
are not touching, or we can just wait until the AABBs stop overlapping.
LiquidFun takes the latter approach because it lets the system cache
information to improve performance.
<a name="cc">
## Contact Class
As mentioned before, the contact class is created and destroyed by LiquidFun.
Contact objects are not created by the user. However, you are able to access
the contact class and interact with it.
You can access the raw contact manifold:
&nbsp;&nbsp;&nbsp;`b2Manifold* GetManifold();`<br/>
&nbsp;&nbsp;&nbsp;`const b2Manifold* GetManifold() const;`<br/>
You can potentially modify the manifold, but this is generally not supported
and is for advanced usage.
There is a helper function to get the b2WorldManifold:
&nbsp;&nbsp;&nbsp;`void GetWorldManifold(b2WorldManifold* worldManifold)
const;`<br/>
This uses the current positions of the bodies to compute world positions of
the contact points.
Sensors do not create manifolds, so for them use:
&nbsp;&nbsp;&nbsp;`bool touching = sensorContact->IsTouching();`<br/>
This function also works for non-sensors.
You can get the fixtures from a contact. From those you can get the bodies.
&nbsp;&nbsp;&nbsp;`b2Fixture* fixtureA = myContact->GetFixtureA();`<br/>
&nbsp;&nbsp;&nbsp;`b2Body* bodyA = fixtureA->GetBody();`<br/>
&nbsp;&nbsp;&nbsp;`MyActor* actorA = (MyActor*)bodyA->GetUserData();`<br/>
You can disable a contact. This only works inside the
b2ContactListener::PreSolve event, discussed below.
<a name="ac">
## Accessing Contacts
You can get access to contacts in several ways. You can access the contacts
directly on the world and body structures. You can also implement a contact
listener.
You can iterate over all contacts in the world:
&nbsp;&nbsp;&nbsp;`for (b2Contact* c = myWorld->GetContactList(); c; c =
c->GetNext())`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`// process c`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
You can also iterate over all the contacts on a body. These are stored in a
graph using a contact edge structure.
&nbsp;&nbsp;&nbsp;`for (b2ContactEdge* ce = myBody->GetContactList(); ce; ce =
ce->next)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;` b2Contact* c = ce->contact;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;` // process c`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
You can also access contacts using the contact listener that is described
below.
Caution
Accessing contacts off b2World and b2Body may miss some transient
contacts that occur in the middle of the time step. Use b2ContactListener to
get the most accurate results.
<a name="cl">
## Contact Listener
You can receive contact data by implementing b2ContactListener. The contact
listener supports several events: begin, end, pre-solve, and post-solve.
&nbsp;&nbsp;&nbsp;`class MyContactListener : public b2ContactListener`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`public:`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`void BeginContact(b2Contact*
contact)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{ /* handle begin event */ }`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`void EndContact(b2Contact* contact)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{ /* handle end event */ }`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`void PreSolve(b2Contact* contact, const
b2Manifold* oldManifold)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{ /* handle pre-solve event */ }`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`void PostSolve(b2Contact* contact, const
b2ContactImpulse* impulse)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{ /* handle post-solve event */ }`<br/>
&nbsp;&nbsp;&nbsp;`};`<br/>
Caution
Do not keep a reference to the pointers sent to b2ContactListener.
Instead make a deep copy of the contact point data into your own buffer. The
example below shows one way of doing this.
At run-time you can create an instance of the listener and register it
with b2World::SetContactListener. Be sure your listener remains in scope while
the world object exists.
### Begin Contact Event
This is called when two fixtures begin to overlap. This is called for sensors
and non-sensors. This event can only occur inside the time step.
### End Contact Event
This is called when two fixtures cease to overlap. This is called for sensors
and non-sensors. This may be called when a body is destroyed, so this event
can occur outside the time step.
### Pre-Solve Event
This is called after collision detection, but before collision resolution.
This gives you a chance to disable the contact based on the current
configuration. For example, you can implement a one-sided platform using this
callback and calling b2Contact::SetEnabled(false). The contact will be
re-enabled each time through collision processing, so you will need to disable
the contact every time-step. The pre-solve event may be fired multiple times
per time step per contact due to continuous collision detection.
&nbsp;&nbsp;&nbsp;`void PreSolve(b2Contact* contact, const b2Manifold*
oldManifold)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;`b2WorldManifold worldManifold;`<br/>
&nbsp;&nbsp;&nbsp;`contact->GetWorldManifold(&worldManifold);`<br/>
&nbsp;&nbsp;&nbsp;`if (worldManifold.normal.y < -0.5f)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`contact->SetEnabled(false);`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
The pre-solve event is also a good place to determine the point state and the
approach velocity of collisions.
&nbsp;&nbsp;&nbsp;`void PreSolve(b2Contact* contact, const b2Manifold*
oldManifold)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2WorldManifold worldManifold;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`contact->GetWorldManifold(&worldManifold);`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2PointState state1[2], state2[2];`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2GetPointStates(state1, state2,
oldManifold, contact->GetManifold());`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`if (state2[0] == b2_addState)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`const b2Body* bodyA =
contact->GetFixtureA()->GetBody();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`const b2Body* bodyB =
contact->GetFixtureB()->GetBody();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Vec2 point =
worldManifold.points[0];`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Vec2 vA =
bodyA->GetLinearVelocityFromWorldPoint(point);`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Vec2 vB =
bodyB->GetLinearVelocityFromWorldPoint(point);`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`float32
approachVelocity = b2Dot(vB vA, worldManifold.normal);`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`if (approachVelocity >
1.0f)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`MyPlayCollisionSound();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
### Post-Solve Event
The post solve event is where you can gather collision impulse results. If you
dont care about the impulses, you should probably just implement the
pre-solve event.
It is tempting to implement game logic that alters the physics world inside a
contact callback. For example, you may have a collision that applies damage
and try to destroy the associated actor and its rigid body. However, LiquidFun
does not allow you to alter the physics world inside a callback because you
might destroy objects that LiquidFun is currently processing, leading to
orphaned pointers.
The recommended practice for processing contact points is to buffer all
contact data that you care about and process it after the time step. You
should always process the contact points immediately after the time step;
otherwise some other client code might alter the physics world, invalidating
the contact buffer. When you process the contact buffer you can alter the
physics world, but you still need to be careful that you don't orphan pointers
stored in the contact point buffer. The testbed has example contact point
processing that is safe from orphaned pointers.
This code from the CollisionProcessing test shows how to handle orphaned
bodies when processing the contact buffer. Here is an excerpt. Be sure to read
the comments in the listing. This code assumes that all contact points have
been buffered in the b2ContactPoint array m_points.
&nbsp;&nbsp;&nbsp;`// We are going to destroy some bodies according to
contact`<br/>
&nbsp;&nbsp;&nbsp;`// points. We must buffer the bodies that should be
destroyed`<br/>
&nbsp;&nbsp;&nbsp;`// because they may belong to multiple contact points.`<br/>
&nbsp;&nbsp;&nbsp;`const int32 k_maxNuke = 6;`<br/>
&nbsp;&nbsp;&nbsp;`b2Body* nuke[k_maxNuke];`<br/>
&nbsp;&nbsp;&nbsp;`int32 nukeCount = 0;`<br/>
&nbsp;&nbsp;&nbsp;`// Traverse the contact buffer. Destroy bodies that`<br/>
&nbsp;&nbsp;&nbsp;`// are touching heavier bodies.`<br/>
&nbsp;&nbsp;&nbsp;`for (int32 i = 0; i < m_pointCount; ++i)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`ContactPoint* point = m_points + i;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Body* bodyA =
point->fixtureA->GetBody();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Body* bodyB =
point->FixtureB->GetBody();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`float32 massA = bodyA->GetMass();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`float32 massB = bodyB->GetMass();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`if (massA > 0.0f && massB > 0.0f)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`if (massB > massA)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`nuke[nukeCount++] = bodyA;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`else`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`nuke[nukeCount++] = bodyB;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`if (nukeCount == k_maxNuke)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`break;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;`// Sort the nuke array to group duplicates.`<br/>
&nbsp;&nbsp;&nbsp;`std::sort(nuke, nuke + nukeCount);`<br/>
&nbsp;&nbsp;&nbsp;`// Destroy the bodies, skipping duplicates.`<br/>
&nbsp;&nbsp;&nbsp;`int32 i = 0;`<br/>
&nbsp;&nbsp;&nbsp;`while (i < nukeCount)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Body* b = nuke[i++];`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`while (i < nukeCount && nuke[i] ==
b)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`++i;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`m_world->DestroyBody(b);`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
## Contact Filtering
Often in a game you don't want all objects to collide. For example, you may
want to create a door that only certain characters can pass through. This is
called contact filtering, because some interactions are filtered out.
LiquidFun allows you to achieve custom contact filtering by implementing a
b2ContactFilter class. This class requires you to implement a ShouldCollide
function that receives two b2Shape pointers. Your function returns true if the
shapes should collide.
The default implementation of ShouldCollide uses the b2FilterData defined in
Chapter 6, Fixtures.
&nbsp;&nbsp;&nbsp;`bool b2ContactFilter::ShouldCollide(b2Fixture* fixtureA,
b2Fixture* fixtureB)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`const b2Filter& filterA =
fixtureA->GetFilterData();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`const b2Filter& filterB =
fixtureB->GetFilterData();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`if (filterA.groupIndex ==
filterB.groupIndex && filterA.groupIndex != 0)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`return
filterA.groupIndex > 0;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`bool collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`return collide;`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
At run-time you can create an instance of your contact filter and register it
with b2World::SetContactFilter. Make sure your filter stays in scope while the
world exists.
&nbsp;&nbsp;&nbsp;`MyContactFilter filter;`<br/>
&nbsp;&nbsp;&nbsp;`world->SetContactFilter(&filter);`<br/>
&nbsp;&nbsp;&nbsp;`// filter remains in scope …`<br/>
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,322 @@
# World Class
[About](#about)<br/>
[Creating and Destroying a World](#cdw)<br/>
[Using a World](#uw)<br/>
[Simulation](#sim)<br/>
[Exploring the World](#ew)<br/>
[AABB Queries](#ab)<br/>
[Ray Casts](#rc)<br/>
[Forces and Impulses](#fi)<br/>
[Coordinate Transformations](#ct)<br/>
[Lists](#lists)<br/>
<a name="about"></a><br/>
## About
The b2World class contains the bodies and joints. It manages all aspects of
the simulation and allows for asynchronous queries (like AABB queries and
ray-casts). Much of your interactions with LiquidFun will be with a b2World
object.
<a name="cdw"></a><br/>
## Creating and Destroying a World
Creating a world is fairly simple. You just need to provide a gravity vector
and a Boolean indicating if bodies can sleep. Usually you will create and
destroy a world using new and delete.
&nbsp;&nbsp;&nbsp;`b2World* myWorld = new b2World(gravity, doSleep);`<br/>
&nbsp;&nbsp;&nbsp;`... do stuff ...`<br/>
&nbsp;&nbsp;&nbsp;`delete myWorld;`<br/>
<a name="uw"></a><br/>
## Using a World
The world class contains factories for creating and destroying bodies and
joints. These factories are discussed later in the sections on bodies and
joints. There are some other interactions with b2World that I will cover now.
<a name="sim"></a><br/>
## Simulation
The world class is used to drive the simulation. You specify a time step and a
velocity and position iteration count. For example:
&nbsp;&nbsp;&nbsp;`float32 timeStep = 1.0f / 60.f;`<br/>
&nbsp;&nbsp;&nbsp;`int32 velocityIterations = 10;`<br/>
&nbsp;&nbsp;&nbsp;`int32 positionIterations = 8;`<br/>
&nbsp;&nbsp;&nbsp;`myWorld->Step(timeStep, velocityIterations,
positionIterations);`<br/>
After the time step you can examine your bodies and joints for information.
Most likely you will grab the position off the bodies so that you can update
your actors and render them. You can perform the time step anywhere in your
game loop, but you should be aware of the order of things. For example, you
must create bodies before the time step if you want to get collision results
for the new bodies in that frame.
As I discussed above in the HelloWorld tutorial, you should use a fixed time
step. By using a larger time step you can improve performance in low frame
rate scenarios. But generally you should use a time step no larger than 1/30
seconds. A time step of 1/60 seconds will usually deliver a high quality
simulation.
The iteration count controls how many times the constraint solver sweeps over
all the contacts and joints in the world. More iteration always yields a
better simulation. But don't trade a small time step for a large iteration
count. 60Hz and 10 iterations is far better than 30Hz and 20 iterations.
After stepping, you should clear any forces you have applied to your bodies.
This is done with the command b2World::ClearForces. This lets you take
multiple sub-steps with the same force field.
&nbsp;&nbsp;&nbsp;`myWorld->ClearForces();`<br/>
<a name="ew"></a><br/>
## Exploring the World
The world is a container for bodies, contacts, and joints. You can grab the
body, contact, and joint lists off the world and iterate over them. For
example, this code wakes up all the bodies in the world:
&nbsp;&nbsp;&nbsp;`for (b2Body* b = myWorld->GetBodyList(); b; b =
b->GetNext())`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;` b->SetAwake(true);`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
Unfortunately real programs can be more complicated. For example, the
following code is broken:
&nbsp;&nbsp;&nbsp;`for (b2Body* b = myWorld->GetBodyList(); b; b =
b->GetNext())`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`GameActor* myActor =
(GameActor*)b->GetUserData();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`if (myActor->IsDead())`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`myWorld->DestroyBody(b);
// ERROR: now GetNext returns garbage.`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
Everything goes ok until a body is destroyed. Once a body is destroyed, its
next pointer becomes invalid. So the call to b2Body::GetNext() will return
garbage. The solution to this is to copy the next pointer before destroying
the body.
&nbsp;&nbsp;&nbsp;`b2Body* node = myWorld->GetBodyList();`<br/>
&nbsp;&nbsp;&nbsp;`while (node)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Body* b = node;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`node = node->GetNext();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`GameActor* myActor =
(GameActor*)b->GetUserData();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`if (myActor->IsDead())`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`myWorld->DestroyBody(b);`
<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
This safely destroys the current body. However, you may want to call a game
function that may destroy multiple bodies. In this case you need to be very
careful. The solution is application specific, but for convenience I'll show
one method of solving the problem.
&nbsp;&nbsp;&nbsp;`b2Body* node = myWorld->GetBodyList();`<br/>
&nbsp;&nbsp;&nbsp;`while (node)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Body* b = node;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`node = node->GetNext();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`GameActor* myActor =
(GameActor*)b->GetUserData();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`if (myActor->IsDead())`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`bool
otherBodiesDestroyed = GameCrazyBodyDestroyer(b);`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`if
(otherBodiesDestroyed)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`node
= myWorld->GetBodyList();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
Obviously to make this work, GameCrazyBodyDestroyer must be honest about what
it has destroyed.
<a name="ab"></a><br/>
## AABB Queries
Sometimes you want to determine all the shapes in a region. The b2World class
has a fast log(N) method for this using the broad-phase data structure. You
provide an AABB in world coordinates and an implementation of b2QueryCallback.
The world calls your class with each fixture whose AABB overlaps the query
AABB. Return true to continue the query, otherwise return false. For example,
the following code finds all the fixtures that potentially intersect a
specified AABB and wakes up all of the associated bodies.
&nbsp;&nbsp;&nbsp;`class MyQueryCallback : public b2QueryCallback`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`public:`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`bool ReportFixture(b2Fixture*
fixture)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Body* body =
fixture->GetBody();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`body->SetAwake(true);`<br
/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`// Return true to
continue the query.`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`return true;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;`};`<br/>
&nbsp;&nbsp;&nbsp;`...`<br/>
&nbsp;&nbsp;&nbsp;`MyQueryCallback callback;`<br/>
&nbsp;&nbsp;&nbsp;`b2AABB aabb;`<br/>
&nbsp;&nbsp;&nbsp;`aabb.lowerBound.Set(-1.0f, -1.0f);`<br/>
&nbsp;&nbsp;&nbsp;`aabb.upperBound.Set(1.0f, 1.0f);`<br/>
&nbsp;&nbsp;&nbsp;`myWorld->Query(&callback, aabb);`<br/>
You cannot make any assumptions about the order of the callbacks.
<a name="rc"></a><br/>
## Ray Casts
You can use ray casts to do line-of-sight checks, fire guns, etc. You perform
a ray cast by implementing a callback class and providing the start and end
points. The world class calls your class with each fixture hit by the ray.
Your callback is provided with the fixture, the point of intersection, the
unit normal vector, and the fractional distance along the ray. You cannot make
any assumptions about the order of the callbacks.
You control the continuation of the ray cast by returning a fraction.
Returning a fraction of zero indicates the ray cast should be terminated. A
fraction of one indicates the ray cast should continue as if no hit occurred.
If you return the fraction from the argument list, the ray will be clipped to
the current intersection point. So you can ray cast any shape, ray cast all
shapes, or ray cast the closest shape by returning the appropriate fraction.
You may also return of fraction of -1 to filter the fixture. Then the ray cast
will proceed as if the fixture does not exist.
Here is an example:
&nbsp;&nbsp;&nbsp;`// This class captures the closest hit shape.`<br/>
&nbsp;&nbsp;&nbsp;`class MyRayCastCallback : public b2RayCastCallback`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`public:`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`MyRayCastCallback()`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`m_fixture = NULL;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`float32 ReportFixture(b2Fixture* fixture,
const b2Vec2& point, const b2Vec2& normal, float32 fraction)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`m_fixture =
fixture;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`m_point = point;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`m_normal = normal;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`m_fraction =
fraction;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`return fraction;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Fixture* m_fixture;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Vec2 m_point;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`b2Vec2 m_normal;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`float32 m_fraction;`<br/>
&nbsp;&nbsp;&nbsp;`};`<br/>
&nbsp;&nbsp;&nbsp;`MyRayCastCallback callback;`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 point1(-1.0f, 0.0f);`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 point2(3.0f, 1.0f);`<br/>
&nbsp;&nbsp;&nbsp;`myWorld->RayCast(&callback, point1, point2);`<br/>
Caution
Due to round-off errors, ray casts can sneak through small cracks
between polygons in your static environment. If this is not acceptable in your
application, please enlarge your polygons slightly.
&nbsp;&nbsp;&nbsp;`void SetLinearVelocity(const b2Vec2& v);`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 GetLinearVelocity() const;`<br/>
&nbsp;&nbsp;&nbsp;`void SetAngularVelocity(float32 omega);`<br/>
&nbsp;&nbsp;&nbsp;`float32 GetAngularVelocity() const;`<br/>
<a name="fi"></a><br/>
## Forces and Impulses
You can apply forces, torques, and impulses to a body. When you apply a force
or an impulse, you provide a world point where the load is applied. This often
results in a torque about the center of mass.
void ApplyForce(const b2Vec2& force, const b2Vec2& point);
void ApplyTorque(float32 torque);
void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point);
void ApplyAngularImpulse(float32 impulse);
Applying a force, torque, or impulse wakes the body. Sometimes this is
undesirable. For example, you may be applying a steady force and want to allow
the body to sleep to improve performance. In this case you can use the
following code.
&nbsp;&nbsp;&nbsp;`if (myBody->IsAwake() == true)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`myBody->ApplyForce(myForce,
myPoint);`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
You can apply forces and impulses to particles and particle groups, as well.
Unlike with bodies, however, the load is not applied to an arbitrary world
point. Instead, it acts upon the center of each particle.
You can apply forces and impulses to individual particles or to particle groups.
The following example spreads an impulse of (0.7, 0.3) kg m/s across the
particles in myParticleGroup:
&nbsp;&nbsp;&nbsp;`const b2Vec2 impulse(0.7f, 0.3f);`
&nbsp;&nbsp;&nbsp;`myParticleGroup->ApplyLinearImpulse(impulse);`
<a name="ct"></a><br/>
## Coordinate Transformations
The body class has some utility functions to help you transform points and
vectors between local and world space. If you don't understand these concepts,
please read "Essential Mathematics for Games and Interactive Applications" by
Jim Van Verth and Lars Bishop. These functions are efficient (when inlined).
&nbsp;&nbsp;&nbsp;`b2Vec2 GetWorldPoint(const b2Vec2& localPoint);`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 GetWorldVector(const b2Vec2& localVector);`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 GetLocalPoint(const b2Vec2& worldPoint);`<br/>
&nbsp;&nbsp;&nbsp;`b2Vec2 GetLocalVector(const b2Vec2& worldVector);`<br/>
<a name="lists"></a><br/>
## Lists
You can iterate over a body's fixtures. This is mainly useful if you need to
access the fixture's user data.
&nbsp;&nbsp;&nbsp;`for (b2Fixture* f = body->GetFixtureList(); f; f =
f->GetNext())`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`MyFixtureData* data =
(MyFixtureData*)f->GetUserData();`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`… do something with data …`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
You can similarly iterate over the body's joint list.
The body also provides a list of associated contacts. You can use this to get
information about the current contacts. Be careful, because the contact list
may not contain all the contacts that existed during the previous time step.
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,729 @@
# Particle Module
[About](#About)<br/>
[Particles](#Particles)<br/>
[Particle Systems](#ps)<br/>
[Particle Groups](#pg)<br/>
[Discrete Particles vs. Particle Groups](#dp)<br/>
[Stepping the World](#stw)<br/>
[Maximum Velocity](#mv)<br/>
[Creating and Destroying Particles](#cdp)<br/>
[Creating and Destroying Particle Groups](#cdpg)<br/>
[Particle Behaviors](#pb)<br/>
[Particle Properties](#pp)<br/>
[Rendering with OpenGL](#gl)<br/>
[Sample Applications](#sa)<br/>
<a name="About">
## About
The Particle module offers the ability to create and manipulate liquid or soft
(deformable) bodies. It allows you to create (and destroy) particles with
various behaviors and properties, and provides various methods for
manipulating
them. The module permits you to define particles discretely or as groups. It
is
designed to allow you to manipulate large numbers of particles efficiently.
<a name="Particles">
## Particles
A particle is round, and the minimal unit of matter in a particle system. By
default, a particle behaves as a liquid. You can set behavioral flags,
however, to assign different behaviors (explained in
[Particle Behaviors](#pb)) to individual particles or groups of particles.
You can also set other particle properties including position, velocity, and
color.<br/>
The `b2Particle.h` file contains the enumerated behavior values, as well as
the
variables specifying other particle properties. The corresponding enum is
named `b2ParticleFlag.`
<a name="ps">
## Particle Systems
The "world" that particles inhabit is called a particle system. A particle
system describes a wide variety of physical coefficients that help dictate
how particles interact with the world around them. A few examples of these
conditions are default particle radius, elasticity, and viscosity. For more
detail, see the API Reference description of the b2ParticleSystemDef struct.
The following example creates a particle system:
&nbsp;&nbsp;&nbsp;`const b2ParticleSystemDef particleSystemDef;`<br/>
&nbsp;&nbsp;&nbsp;`m_particleSystems[0] =
`m_world->CreateParticleSystem(&particleSystemDef);`<br/>
You can also create more than one particle system: Thus, one "world's"
particles may have a certain default radius, elasticity, etc., while the other
"world" has different default values for these properties. The following sample
shows the creation of multiple particle systems:
&nbsp;&nbsp;&nbsp;`const b2ParticleSystemDef particleSystemDef;`<br/>
&nbsp;&nbsp;&nbsp;`for (int i = 0; i < NUM_PARTICLE_SYSTEMS; ++i) {`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
`m_particleSystems[i] = m_world->CreateParticleSystem(&particleSystemDef);`
<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
In many, if not most,
cases, it will not be necessary to adjust the default values or create multiple
particle systems. You may find it useful in some cases, however.
For example, dividing particles into multiple systems can yield a performance
gain by allowing you to simulate only the visible systems while putting all
other systems in a "paused" state using `b2ParticleSystem::SetPaused()`.
The "Multiple Systems" example in the Testbed provides an example of
two particle systems influencing a rigid body while not interacting with each
other.
<a name="pg">
## Particle Groups
Instead of creating particles individually, you can create a group of
particles to manipulate en masse. Some of the particle-group properties that
you can set are the same as those for discrete particles: behavior, position,
linear velocity, and color. There are also properties specific to groups:
rotational angle, rotational velocity, and strength.<br/>
The `b2ParticleGroup.h` file contains the declarations for all of these
variables, as well as the enum for particle-group behavior:
`b2ParticleGroupFlag`.
<a name="dp">
## Discrete Particles vs. Particle Groups
With one main exception, there is no functional difference between working
with individual particles and groups of particles. The exception is rigid
particles: Because of the internal algorithm used to make particles rigid, you
must define them as a group.
Particle groups do offer several conveniences. First, they allow you to create
and destroy large numbers of particles automatically. If you do not create a
group, you must create all of the particles individually. Also, a group allows
you to assign the same property, such as angle of rotation, to all of its
particles at once.
<a name="stw">
## Stepping the World (Particle Iterations)
The particle solver can iterate multiple times per step. Larger numbers of
steps improve the stability and fidelity of the particle simulation. However,
more steps also require more processor cycles.
The cycles cost is almost linear: double the number of particle iterations
will almost double the cycles cost of b2ParticleSystem::Solve.
Use the `particleIterations` parameter in `b2World::Step` to set the number
of iterations. The default value of `particleIterations` is 1.
You should experiment with `particleIterations` in your game to find the best
balance of stability versus cycles. Try calling `b2CalculateParticleIterations`
or `b2World::CalculateReasonableParticleIterations` to estimate a reasonable
value. Note that these functions are, necessarily, a simplification, and
should be used only as a starting point.
If your simulation seems overly bouncy or energetic, or if the particles in
your simulation are passing through contacts, try increasing the number of
particle iterations.
Note that, as particle iterations increases, the affect of pressure on
highly-compressed particles also increases. That is, particles get more
incompressible as you increase particle iterations.
<a name="mv">
## Maximum Velocity
The particle simulation enforces a maximum velocity on the particles, for
stability and to prevent excessive interpenetration. The maximum velocity is,
&nbsp;&nbsp;&nbsp;`particle diameter / (particle iterations *
b2World::Step's dt)`<br/>
<a name="cdp">
## Creating and Destroying Particles
To create individual particles, create a `b2ParticleDef`-struct object. Next,
specify the behavior and properties of the particle. Finally, call the method
to create the particle.<br/>
The following example creates an individual particle.
&nbsp;&nbsp;&nbsp;`b2ParticleDef pd;`<br>
&nbsp;&nbsp;&nbsp;`pd.flags = b2_elasticParticle;`<br/>
&nbsp;&nbsp;&nbsp;`pd.color.Set(0, 0, 255, 255);`<br/>
&nbsp;&nbsp;&nbsp;`pd.position.Set(i, 0);`<br/>
&nbsp;&nbsp;&nbsp;`int tempIndex = m_particleSystem->CreateParticle(pd);`<br/>
Particle lists are self-compacting. Therefore, the index returned by
CreateParticle is only valid until a lower-indexed particle, or a group
referencing a lower-indexed particle, is deleted.<br/>
To destroy an individual particle, invoke the function
&nbsp;&nbsp;&nbsp;`void DestroyParticle(int32 index);`
The following example destroys the particle created above.
&nbsp;&nbsp;&nbsp;`m_particleSystem->DestroyParticle(tempIndex);`<br/>
### Particle lifetimes
In addition to manual destruction of particles as described above, particles
can also expire and be destroyed due to age.
The following example tells the system to track particle ages for the purpose
of destroying them.
&nbsp;&nbsp;&nbsp;`m_particleSystem->SetParticleDestructionByAge(true);`
A particle can die one of two "age-related" deaths. First, you can set a
lifetime for a particle--a period of time after which it expires. The following
example does this:
&nbsp;&nbsp;&nbsp;`m_particleSystem->SetParticleLifetime(`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`index, Random() *`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
`(k_particleLifetimeMax - k_particleLifetimeMin) +`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`k_particleLifetimeMin);`<br/>
where `index` specifies the number of the particle whose lifetime is being
assigned, and the `Random()` function generates a random value for that
lifetime.
You do not need to set a specific lifetime for a particle for it to have an
age-related death. If you set a maximum number of particles that can exist in a
particle system, and you have have told the system to track particle ages, the
system clamps particle count by culling "excess" particles. Particle culling
takes place in age order, with the oldest ones destroyed first.
The following example sets a maximum particle count for a particle system.
&nbsp;&nbsp;&nbsp;`m_particleSystem->SetMaxParticleCount(k_maxParticleCount);`
The Faucet example in the Testbed provides an example of both types of
lifetime-driven particle destruction.
### Stuck Particles
Particles may get stuck and become obstructions that need to be destroyed or
relocated. A particle is identified as possibly stuck if it remains in contact
with two or more surfaces for a user-specified number (threshold) of particle
iterations. Once "candidates" are identified, you can implement your own logic
to decide whether they are actually stuck, and how to deal with them.
The ability to implement your own logic gives you flexibility in deciding
when you want to consider a particle stuck. For instance, a ball may
be traveling down a chute, making contact with walls on multiple sides. This
state satisfies the "possibly stuck" condition described in the previous
paragraph. But you could implement logic judging the ball not stuck as long
as it keeps traveling down the chute.
On the other hand, you could also decide that not only an immobile particle,
but even a mobile one trapped in a certain spatial range, is stuck. The system
relies on you to judge the candidates.
The following example shows one possible implementation for such a case.
<pre>
// This code example of app logic deciding whether or not to eliminate stuck
// particles shows a user who set up a global array of sensor fixtures
// covering areas they know to be "problematic" for stuck particles in
// their geometry, and then at each step testing any stuck particles against
// those sensors, eliminating any stuck particles that lie inside a known
// problem region.
void DestroyStuckParticlesInSensors(
const b2Fixture * const *sensors, int32 num)
{
const int32 stuck = gParticleSystem->GetStuckCandidateCount();
if (stuck > 0)
{
const int32 *candidates = gParticleSystem->GetStuckCandidates();
const b2Vec2 *positions = gParticleSystem->GetPositionBuffer();
for (int32 i = 0; i < stuck; ++i)
{
const int32 particle = candidates[i];
const b2Vec2 &position = positions[particle];
for (int32 j = 0; j < num; ++j)
{
if(sensors[j]->TestPoint(position))
{
gParticleSystem->DestroyParticle(particle);
}
}
}
}
}
// particles in multiple contacts for 5 or more iterations are
// candidates
gParticleSystem->SetStuckThreshold(5);
// step the world (assuming the timestep, velocity iterations,
// and position iterations have been set globally).
gWorld->Step(gTimeStep, gVelocityIterations, gPositionIterations);
// Perform the above check for stuck particles against sensors
// in this global array.
DestroyStuckParticlesInSensors(gProblemAreaSensors, gNumSensors);
</pre>
<a name="cdpg">
## Creating and Destroying Particle Groups
A particle group begins life in a shaped container. You must therefore start a
particle group definition by specifying a shape. Next, create a
b2ParticleGroupDef-struct object. Then, specify the behavior and properties of
the particles themselves. Finally, call the method to create a particle
group.<br/>
The following example creates five differently colored, box-shaped groups of
particles.
&nbsp;&nbsp;&nbsp;`b2ParticleGroupDef pd;`<br/>
&nbsp;&nbsp;&nbsp;`b2PolygonShape shape;`<br/>
&nbsp;&nbsp;&nbsp;`shape.SetAsBox(10, 5);`<br/>
&nbsp;&nbsp;&nbsp;`pd.shape = &shape;`<br/>
&nbsp;&nbsp;&nbsp;`pd.flags = b2_elasticParticle;`<br/>
&nbsp;&nbsp;&nbsp;`pd.angle = -0.5f;`<br/>
&nbsp;&nbsp;&nbsp;`pd.angularVelocity = 2.0f;`<br/>
&nbsp;&nbsp;&nbsp;`for (int32 i = 0; i < 5; i++)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`pd.position.Set(10 + 20 * i, 40);`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`pd.color.Set(i * 255 / 5, 255 - i * 255 /
5, 128, 255);`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
`m_particleSystem->CreateParticleGroup(pd);`<br/>
&nbsp;&nbsp;&nbsp;`}`<br/>
To destroy a particles in a group, invoke the function
&nbsp;&nbsp;&nbsp;`DestroyParticles(bool callDestructionListener);`<br/>
Groups are automatically destroyed when they contain no particles if the
`b2_particleGroupCanBeEmpty` is not set in the group's flags.
The following example destroys all particle groups in the particle system.
<pre>
b2ParticleGroup* group = m_particleSystem->GetParticleGroupList();
while (group)
{
m_particleSystem->SetGroupFlags(
m_particleSystem->GetGroupFlags() & ~b2_particleGroupCanBeEmpty);
group->DestroyParticles(false);
// The destruction of particle groups are deferred to the next call of
// Step() so it's safe to reference the group here.
group = group->GetNext();
}
</pre>
The next several sections provide more information on how to define particle
behaviors and properties.
<a name="pb">
## Particle Behaviors
Particle behaviors are defined either for entire groups of, or individual,
particles.
For a group of particles, use the `b2ParticleGroupFlag` enum, which provides
two types of particle groups:
###Solid
A solid particle group prevents other bodies from lodging inside of it. Should
anything penetrate it, the solid particle group pushes the offending body back
out to its surface.
A solid particle group also possesses an especially strong repulsive force. It
is useful, for example, in a case where:
* Something should be expected to bounce with unusual vigor
** As when a racquetball strikes the wall of a court
Use the `b2_SolidParticleGroup` flag of the `b2ParticleGroupFlag` enum to
specify a solid particle group. For example:
&nbsp;&nbsp;&nbsp;`pd.groupFlags = b2_solidParticleGroup;`
###Rigid
Rigid particle groups are ones whose shape does not change, even when they
collide
with other bodies. Working with rigid particle groups confers a few advantages
over simply
working with rigid bodies: With a rigid particle group, you can:<br/>
* Delete part of the group (i.e., some of its particles).
* For example, firing a bullet that leaves a hole in a box-shaped group of
particles.
* Merge it with other groups.
* For example, creating a snowman from three round particle groups, and
then merging them into a single particle group.
Use the `b2_rigidParticleGroup` flag of the `b2ParticleGroupFlag` enum to
specify a rigid particle group. For example:
&nbsp;&nbsp;&nbsp;`pd.groupFlags = b2_rigidParticleGroup;`
For individual particles, use the b2ParticleFlag enum. The b2ParticleFlag enum
provides the flags described in the following sections. Note that different
particle behaviors may exact different performance costs.
### Elastic
Elastic particles deform and may also bounce when they collide with rigid
bodies.<br/>
Set particle behavior as elastic using the statement
&nbsp;&nbsp;&nbsp;`pd.flags = b2_elasticParticle;`
The green circle and the blue box in the "Elastic Particles" demo of the
Testbed application comprise elastic particles.
### Color-mixing
Color-mixing particles take on some of the color of other particles with which
they collide. If only one of the two colliding particles is a color-mixing
one,
the other particle retains its pre-collision color.<br/>
<br/>
The following example shows how color mixture is calculated. It shows the
collision of two color-mixing particles: one red ("R") and one green ("G").
1. First, the system calculates deltaColor, which is the value by which each
color will change.
deltaColor = colorMixingStrength * (B's color - A's color).<br/>
= 0.5 * ((0,255,0,255) - (255,0,0,255))<br/>
= 0.5 * (-255,255,0,0)<br/>
= (-127.5,127.5,0,0)
2. Then, it applies the delta to each particle
R's color += deltaColor<br/>
G's color -= deltaColor
3. As a result, both particles are now yellow:
A's color = (127.5,127.5,0,255)<br/>
B's color = (127.5,127.5,0,255)<br/>
<br/>
Note that when one of the operations in step 2 results in a negative number,
the
system uses the absolute value of that number. When it results in a value over
255, it rolls over from zero.<br/>
Set particle behavior as color-mixing using the statement<br/>
&nbsp;&nbsp;&nbsp;`pd.flags = b2_colorMixingParticle;`
The "Surface Tension" demo of the Testbed application uses color-mixing
particles.
### Powder
Powder particles produce a scattering effect such as you might see with sand
or
dust.<br/>
Set particle behavior as powder using the statement<br/>
&nbsp;&nbsp;&nbsp;`pd.flags = b2_powderParticle;`
The "Sparky" demo of the Testbed application uses powder particles.
### Spring
Spring particles produce the effect of being attached to one another, as by a
spring. Particles are "connected" in pairs. Each particle is connected to the
one that was closest to it at time of creation. Once paired, particles do not
change "partners." The farther an external force pulls them from one another,
the greater the power with which they collide when that external force is
removed. No matter how far particles get from one another, the connection
between them does not "snap."<br/>
Set spring behavior using the statement<br/>
&nbsp;&nbsp;&nbsp;`pd.flags = b2_springParticle;`
The red circle in the "Elastic Particles" demo of the Testbed application
comprises spring particles.
### Tensile
Tensile particles are used to produce the effect of surface tension, or the
taut
curvature on the surface of a body of liquid. They might be used, for example,
to create the surface tension you would see on a drop of water.<br/>
Once the tension is broken, the particles bounce as if they were elastic, but
also continue to attract each other. As a result, particles tend to form
clusters as they bounce.<br/>
Set tensile behavior using the statement
&nbsp;&nbsp;&nbsp;`pd.flags = b2_tensileParticle;`
The "Surface Tension" demo of the Testbed application uses tensile particles.
### Viscous
Viscous particles exhibit clinginess or stickiness, like oil.<br/>
Set viscous behavior using the statement
&nbsp;&nbsp;&nbsp;`pd.flags = b2_viscousParticle;`
The "Liquid Timer" demo of the Testbed application uses viscous particles.
### Static Pressure
Particles are subject to compression when pressure acts upon them. For example,
when particles pour into a container, the ones at the bottom of the container
are "crushed" under the weight of those above them and packed more tightly
together than the ones at the top of the pile.
The static-pressure particle eliminates this differential; the same amount of
pressure acts upon each particle in the group.
The following example sets static-pressure behavior.
&nbsp;&nbsp;&nbsp;`pd.flags = b2_staticPressureParticle;`
### Wall
Wall particles are static. They are permanently stationary, even if something
collides with them. <br/>
Set wall behavior using the statement
&nbsp;&nbsp;&nbsp;`pd.flags = b2_wallParticle;`
### Barrier
Solid or rigid particle groups are not inherently tunneling-proof. Particles
traveling at high enough velocities may penetrate them. Barrier particles,
used in conjunction with other particle types, provide particle groups
with protection against tunneling. This functionality is useful when, for
example, you want to ensure that liquid particles will not leak out of a
container formed of wall particles.
Barrier particles only prevent penetration of the particle groups they inhabit.
They cannot prevent particles from getting between groups of particles, even if
the groups' positions make them look as if they are contiguous.
You can use barrier particles with elastic, spring, or wall particles.
The following example creates an impermeable group of wall particles:
&nbsp;&nbsp;&nbsp;`pd.flags = b2_wallParticle | b_barrierParticle;`
&nbsp;&nbsp;&nbsp;`pd.groupFlags = b2_solidParticleGroup;`
### Zombie
Zombie particles are useful when you want efficiently to destroy multiple
particles in a single step. All of the particles that you designate as zombies
are destroyed at the same time, in a single iteration of the solver.
Destroying
particles in a batch, after designating them as zombies, yields better
performance than destroying them one by one: Whereas destroying particles
one-by-one takes (number of parti`cles) * (time per particle) to complete,
destroying them all in a batch takes the same time as it would to destroy a
single particle.<br/>
In the following example, every other particle in a group is designated as a
zombie, and will be destroyed in the next step of the solver. (For more
information on the LiquidFun solver, see Chapter 1. Introduction.)
&nbsp;&nbsp;&nbsp;`b2ParticleGroup*group=
m_particleSystem->CreateParticleGroup(pd);`<br/>
&nbsp;&nbsp;&nbsp;`for (int32 i=0;i<group->GetParticleCount();i+=2)`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`group->GetFlagsBuffer()[i] |=`
`b2_zombieParticle;`<br/>
&nbsp;&nbsp;&nbsp;`}`
Note that you can assign multiple behaviors to a group or particle. Use
the | ("bitwise OR") operator to chain behavior flags. For example, for a group:
&nbsp;&nbsp;&nbsp;`pd.groupFlags = b2_solidParticleGroup |
b2_rigidParticleGroup;`
And for particles:
&nbsp;&nbsp;&nbsp;`pd.flags = b2_elasticParticle | b2_viscousParticle;`
To define a group combining a specific group behavior with a specific particle
behavior, use two statements. For example:
&nbsp;&nbsp;&nbsp;`pd.flags = b2_elasticParticle;`<br/>
&nbsp;&nbsp;&nbsp;`pd.groupFlags = b2_solidParticleGroup;`<br/>
<a name="pp">
## Particle Properties
### Color
Set particle or particle-group color using the statement
&nbsp;&nbsp;&nbsp;`pd.color.Set(r, g, b, a);`
whose parameters set red, green, blue, and opacity, respectively. Each
parameter takes a value of 0-255.
### Size
There are two points to keep in mind when using small particles. First, in the
case of particle groups, particle size can affect performance. This is
because particle size is inversely proportional to the number of particles
generated to constitute a group. Having a large number of particles, in turn,
can diminish performance.
Set particle size using the statement
&nbsp;&nbsp;&nbsp;`m_particleSystem->SetRadius(r);`
where `r` is a float32 value greater than 0.0f. Default particle radius is
1.0f.
Small particles may also behave unpredictably (i.e., break conservation of
momentum) in scenarios such as explosions. Slowing these particles down by
reducing gravity scale can stabilize their behavior.
Set gravity scale using the statement
&nbsp;&nbsp;&nbsp;`m_particleSystem->SetGravityScale(g);`
where `g` is a `float32` value greater than 0.0f. Default gravity scale is
1.0f.
It is worth noting that adjusting the number of particle iterations per solver
step can also affect the effect of gravity on particles. Larger iteration sizes
confer greater resistance to gravity. A common reason for increasing the number
of particle-iterations is to prevent volume loss (i.e. compression) due to
gravity.
### Position
Set particle or particle-group position using the statement
&nbsp;&nbsp;&nbsp;`pd.position.Set(x, y);`
where `x` and `y` are the world-coordinates of the translation of the
particle
group.
### Velocity
For discrete particles, set velocity using the statement
&nbsp;&nbsp;&nbsp;`pd.velocity.Set(x,y);`
where `x` is velocity along the x-axis, and `y` is velocity along the
y-axis.<br/>
For particle groups, set velocity using the statements
&nbsp;&nbsp;&nbsp;`pd.linearVelocity.Set(x,y);`<br/>
&nbsp;&nbsp;&nbsp;`pd.angularVelocity = aV;`<br/>
where `x` is the group's velocity along the x-axis, `y` is velocity along the
y-axis, and `aV` is the group's angular (i.e., rotational) velocity (expressed
as radians per second).
### Angle (Groups Only)
This property applies only to rigid particle groups. It indicates the angle at
which a group is tilted. Set angle with the statement
&nbsp;&nbsp;&nbsp;`pd.angle =checkout a;`
where `a` is the angle of tilt, expressed in radians. Left unspecified, the
value defaults to 0.
### Strength (Groups Only)
Strength describes the cohesion of a group of particles. Set strength with the
statement
&nbsp;&nbsp;&nbsp;`pd.strength = s;`<br/>
where `s` is a float32 value between 0.0 (least cohesive) and 1.0 (most
cohesive). The default value is 1.0.
<a name="gl">
## Rendering with OpenGL
The Particle module provides particularly efficient rendering via OpenGL.
Each type of particle property lives in a contiguous memory buffer. For
example,
all particles' position data live next door to one another, all color data
live
next door to one another, and so forth. Table 1 provides a visual
representation
of this storage.
**_Table 1. Memory Map of Particle Buffers_**
<table>
<tr>
<td></td>
<td>Particle 1</td>
<td>Particle 2</td>
<td>Particle 3</td>
</tr>
<tr>
<td>Position</td>
<td>x1,y1</td>
<td>x2,y2</td>
<td>x3,y3</td>
</tr>
<tr>
<td>Address</td>
<td>0x00001000</td>
<td>0x00001008</td>
<td>0x00001010</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Color</td>
<td>r1,g1,b1,a1</td>
<td>r2,g2,b2,a2</td>
<td>r3,g3,b3,a3</td>
</tr>
<tr>
<td>Address</td>
<td>0x00002000</td>
<td>0x00002004</td>
<td>0x00002008</td>
</tr>
</table>
OpenGL can use these buffers directly in rendering.<br/>
In this example, OpenGL 1.1 would use glVertexPointer and glColorPointer to
get
the values from memory. OpenGL 2.0 would use glVertexAttribPointer.<br/>
OpenGL can be used to render either individual particles or particle groups.
<a name="sa">
## Sample Applications
Among the samples included in the LiquidFun distribution are two applications
that offer a quick look into the capabilities of the library.
Testbed includes a large number of demos that provide examples of different
types of particle behavior. While some of the demos are "look only," others are
interactive, allowing you to use your mouse or touchscreen to affect the
behavior on screen.
Experimenting with each of the demos, and comparing their behavior against the
source code, can provide useful insights into how different particles behave
under various conditions. Testbed builds and runs on Android, MacOSX, Linux,
and Windows.
EyeCandy is an Android-only application and is twofold in purpose: It provides
a simple Android example of how to use LiquidFun; and, it seeks to inspire
developers with its demonstration of the powerful liquid shaders it brings to
mobile hardware.
When running the program, you can slosh the fluid around by changing the
orientation of the Android device. You can also toggle bewteen shaders by
tapping the screen.
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,178 @@
# Loose Ends
[User Data](#ud)<br/>
[Implicit Destruction](#id)<br/>
[Pixels and Coordinate Systems](#pcs)<br/>
<a name="ud"></a>
## User Data
The b2Fixture, b2Body, and b2Joint classes allow you to attach user data as a
void pointer. This is handy when you are examining LiquidFun data structures
and you want to determine how they relate to the objects in your game engine.
For example, it is typical to attach an actor pointer to the rigid body on
that actor. This sets up a circular reference. If you have the actor, you can
get the body. If you have the body, you can get the actor.
&nbsp;&nbsp;&nbsp;`GameActor* actor = GameCreateActor();`<br/>
&nbsp;&nbsp;&nbsp;`b2BodyDef bodyDef;`<br/>
&nbsp;&nbsp;&nbsp;`bodyDef.userData = actor;`<br/>
&nbsp;&nbsp;&nbsp;`actor->body = box2Dworld->CreateBody(&bodyDef);`<br/>
Here are some examples of cases where you would need the user data:
* Applying damage to an actor using a collision result.
* Playing a scripted event if the player is inside an axis-aligned box.
* Accessing a game structure when LiquidFun notifies you that a joint is going
to be destroyed.
Keep in mind that user data is optional and you can put anything in it.
However, you should be consistent. For example, if you want to store an actor
pointer on one body, you should keep an actor pointer on all bodies. Don't
store an actor pointer on one body, and a foo pointer on another body. Casting
an actor pointer to a foo pointer may lead to a crash.
User data pointers are NULL by default.
For fixtures you might consider defining a user data structure that lets you
store game specific information, such as material type, effects hooks, sound
hooks, etc.
&nbsp;&nbsp;&nbsp;`struct FixtureUserData`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;` int materialIndex;`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;` . . .`<br/>
&nbsp;&nbsp;&nbsp;`};`<br/>
&nbsp;&nbsp;&nbsp;`FixtureUserData myData = new FixtureUserData;`<br/>
&nbsp;&nbsp;&nbsp;`myData->materialIndex = 2;`<br/>
&nbsp;&nbsp;&nbsp;`b2FixtureDef fixtureDef;`<br/>
&nbsp;&nbsp;&nbsp;`fixtureDef.shape = &someShape;`<br/>
&nbsp;&nbsp;&nbsp;`fixtureDef.userData = myData;`<br/>
&nbsp;&nbsp;&nbsp;`b2Fixture* fixture = body->CreateFixture(&fixtureDef);`<br/>
&nbsp;&nbsp;&nbsp;`. . .`<br/>
&nbsp;&nbsp;&nbsp;`delete fixture->GetUserData();`<br/>
&nbsp;&nbsp;&nbsp;`fixture->SetUserData(NULL);`<br/>
&nbsp;&nbsp;&nbsp;`body->DestroyFixture(fixture);`<br/>
<a name="id"></a>
## Implicit Destruction
LiquidFun doesn't use reference counting. So if you destroy a body it is
really gone. Accessing a pointer to a destroyed body has undefined behavior.
In other words, your program will likely crash and burn. To help fix these
problems, the debug build memory manager fills destroyed entities with
FDFDFDFD. This can help find problems more easily in some cases.
If you destroy a LiquidFun entity, it is up to you to make sure you remove all
references to the destroyed object. This is easy if you only have a single
reference to the entity. If you have multiple references, you might consider
implementing a handle class to wrap the raw pointer.
Often when using LiquidFun you will create and destroy many bodies, shapes,
and joints. Managing these entities is somewhat automated by LiquidFun. If you
destroy a body then all associated shapes and joints are automatically
destroyed. This is called implicit destruction.
When you destroy a body, all its attached shapes, joints, and contacts are
destroyed. This is called implicit destruction. Any body connected to one of
those joints and/or contacts is woken. This process is usually convenient.
However, you must be aware of one crucial issue:
Caution
When a body is destroyed, all fixtures and joints attached to the body
are automatically destroyed. You must nullify any pointers you have to those
shapes and joints. Otherwise, your program will die horribly if you try to
access or destroy those shapes or joints later.
To help you nullify your joint pointers, LiquidFun provides a listener class
named b2DestructionListener that you can implement and provide to your world
object. Then the world object will notify you when a joint is going to be
implicitly destroyed
Note that there no notification when a joint or fixture is explicitly
destroyed. In this case ownership is clear and you can perform the necessary
cleanup on the spot. If you like, you can call your own implementation of
b2DestructionListener to keep cleanup code centralized.
Implicit destruction is a great convenience in many cases. It can also make
your program fall apart. You may store pointers to shapes and joints somewhere
in your code. These pointers become orphaned when an associated body is
destroyed. The situation becomes worse when you consider that joints are often
created by a part of the code unrelated to management of the associated body.
For example, the testbed creates a b2MouseJoint for interactive manipulation
of bodies on the screen.
LiquidFun provides a callback mechanism to inform your application when
implicit destruction occurs. This gives your application a chance to nullify
the orphaned pointers. This callback mechanism is described later in this
manual.
You can implement a b2DestructionListener that allows b2World to inform you
when a shape or joint is implicitly destroyed because an associated body was
destroyed. This will help prevent your code from accessing orphaned pointers.
&nbsp;&nbsp;&nbsp;`class MyDestructionListener : public
b2DestructionListener`<br/>
&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`void SayGoodbye(b2Joint* joint)`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`{`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`// remove all
references to joint.`<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`}`<br/>
&nbsp;&nbsp;&nbsp;`};`<br/>
You can then register an instance of your destruction listener with your world
object. You should do this during world initialization.
&nbsp;&nbsp;&nbsp;`myWorld->SetListener(myDestructionListener);`
<a name="pcs"></a>
## Pixels and Coordinate Systems
Recall that LiquidFun uses MKS (meters, kilograms, and seconds) units and
radians for angles. You may have trouble working with meters because your game
is expressed in terms of pixels. To deal with this in the testbed I have the
whole *game* work in meters and just use an OpenGL viewport transformation to
scale the world into screen space.
&nbsp;&nbsp;&nbsp;`float lowerX = -25.0f, upperX = 25.0f, lowerY = -5.0f,
upperY = 25.0f;`<br/>
&nbsp;&nbsp;&nbsp;`gluOrtho2D(lowerX, upperX, lowerY, upperY);`<br/>
If your game must work in pixel units then you should convert your length
units from pixels to meters when passing values from LiquidFun. Likewise you
should convert the values received from LiquidFun from meters to pixels. This
will improve the stability of the physics simulation.
You have to come up with a reasonable conversion factor. I suggest making this
choice based on the size of your characters. Suppose you have determined to
use 50 pixels per meter (because your character is 75 pixels tall). Then you
can convert from pixels to meters using these formulas:
&nbsp;&nbsp;&nbsp;`xMeters = 0.02f * xPixels;`<br/>
&nbsp;&nbsp;&nbsp;`yMeters = 0.02f * yPixels;`<br/>
In reverse:
&nbsp;&nbsp;&nbsp;`xPixels = 50.0f * xMeters;`<br/>
&nbsp;&nbsp;&nbsp;`yPixels = 50.0f * yMeters;`<br/>
You should consider using MKS units in your game code and just convert to
pixels when you render. This will simplify your game logic and reduce the
chance for errors since the rendering conversion can be isolated to a small
amount of code.
If you use a conversion factor, you should try tweaking it globally to make
sure nothing breaks. You can also try adjusting it to improve stability.
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,28 @@
# Debug Drawing
You can implement the b2DebugDraw class to get detailed drawing of the physics
world. Here are the available entities:
* shape outlines
* joint connectivity
* broad-phase axis-aligned bounding boxes (AABBs)
* center of mass
<img align="center" src="image_24.png" alt="Debug drawing" height="306"
width="431"><br/>
This is the preferred method of drawing these physics entities, rather than
accessing the data directly. The reason is that much of the necessary data is
internal and subject to change.
The testbed draws physics entities using the debug draw facility and the
contact listener, so it serves as the primary example of how to implement
debug drawing as well as how to draw contact points.
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,33 @@
## Limitations
LiquidFun uses several approximations to simulate rigid body physics
efficiently. This brings some limitations.
Here are the current limitations:
1. Stacking heavy bodies on top of much lighter bodies is not stable.
Stability degrades as the mass ratio passes 10:1.
2. Chains of bodies connected by joints may stretch if a lighter body is
supporting a heavier body. For example, a wrecking ball connect to a chain of
light weight bodies may not be stable. Stability degrades as the mass ratio
passes 10:1.
3. There is typically around 0.5cm of slop in shape versus shape collision.
4. Continuous collision does not handle joints. So you may see joint
stretching on fast moving objects.
5. LiquidFun uses the symplectic Euler integration scheme. It does not
reproduce parabolic motion of projectiles and has only first-order accuracy.
However it is fast and has good stability.
6. LiquidFun uses an iterative solver to provide real-time performance. You
will not get precisely rigid collisions or pixel perfect accuracy. Increasing
the iterations will improve accuracy.
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,13 @@
# References
Erin Catto's GDC Tutorials:<br/>
[http://code.google.com/p/box2d/downloads/list](http://code.google.com/p/box2d/downloads/list)<br/>
_Collision Detection in Interactive 3D Environments,_ Gino van den Bergen,
2004<br/>
_Real-Time Collision Detection,_ Christer Ericson, 2005
*This content is licensed under
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
For details and restrictions, please see the
[Content License](md__content_license.html).*
@@ -0,0 +1,11 @@
# Content License
Portions of this documentation are modifications based on work
created and shared by Erin Catto and used according to terms
described in the
[Creative Commons 4.0 Attribution License](http://creativecommons.org/licenses/by/4.0/legalcode)
Copyright © 2007-2011 Erin Catto
Copyright © 2013-2014 Fun Propulsion Labs at Google
@@ -0,0 +1,17 @@
# Logo
Please feel free to make fair use the LiquidFun logo in connection with any
implementations (in your splash screens or documentation, for example).
There is no requirement to include the logo, but we appreciate your
acknowledgement. We only ask that you avoid changing the proportions of the
logo or otherwise modifying it, and that you avoid using the logo in a way
that suggests your implementation is developed by, sponsored by, or affiliated
with Fun Propulsion Labs or Google. (For example, you shouldn't use the
LiquidFun logo as your app icon, and you shouldn't use it more prominently
than your own logos or icons.)
![LiquidFun Logo bitmap](liquidfun-logo-small.png)
* [Logo in bitmap format](liquidfun-logo.png)
* [Logo in vector format](liquidfun-logo.ai)
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB