8 #include <unordered_set>
10 #include <reactphysics3d/utils/DefaultLogger.h>
12 #include <reactphysics3d/collision/shapes/AABB.h>
13 #include <reactphysics3d/collision/ContactManifold.h>
14 #include <reactphysics3d/collision/OverlapCallback.h>
15 #include <reactphysics3d/collision/RaycastInfo.h>
16 #include <reactphysics3d/constraint/ContactPoint.h>
17 #include <reactphysics3d/constraint/FixedJoint.h>
18 #include <reactphysics3d/constraint/Joint.h>
19 #include <reactphysics3d/engine/PhysicsWorld.h>
20 #include <reactphysics3d/engine/EventListener.h>
21 #include <reactphysics3d/mathematics/Ray.h>
22 #include <reactphysics3d/mathematics/Vector3.h>
47 using std::make_unique;
52 using std::unordered_set;
76 World::World(
const string&
id)
79 reactphysics3d::PhysicsWorld::WorldSettings worldSettings;
80 worldSettings.worldName = id;
98 vector<string> jointIds;
99 for (
const auto& [jointId, joint]:
jointsById) jointIds.push_back(jointId);
100 for (
const auto& jointId: jointIds)
removeJoint(jointId);
105 for (
auto body: _bodies)
removeBody(body->getId());
110 Body*
World::addRigidBody(
const string&
id, uint16_t collisionTypeId,
bool enabled,
const Transform& transform,
float restitution,
float friction,
float mass,
const Vector3& inertiaTensor,
const vector<BoundingVolume*>& boundingVolumes,
bool hierarchy)
117 new Body(
this,
id,
Body::BODYTYPE_DYNAMIC, collisionTypeId, enabled, transform, restitution, friction, mass, inertiaTensor, boundingVolumes);
119 if (hierarchy ==
true) {
129 listener->onAddedBody(
id,
Body::BODYTYPE_DYNAMIC, collisionTypeId, enabled, transform, restitution, friction, mass, inertiaTensor, boundingVolumes);
141 new Body(
this,
id,
Body::BODYTYPE_COLLISION_STATIC, collisionTypeId, enabled, transform, 0.0f, 0.0f, 0.0f,
Body::getNoRotationInertiaTensor(), boundingVolumes);
143 if (hierarchy ==
true) {
164 new Body(
this,
id,
Body::BODYTYPE_COLLISION_DYNAMIC, collisionTypeId, enabled, transform, 0.0f, 0.0f, 0.0f,
Body::getNoRotationInertiaTensor(), boundingVolumes);
166 if (hierarchy ==
true) {
188 new Body(
this,
id,
Body::BODYTYPE_STATIC, collisionTypeId, enabled, transform, 0.0f, friction, 0.0f,
Body::getNoRotationInertiaTensor(), boundingVolumes);
190 if (hierarchy ==
true) {
207 if (body ==
nullptr)
return nullptr;
214 auto body = bodyByIdIt->second;
219 listener->onRemovedBody(
id, body->getType(), body->getCollisionTypeId());
229 Console::println(
"World::createFixedJoint(): body1: no rigid body attached");
233 Console::println(
"World::createFixedJoint(): body2: no rigid body attached");
237 reactphysics3d::FixedJointInfo jointInfo(body1->
rigidBody, body2->
rigidBody, reactphysics3d::Vector3(anchorPoint.
getX(), anchorPoint.
getY(), anchorPoint.
getZ()));
238 jointInfo.isCollisionEnabled =
false;
239 jointsById[id] =
dynamic_cast<reactphysics3d::FixedJoint*
>(
world->createJoint(jointInfo));
245 auto joint = jointByIdIt->second;
246 world->destroyJoint(joint);
253 if (deltaTime < Math::EPSILON)
return;
256 world->update(deltaTime);
336 if (body->isEnabled() ==
false) {
340 if (body->isSleeping() ==
true) {
345 const auto& transform = body->rigidBody->getTransform();
346 const auto& transformPosition = transform.getPosition();
347 const auto& transformOrientation = transform.getOrientation();
350 auto& physicsTransform = body->transform;
354 while (physicsTransform.getRotationCount() > 1) {
355 physicsTransform.removeRotation(physicsTransform.getRotationCount() - 1);
357 if (physicsTransform.getRotationCount() < 1) {
358 physicsTransform.addRotation(
Vector3(0.0f, 1.0f, 0.0f), 0.0f);
362 physicsTransform.getRotation(0).fromRotation(
365 transformOrientation.x,
366 transformOrientation.y,
367 transformOrientation.z,
368 transformOrientation.w
373 physicsTransform.setScale(body->transformScale);
375 physicsTransform.setTranslation(
Vector3(transformPosition.x, transformPosition.y, transformPosition.z));
377 physicsTransform.update();
388 if (body->isSleeping() ==
true)
continue;
391 auto entity = engine->
getEntity(body->getId());
392 if (entity ==
nullptr) {
393 Console::println(
"World::entity '" + body->getId() +
"' not found");
398 entity->setEnabled(body->isEnabled());
401 if (body->isEnabled() ==
true) entity->setTransform(body->transform);
409 class CustomCallbackClass :
public reactphysics3d::RaycastCallback {
411 CustomCallbackClass(
float stepUpMax,
const Vector3& point,
float height = 10000.0f): stepUpMax(stepUpMax), point(point), height(height), body(
nullptr) {
413 virtual reactphysics3d::decimal notifyRaycastHit(
const reactphysics3d::RaycastInfo& info) {
414 Vector3 hitPoint(info.worldPoint.x, info.worldPoint.y, info.worldPoint.z);
415 auto _body =
static_cast<Body*
>(info.body->getUserData());
416 if (hitPoint.
getY() < height && hitPoint.
getY() <= point.
getY() + stepUpMax) {
417 height = hitPoint.
getY();
418 body =
static_cast<Body*
>(info.body->getUserData());
420 return reactphysics3d::decimal(info.hitFraction);
434 reactphysics3d::Vector3 startPoint(point.
getX(), maxHeight, point.
getZ());
435 reactphysics3d::Vector3 endPoint(point.
getX(), minHeight, point.
getZ());
436 reactphysics3d::Ray ray(startPoint, endPoint);
437 CustomCallbackClass customCallbackObject(stepUpMax, point, maxHeight);
438 world->raycast(ray, &customCallbackObject, collisionTypeIds);
439 if (customCallbackObject.getBody() !=
nullptr) {
440 heightPoint.
set(point);
441 heightPoint.
setY(customCallbackObject.getHeight());
443 return customCallbackObject.getBody();
451 class CustomCallbackClass :
public reactphysics3d::RaycastCallback {
453 CustomCallbackClass(
const string& actorId): actorId(actorId), body(
nullptr) {
455 virtual reactphysics3d::decimal notifyRaycastHit(
const reactphysics3d::RaycastInfo& info) {
456 auto _body =
static_cast<Body*
>(info.body->getUserData());
457 if (actorId.size() == 0 || _body->getId() != actorId) {
459 hitPoint.
set(info.worldPoint.x, info.worldPoint.y, info.worldPoint.z);
460 return reactphysics3d::decimal(info.hitFraction);
462 return reactphysics3d::decimal(1.0);
476 reactphysics3d::Vector3 startPoint(start.
getX(), start.
getY(), start.
getZ());
477 reactphysics3d::Vector3 endPoint(end.
getX(), end.
getY(), end.
getZ());
478 reactphysics3d::Ray ray(startPoint, endPoint);
479 CustomCallbackClass customCallbackObject(actorId);
480 world->raycast(ray, &customCallbackObject, collisionTypeIds);
481 if (customCallbackObject.getBody() !=
nullptr) {
482 hitPoint.
set(customCallbackObject.getHitPoint());
483 return customCallbackObject.getBody();
491 class CustomOverlapCallback:
public reactphysics3d::OverlapCallback {
493 CustomOverlapCallback(
int collisionTypeIds,
Body* body, vector<Body*>& collisionBodies): collisionTypeIds(collisionTypeIds), body(body), collisionBodies(collisionBodies) {
496 void onOverlap(CallbackData &callbackData) {
497 for (
auto i = 0; i < callbackData.getNbOverlappingPairs(); i++) {
498 auto overlappingPair = callbackData.getOverlappingPair(i);
499 auto body1 =
static_cast<Body*
>(overlappingPair.getBody1()->getUserData());
500 auto body2 =
static_cast<Body*
>(overlappingPair.getBody2()->getUserData());
501 if (body != body1 && ((body1->getCollisionTypeId() & collisionTypeIds) != 0)) collisionBodies.push_back(body1);
502 if (body != body2 && ((body2->getCollisionTypeId() & collisionTypeIds) != 0)) collisionBodies.push_back(body2);
506 int collisionTypeIds;
508 vector<Body*>& collisionBodies;
512 CustomOverlapCallback customOverlapCallback(collisionTypeIds, body, collisionBodies);
516 return collisionBodies.size() > 0;
520 auto collisionBody =
addStaticCollisionBody(
"tdme.world->doescollidewith", 32768,
true, transform, boundingVolumes);
523 return collisionBodies.size() > 0;
532 class CustomCollisionCallback:
public reactphysics3d::CollisionCallback {
537 void onContact(
const CallbackData &callbackData) {
538 for (
auto i = 0; i < callbackData.getNbContactPairs(); i++) {
539 auto contactPair = callbackData.getContactPair(i);
540 auto body1 = contactPair.getBody1();
541 auto body2 = contactPair.getBody2();
542 auto collider1 = contactPair.getCollider1();
543 auto collider2 = contactPair.getCollider2();
544 for (
auto j = 0; j < contactPair.getNbContactPoints(); j++) {
545 auto contactPoint = contactPair.getContactPoint(j);
547 auto entity = collision.
addResponse(-contactPoint.getPenetrationDepth());
548 auto normal = contactPoint.getWorldNormal();
550 auto collider1LocalToWorldTransform1 = collider1->getLocalToWorldTransform();
551 auto collider2LocalToWorldTransform2 = collider2->getLocalToWorldTransform();
552 const auto& localPoint1 = contactPoint.getLocalPointOnCollider1();
553 const auto& localPoint2 = contactPoint.getLocalPointOnCollider2();
554 auto worldPoint1 = collider1LocalToWorldTransform1 * localPoint1;
555 auto worldPoint2 = collider2LocalToWorldTransform2 * localPoint2;
556 entity->addHitPoint(
Vector3(worldPoint1.x, worldPoint1.y, worldPoint1.z));
557 entity->addHitPoint(
Vector3(worldPoint2.x, worldPoint2.y, worldPoint2.z));
566 CustomCollisionCallback customCollisionCallback(collision);
574 auto clonedWorld =
new World(
id);
577 Body* clonedBody =
nullptr;
578 auto bodyType = body->
getType();
581 if ((body->getCollisionTypeId() & collisionTypeIds) == 0)
continue;
586 clonedBody = clonedWorld->addStaticRigidBody(body->id, body->getCollisionTypeId(), body->isEnabled(), body->transform, body->getFriction(), body->boundingVolumes);
589 clonedBody = clonedWorld->addRigidBody(body->id, body->getCollisionTypeId(), body->isEnabled(), body->transform, body->getRestitution(), body->getFriction(), body->getMass(), body->inertiaTensor, body->boundingVolumes);
592 clonedBody = clonedWorld->addStaticCollisionBody(body->id, body->getCollisionTypeId(), body->isEnabled(), body->transform, body->boundingVolumes);
595 clonedBody = clonedWorld->addDynamicCollisionBody(body->id, body->getCollisionTypeId(), body->isEnabled(), body->transform, body->boundingVolumes);
598 Console::println(
"World::clone(): Unsupported type: " + to_string(bodyType));
626 auto clonedBody =
world->getBody(body->id);
627 if (clonedBody ==
nullptr) {
628 Console::println(
"Cloned world::entity '" + body->id +
"' not found");
Entity * getEntity(const string &id)
Returns a entity by given id.
static const Rotation fromQuaternion(const Quaternion &quaternion)
Returns rotation from a quaternion.
void setTransform(const Transform &transform)
Set transform.
uint16_t getCollisionTypeIds()
reactphysics3d::RigidBody * rigidBody
void setMass(float mass)
Set up mass.
void setAngularVelocity(const Vector3 &angularVelocity)
Set angular velocity.
void setEnabled(bool enabled)
Set up if rigid body is enabled.
void setLinearVelocity(const Vector3 &linearVelocity)
Set linear velocity.
const Transform & getTransform()
const Vector3 getAngularVelocity()
void setCollisionTypeIds(uint16_t collisionTypeIds)
Set up collision type ids.
@ BODYTYPE_COLLISION_DYNAMIC
@ BODYTYPE_COLLISION_STATIC
BodyType getType()
Return type, see TYPE_*.
static const Vector3 getNoRotationInertiaTensor()
const Vector3 getLinearVelocity()
Collision response entity.
void setNormal(const Vector3 &normal)
Set normal.
CollisionResponse_Entity * addResponse(float distance)
Adds a collision response entity.
Dynamic physics world class.
BodyHierarchy * getBodyHierarchy(const string &id)
Returns body hierarchy identified by id.
Body * doRayCasting(uint16_t collisionTypeIds, const Vector3 &start, const Vector3 &end, Vector3 &hitPoint, const string &actorId=string())
Do a ray cast from given start to given end point, if there is any body with given collision type in ...
bool doesCollideWith(uint16_t collisionTypeIds, Body *body, vector< Body * > &collisionBodies)
Check if world collides with given body.
bool doCollide(Body *body1, Body *body2)
Check if body 1 collides with body 2.
void removeBody(const string &id)
Removes body identified by id.
reactphysics3d::PhysicsCommon physicsCommon
map< string, reactphysics3d::Joint * > jointsById
map< string, Body * > bodiesById
bool getCollisionResponse(Body *body1, Body *body2, CollisionResponse &collision)
Get collision response.
void synchronize(Body *clonedBody, Body *body)
Synchronize cloned body from body.
void addWorldListener(WorldListener *listener)
Add a world listener.
map< string, BodyCollisionStruct > bodyCollisionsLastFrame
World * clone(const string &id, uint16_t collisionTypeIds=~0)
Clone this world.
Body * getBody(const string &id)
Returns body identified by id.
vector< Body * > rigidBodiesDynamic
void addFixedJoint(const string &id, Body *body1, Body *body2)
Add fixed joint.
Body * addStaticRigidBody(const string &id, uint16_t collisionTypeId, bool enabled, const Transform &transform, float friction, const vector< BoundingVolume * > &boundingVolumes, bool hierarchy=false)
Add a static rigid body.
vector< WorldListener * > worldListeners
Body * addStaticCollisionBody(const string &id, uint16_t collisionTypeId, bool enabled, const Transform &transform, const vector< BoundingVolume * > &boundingVolumes, bool hierarchy=false)
Add a static collision body.
void removeJoint(const string &id)
Remove joint.
reactphysics3d::PhysicsWorld * world
Body * determineHeight(uint16_t collisionTypeIds, float stepUpMax, const Vector3 &point, Vector3 &heightPoint, float minHeight=-10000.0f, float maxHeight=10000.0f)
Determine height on x,y,u while respecting step up max.
void removeWorldListener(WorldListener *listener)
Remove a world listener.
void update(float deltaTime)
Update world.
void reset()
Resets the physic world.
Body * addRigidBody(const string &id, uint16_t collisionTypeId, bool enabled, const Transform &transform, float restitution, float friction, float mass, const Vector3 &inertiaTensor, const vector< BoundingVolume * > &boundingVolumes, bool hierarchy=false)
Add a rigid body.
Body * addDynamicCollisionBody(const string &id, uint16_t collisionTypeId, bool enabled, const Transform &transform, const vector< BoundingVolume * > &boundingVolumes, bool hierarchy=false)
Add a dynamic collision body.
World(const string &id)
Public constructor.
Axis aligned bounding box used for frustum, this is not directly connectable with physics engine.
Bounding volume interface.
Line segment helper functions.
Oriented bounding box physics primitive.
Matrix4x4 class representing matrix4x4 mathematical structure and operations for 3d space.
Quaternion class representing quaternion mathematical structure and operations with x,...
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Vector3 & add(float scalar)
Adds a scalar.
Vector3 & setY(float y)
Sets y component.
Vector3 clone() const
Clones this vector3.
Vector3 & scale(float scalar)
Scales by scalar.
Vector3 & set(float x, float y, float z)
Sets this vector3 by its components.
World listener which is about notifying adding or removing bodies.