1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
# Loose Ends
## User Data
The `b2Fixture`, `b2Body`, and `b2Joint` classes allow you to attach user data
as a uintptr_t. This is handy when you are examining Box2D 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.
```cpp
GameActor* actor = GameCreateActor();
b2BodyDef bodyDef;
bodyDef.userData.pointer = reinterpret_cast<uintptr_t>(actor);
actor->body = myWorld->CreateBody(&bodyDef);
```
You can also use this to hold an integral value rather than a pointer.
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 Box2D 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 0 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.
```cpp
struct FixtureUserData
{
int materialIndex;
// ...
};
FixtureUserData myData = new FixtureUserData;
myData->materialIndex = 2;
b2FixtureDef fixtureDef;
fixtureDef.shape = &someShape;
fixtureDef.userData.pointer = reinterpret_cast<uintptr_t>(myData);
b2Fixture* fixture = body->CreateFixture(&fixtureDef);
// ...
delete fixture->GetUserData();
body->DestroyFixture(fixture);
```
## Custom User Data
You can define custom data structures that are embedded in the Box2D data
structures. This is done by defining `B2_USER_SETTINGS` and providing the
file `b2_user_settings.h`. See `b2_settings.h` for details.
## Implicit Destruction
Box2D 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 Box2D 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 Box2D you will create and destroy many bodies, shapes,
and joints. Managing these entities is somewhat automated by Box2D. 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, Box2D 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.
Box2D 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.
```cpp
class MyDestructionListener : public b2DestructionListener
{
void SayGoodbye(b2Joint* joint)
{
// remove all references to joint.
}
};
```
You can then register an instance of your destruction listener with your
world object. You should do this during world initialization.
```cpp
myWorld->SetListener(myDestructionListener);
```
## Pixels and Coordinate Systems
Recall that Box2D 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.
```cpp
float lowerX = -25.0f, upperX = 25.0f, lowerY = -5.0f, upperY = 25.0f;
gluOrtho2D(lowerX, upperX, lowerY, upperY);
```
If your game must work in pixel units then you should convert your
length units from pixels to meters when passing values from Box2D.
Likewise you should convert the values received from Box2D 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:
```cpp
xMeters = 0.02f * xPixels;
yMeters = 0.02f * yPixels;
```
In reverse:
```cpp
xPixels = 50.0f * xMeters;
yPixels = 50.0f * yMeters;
```
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.
## 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

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.
## Limitations
Box2D 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. Box2D 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. Box2D 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.
|