7#include <box3d/box3d.h>
15b3BodyType parseBodyType(
const std::string &
type) {
16 if (
type ==
"static")
return b3_staticBody;
17 if (
type ==
"kinematic")
return b3_kinematicBody;
18 if (
type ==
"dynamic")
return b3_dynamicBody;
22const char *bodyTypeName(b3BodyType t) {
24 case b3_staticBody:
return "static";
25 case b3_kinematicBody:
return "kinematic";
26 case b3_dynamicBody:
return "dynamic";
27 default:
return "static";
31b3ShapeDef makeShapeDef(
float density,
float friction,
float restitution) {
32 b3ShapeDef def = b3DefaultShapeDef();
33 def.density = density;
34 def.baseMaterial.friction = friction;
35 def.baseMaterial.restitution = restitution;
36 def.enableContactEvents =
true;
37 def.enableSensorEvents =
true;
44 : world_(world), bodyId_(bodyId), id_(
id) {}
49 std::vector<Shape3D *> shapes(world_->shapes_.begin(), world_->shapes_.end());
51 if (
s &&
s->getBody() ==
this) {
56 b3Body_SetUserData(bodyId_,
nullptr);
57 b3DestroyBody(bodyId_);
67 if (
isValid()) b3Body_SetUserData(bodyId_,
nullptr);
77 std::vector<Shape3D *> shapes(world_->shapes_.begin(), world_->shapes_.end());
79 if (
s &&
s->getBody() ==
this) {
82 if (
s->isValid()) b3DestroyShape(
s->raw(),
false);
86 b3Body_SetUserData(bodyId_,
nullptr);
87 b3DestroyBody(bodyId_);
95 b3Body_SetTransform(bodyId_, b3Pos{
x,
y,
z}, b3Body_GetRotation(bodyId_));
100 return static_cast<float>(b3Body_GetPosition(bodyId_).x);
105 return static_cast<float>(b3Body_GetPosition(bodyId_).y);
110 return static_cast<float>(b3Body_GetPosition(bodyId_).z);
116 q.v = b3Vec3{qx, qy, qz};
118 float len = std::sqrt(qx * qx + qy * qy + qz * qz + qw * qw);
127 b3Body_SetTransform(bodyId_, b3Body_GetPosition(bodyId_), q);
132 return b3Body_GetRotation(bodyId_).v.x;
137 return b3Body_GetRotation(bodyId_).v.y;
142 return b3Body_GetRotation(bodyId_).v.z;
147 return b3Body_GetRotation(bodyId_).s;
152 b3Body_SetLinearVelocity(bodyId_, b3Vec3{vx, vy, vz});
157 return b3Body_GetLinearVelocity(bodyId_).x;
162 return b3Body_GetLinearVelocity(bodyId_).y;
167 return b3Body_GetLinearVelocity(bodyId_).z;
172 b3Body_SetAngularVelocity(bodyId_, b3Vec3{wx, wy, wz});
177 return b3Body_GetAngularVelocity(bodyId_).x;
182 return b3Body_GetAngularVelocity(bodyId_).y;
187 return b3Body_GetAngularVelocity(bodyId_).z;
192 b3Body_ApplyForceToCenter(bodyId_, b3Vec3{fx, fy, fz},
true);
197 b3Body_ApplyForce(bodyId_, b3Vec3{fx, fy, fz}, b3Pos{
x,
y,
z},
true);
202 b3Body_ApplyLinearImpulseToCenter(bodyId_, b3Vec3{ix, iy, iz},
true);
207 b3Body_ApplyAngularImpulse(bodyId_, b3Vec3{ix, iy, iz},
true);
212 b3Body_SetType(bodyId_, parseBodyType(bodyType));
216 if (!
isValid())
return "static";
217 return bodyTypeName(b3Body_GetType(bodyId_));
222 b3MotionLocks locks = b3Body_GetMotionLocks(bodyId_);
223 locks.angularX = fixed;
224 locks.angularY = fixed;
225 locks.angularZ = fixed;
226 b3Body_SetMotionLocks(bodyId_, locks);
231 b3MotionLocks locks = b3Body_GetMotionLocks(bodyId_);
232 return locks.angularX && locks.angularY && locks.angularZ;
238 b3Body_Enable(bodyId_);
240 b3Body_Disable(bodyId_);
247 b3Body_SetBullet(bodyId_, bullet);
254 b3Body_SetAwake(bodyId_, awake);
260 float friction,
float restitution) {
263 throw eve::Exception(
"Body3D.newBoxShape: width/height/depth must be > 0");
265 float hx =
width * 0.5f;
267 float hz =
depth * 0.5f;
269 b3BoxHull box = b3MakeBoxHull(hx, hy, hz);
270 b3ShapeDef def = makeShapeDef(density, friction, restitution);
271 b3ShapeId
id = b3CreateHullShape(bodyId_, &def, &box.base);
274 b3Shape_SetUserData(
id, shape);
275 world_->shapes_.insert(shape);
281 if (radius <= 0.f)
throw eve::Exception(
"Body3D.newSphereShape: radius must be > 0");
284 sphere.center = b3Vec3_zero;
285 sphere.radius = radius;
287 b3ShapeDef def = makeShapeDef(density, friction, restitution);
288 b3ShapeId
id = b3CreateSphereShape(bodyId_, &def, &sphere);
291 b3Shape_SetUserData(
id, shape);
292 world_->shapes_.insert(shape);
299 if (
height < 0.f || radius <= 0.f)
300 throw eve::Exception(
"Body3D.newCapsuleShape: height >= 0 and radius > 0 required");
302 float half =
height * 0.5f;
304 capsule.center1 = b3Vec3{0.f, -half, 0.f};
305 capsule.center2 = b3Vec3{0.f, half, 0.f};
306 capsule.radius = radius;
308 b3ShapeDef def = makeShapeDef(density, friction, restitution);
309 b3ShapeId
id = b3CreateCapsuleShape(bodyId_, &def, &capsule);
312 b3Shape_SetUserData(
id, shape);
313 world_->shapes_.insert(shape);
void setActive(bool active)
Disables/enables the body and its shapes.
void setRotation(float qx, float qy, float qz, float qw)
Orientation as quaternion (x, y, z, w).
void applyForce(float fx, float fy, float fz)
Force applied at the center of mass.
float getLinearVelocityY() const
void applyLinearImpulse(float ix, float iy, float iz)
Instantaneous linear impulse.
void setFixedRotation(bool fixed)
Lock all angular axes (Box3D motion locks).
Body3D(World3D *world, b3BodyId bodyId, int id)
Internal: wraps a Box3D body (use World3D::newBody).
void applyAngularImpulse(float ix, float iy, float iz)
Instantaneous angular impulse.
bool isFixedRotation() const
void setBullet(bool bullet)
CCD bullet mode.
Shape3D * newBoxShape(float width, float height, float depth, float density=1.f, float friction=0.2f, float restitution=0.f)
Box extents are full width/height/depth in meters (same convention as Body.newRectangleFixture)....
bool isValid() const
True while the underlying Box3D body is still alive.
void setAwake(bool awake)
Wakes / sleeps the body manually.
void destroy()
Destroys the body inside its world.
float getAngularVelocityZ() const
void invalidate()
Internal: marks the wrapper invalid after world destruction.
float getAngularVelocityX() const
std::string getType() const
void applyForceAt(float fx, float fy, float fz, float x, float y, float z)
Force applied at a world position.
Shape3D * newCapsuleShape(float height, float radius, float density=1.f, float friction=0.2f, float restitution=0.f)
Capsule along local Y; height is distance between hemisphere centers.
void setLinearVelocity(float vx, float vy, float vz)
Linear velocity in m/s.
void setPosition(float x, float y, float z)
Position in meters.
void setType(const std::string &bodyType)
"static" | "kinematic" | "dynamic".
float getLinearVelocityZ() const
void setAngularVelocity(float wx, float wy, float wz)
Angular velocity in rad/s.
float getAngularVelocityY() const
Shape3D * newSphereShape(float radius, float density=1.f, float friction=0.2f, float restitution=0.f)
float getLinearVelocityX() const
3D shape (box/sphere/capsule) attached to a Body3D with material settings. Created via Body3D::new*Sh...
Box3D rigid-body world. Script coordinates are meters (Box3D native), unlike 2D World which uses pixe...
void forgetBody(Body3D *body)
Internal: wrapper teardown bookkeeping.
bool isValid() const
True while the underlying Box3D world is alive.
void forgetShape(Shape3D *shape)