7#include <unordered_set>
10#include <ext/reactphysics3d/src/collision/shapes/AABB.h>
11#include <ext/reactphysics3d/src/collision/ContactManifold.h>
12#include <ext/reactphysics3d/src/collision/OverlapCallback.h>
13#include <ext/reactphysics3d/src/collision/RaycastInfo.h>
14#include <ext/reactphysics3d/src/constraint/ContactPoint.h>
15#include <ext/reactphysics3d/src/engine/CollisionWorld.h>
16#include <ext/reactphysics3d/src/engine/DynamicsWorld.h>
17#include <ext/reactphysics3d/src/engine/EventListener.h>
18#include <ext/reactphysics3d/src/mathematics/Ray.h>
19#include <ext/reactphysics3d/src/mathematics/Vector3.h>
44using std::unordered_set;
66World::World(): world(reactphysics3d::
Vector3(0.0, -9.81, 0.0))
79 for (
auto body: _bodies)
removeBody(body->getId());
86Body*
World::addRigidBody(
const string&
id,
bool enabled, uint16_t collisionTypeId,
const Transformations& transformations,
float restitution,
float friction,
float mass,
const Vector3& inertiaTensor, vector<BoundingVolume*> boundingVolumes)
89 auto body =
new Body(
this,
id,
Body::TYPE_DYNAMIC, enabled, collisionTypeId, transformations, restitution, friction, mass, inertiaTensor, boundingVolumes);
94 listener->onAddedBody(
id,
Body::TYPE_DYNAMIC, enabled, collisionTypeId, transformations, restitution, friction, mass, inertiaTensor, boundingVolumes);
101 auto body =
new Body(
this,
id,
Body::TYPE_COLLISION, enabled, collisionTypeId, transformations, 0.0f, 0.0f, 0.0f,
Body::getNoRotationInertiaTensor(), boundingVolumes);
113 auto body =
new Body(
this,
id,
Body::TYPE_STATIC, enabled, collisionTypeId, transformations, 0.0f, friction, 0.0f,
Body::getNoRotationInertiaTensor(), boundingVolumes);
126 return bodyByIdIt->second;
134 auto body = bodyByIdIt->second;
135 if (body->rigidBody !=
nullptr) {
136 world.destroyRigidBody(body->rigidBody);
138 world.destroyCollisionBody(body->collisionBody);
144 listener->onRemovedBody(
id, body->getType(), body->getCollisionTypeId());
152 if (deltaTime < Math::EPSILON)
return;
155 world.update(deltaTime);
160 map<string, BodyCollisionStruct> bodyCollisionsCurrentFrame;
162 auto manifolds =
world.getContactsList();
163 for (
auto manifold: manifolds) {
164 auto body1 =
static_cast<Body*
>(manifold->getBody1()->getUserData());
165 auto body2 =
static_cast<Body*
>(manifold->getBody2()->getUserData());
167 bodyCollisionStruct.
body1Id = body1->getId();
168 bodyCollisionStruct.
body2Id = body2->getId();
169 string bodyKey = bodyCollisionStruct.
body1Id +
"," + bodyCollisionStruct.
body2Id;
170 string bodyKeyInverted = bodyCollisionStruct.
body2Id +
"," + bodyCollisionStruct.
body1Id;
171 bodyCollisionsCurrentFrame[bodyKey] = bodyCollisionStruct;
172 for (
int i=0; i<manifold->getNbContactPoints(); i++) {
173 auto contactPoint = manifold->getContactPoints();
174 while (contactPoint !=
nullptr) {
176 auto entity = collision.
addResponse(-contactPoint->getPenetrationDepth());
178 entity->setNormal(
Vector3(normal.x, normal.y, normal.z));
179 auto shape1 = manifold->getShape1();
180 auto shape2 = manifold->getShape2();
181 auto& shapeLocalToWorldTransform1 = shape1->getLocalToWorldTransform();
182 auto& shapeLocalToWorldTransform2 = shape2->getLocalToWorldTransform();
183 auto& localPoint1 = contactPoint->getLocalPointOnShape1();
184 auto& localPoint2 = contactPoint->getLocalPointOnShape2();
185 auto worldPoint1 = shapeLocalToWorldTransform1 * localPoint1;
186 auto worldPoint2 = shapeLocalToWorldTransform2 * localPoint2;
187 entity->addHitPoint(
Vector3(worldPoint1.x, worldPoint1.y, worldPoint1.z));
188 entity->addHitPoint(
Vector3(worldPoint2.x, worldPoint2.y, worldPoint2.z));
189 contactPoint = contactPoint->getNext();
194 body1->fireOnCollisionBegin(body2, collision);
197 body1->fireOnCollision(body2, collision);
209 string bodyKey = bodyCollisionStruct->
body1Id +
"," + bodyCollisionStruct->
body2Id;
210 auto bodyCollisionsCurrentFrameIt = bodyCollisionsCurrentFrame.find(bodyKey);
211 if (bodyCollisionsCurrentFrameIt != bodyCollisionsCurrentFrame.end())
continue;
214 string bodyKey = bodyCollisionStruct->
body2Id +
"," + bodyCollisionStruct->
body1Id;
215 auto bodyCollisionsCurrentFrameIt = bodyCollisionsCurrentFrame.find(bodyKey);
216 if (bodyCollisionsCurrentFrameIt != bodyCollisionsCurrentFrame.end())
continue;
219 auto body1 = body1It ==
bodiesById.end()?
nullptr:body1It->second;
221 auto body2 = body2It ==
bodiesById.end()?
nullptr:body2It->second;
222 if (body1 ==
nullptr || body2 ==
nullptr)
continue;
223 body1->fireOnCollisionEnd(body2);
233 if (body->isEnabled() ==
false) {
237 if (body->isSleeping() ==
true) {
242 auto transform = body->rigidBody->getTransform();
243 auto transformPosition = transform.getPosition();
244 auto transformOrientation = transform.getOrientation();
247 auto& physicsTransformations = body->transformations;
251 while (physicsTransformations.getRotationCount() > 1) {
252 physicsTransformations.removeRotation(physicsTransformations.getRotationCount() - 1);
254 if (physicsTransformations.getRotationCount() < 1) {
255 physicsTransformations.addRotation(
Vector3(0.0f, 1.0f, 0.0f), 0.0f);
259 Quaternion rotationsQuaternion(transformOrientation.x, transformOrientation.y, transformOrientation.z, transformOrientation.w);
260 physicsTransformations.getRotation(0).fromQuaternion(rotationsQuaternion);
262 physicsTransformations.setScale(body->transformationsScale);
264 physicsTransformations.setTranslation(
Vector3(transformPosition.x, transformPosition.y, transformPosition.z));
266 physicsTransformations.update();
277 if (body->isSleeping() ==
true)
continue;
280 auto engineEntity = engine->
getEntity(body->id);
281 if (engineEntity ==
nullptr) {
283 string(
"World::entity '") +
285 string(
"' not found")
291 engineEntity->setEnabled(body->isEnabled());
294 if (body->isEnabled() ==
true) {
295 engineEntity->fromTransformations(body->transformations);
302 class CustomCallbackClass :
public reactphysics3d::RaycastCallback {
304 CustomCallbackClass(
float stepUpMax,
const Vector3& point,
float height = 10000.0f): stepUpMax(stepUpMax), point(point), height(height), body(
nullptr) {
306 virtual reactphysics3d::decimal notifyRaycastHit(
const reactphysics3d::RaycastInfo& info) {
307 Vector3 hitPoint(info.worldPoint.x, info.worldPoint.y, info.worldPoint.z);
308 auto _body =
static_cast<Body*
>(info.body->getUserData());
309 if (hitPoint.
getY() < height && hitPoint.
getY() <= point.
getY() + stepUpMax) {
310 height = hitPoint.
getY();
311 body =
static_cast<Body*
>(info.body->getUserData());
313 return reactphysics3d::decimal(info.hitFraction);
327 reactphysics3d::Vector3 startPoint(point.
getX(), maxHeight, point.
getZ());
328 reactphysics3d::Vector3 endPoint(point.
getX(), minHeight, point.
getZ());
329 reactphysics3d::Ray ray(startPoint, endPoint);
330 CustomCallbackClass customCallbackObject(stepUpMax, point, maxHeight);
331 world.raycast(ray, &customCallbackObject, collisionTypeIds);
332 if (customCallbackObject.getBody() !=
nullptr) {
334 dest.
setY(customCallbackObject.getHeight());
335 return customCallbackObject.getBody();
343 class CustomCallbackClass :
public reactphysics3d::RaycastCallback {
345 CustomCallbackClass(
const string& actorId): actorId(actorId), body(
nullptr) {
347 virtual reactphysics3d::decimal notifyRaycastHit(
const reactphysics3d::RaycastInfo& info) {
348 auto _body =
static_cast<Body*
>(info.body->getUserData());
349 if (actorId.size() == 0 || _body->getId() != actorId) {
351 hitPoint.
set(info.worldPoint.x, info.worldPoint.y, info.worldPoint.z);
352 return reactphysics3d::decimal(info.hitFraction);
354 return reactphysics3d::decimal(1.0);
368 reactphysics3d::Vector3 startPoint(start.
getX(), start.
getY(), start.
getZ());
369 reactphysics3d::Vector3 endPoint(end.
getX(), end.
getY(), end.
getZ());
370 reactphysics3d::Ray ray(startPoint, endPoint);
371 CustomCallbackClass customCallbackObject(actorId);
372 world.raycast(ray, &customCallbackObject, collisionTypeIds);
373 if (customCallbackObject.getBody() !=
nullptr) {
374 hitPoint.
set(customCallbackObject.getHitPoint());
375 return customCallbackObject.getBody();
383 class CustomOverlapCallback:
public reactphysics3d::OverlapCallback {
385 CustomOverlapCallback(vector<Body*>& rigidBodies): rigidBodies(rigidBodies) {
388 virtual void notifyOverlap(reactphysics3d::CollisionBody* collisionBody) {
389 rigidBodies.push_back(
static_cast<Body*
>(collisionBody->getUserData()));
392 vector<Body*>& rigidBodies;
396 CustomOverlapCallback customOverlapCallback(rigidBodies);
400 return rigidBodies.size() > 0;
404 auto collisionBody =
addCollisionBody(
"tdme.world.doescollidewith",
true, 32768, transformations, boundingVolumes);
407 return rigidBodies.size() > 0;
416 class CustomCollisionCallback:
public reactphysics3d::CollisionCallback {
421 void notifyContact(
const CollisionCallbackInfo& collisionCallbackInfo) {
422 auto manifold = collisionCallbackInfo.contactManifoldElements;
423 while (manifold !=
nullptr) {
424 auto contactPoint = manifold->getContactManifold()->getContactPoints();
425 while (contactPoint !=
nullptr) {
427 auto entity = collision.
addResponse(-contactPoint->getPenetrationDepth());
429 entity->setNormal(
Vector3(normal.x, normal.y, normal.z));
430 auto shape1 = manifold->getContactManifold()->getShape1();
431 auto shape2 = manifold->getContactManifold()->getShape2();
432 auto& shapeLocalToWorldTransform1 = shape1->getLocalToWorldTransform();
433 auto& shapeLocalToWorldTransform2 = shape2->getLocalToWorldTransform();
434 auto& localPoint1 = contactPoint->getLocalPointOnShape1();
435 auto& localPoint2 = contactPoint->getLocalPointOnShape2();
436 auto worldPoint1 = shapeLocalToWorldTransform1 * localPoint1;
437 auto worldPoint2 = shapeLocalToWorldTransform2 * localPoint2;
438 entity->addHitPoint(
Vector3(worldPoint1.x, worldPoint1.y, worldPoint1.z));
439 entity->addHitPoint(
Vector3(worldPoint2.x, worldPoint2.y, worldPoint2.z));
440 contactPoint = contactPoint->getNext();
442 manifold = collisionCallbackInfo.contactManifoldElements->getNext();
450 CustomCollisionCallback customCollisionCallback(collision);
457 auto clonedWorld =
new World();
458 for (
auto i = 0; i <
bodies.size(); i++) {
461 Body* clonedBody =
nullptr;
462 auto bodyType = body->
getType();
465 if (((body->getCollisionTypeId() & collisionTypeIds) == body->getCollisionTypeId()) ==
false)
continue;
470 clonedBody = clonedWorld->addStaticRigidBody(body->id, body->isEnabled(), body->getCollisionTypeId(), body->transformations, body->getFriction(), body->boundingVolumes);
473 clonedBody = clonedWorld->addRigidBody(body->id, body->isEnabled(), body->getCollisionTypeId(), body->transformations, body->getRestitution(), body->getFriction(), body->getMass(), body->inertiaTensor, body->boundingVolumes);
476 clonedBody = clonedWorld->addCollisionBody(body->id, body->isEnabled(), body->getCollisionTypeId(), body->transformations, body->boundingVolumes);
479 Console::println(
"World::clone(): Unsupported type: " + to_string(bodyType));
487 synch(clonedBody, clonedBody);
508 auto clonedBody =
world->getBody(body->id);
509 if (clonedBody ==
nullptr) {
511 string(
"Cloned world::entity '") +
513 string(
"' not found")
518 synch(clonedBody, body);
Entity * getEntity(const string &id)
Returns a entity by given id.
Dynamic rigid/static rigid/collision body class.
uint16_t getCollisionTypeIds()
void setCloned(bool cloned)
Set cloned.
void setMass(float mass)
Set up mass.
void setAngularVelocity(const Vector3 &angularVelocity)
Set angular velocity.
Transformations transformations
void setEnabled(bool enabled)
Set up if rigid body is enabled.
void setLinearVelocity(const Vector3 &linearVelocity)
Set linear velocity.
reactphysics3d::CollisionBody * collisionBody
static constexpr int32_t TYPE_DYNAMIC
int getType()
Return type, see TYPE_*.
const Vector3 getAngularVelocity()
static const Vector3 getNoRotationInertiaTensor()
void setCollisionTypeIds(uint16_t collisionTypeIds)
Set up collision type ids.
void fromTransformations(const Transformations &transformations)
Synchronizes this rigid body with transformations.
static constexpr int32_t TYPE_STATIC
const Vector3 getLinearVelocity()
static constexpr int32_t TYPE_COLLISION
Collision response entity.
const Vector3 & getNormal()
CollisionResponse_Entity * addResponse(float distance)
Adds a collision response entity.
Dynamic physics world class.
Body * addRigidBody(const string &id, bool enabled, uint16_t collisionTypeId, const Transformations &transformations, float restitution, float friction, float mass, const Vector3 &inertiaTensor, vector< BoundingVolume * > boundingVolumes)
Add a rigid body.
Body * addStaticRigidBody(const string &id, bool enabled, uint16_t collisionTypeId, const Transformations &transformations, float friction, vector< BoundingVolume * > boundingVolumes)
Add a static rigid body.
Body * getBody(const string &id)
Returns body 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 ...
Body * determineHeight(uint16_t collisionTypeId, float stepUpMax, const Vector3 &point, Vector3 &dest, float minHeight=-10000.0f, float maxHeight=10000.0f)
Determine height on x,y,u while respecting step up max.
bool doCollide(Body *body1, Body *body2)
Check if body 1 collides with body 2.
void removeBody(const string &id)
Removes body identified by id.
map< string, Body * > bodiesById
bool getCollisionResponse(Body *body1, Body *body2, CollisionResponse &collision)
Get collision response.
reactphysics3d::DynamicsWorld world
World()
Public constructor.
bool doesCollideWith(uint16_t collisionTypeIds, Body *body, vector< Body * > &rigidBodies)
Check if world collides with given body.
void addWorldListener(WorldListener *listener)
Add a world listener.
map< string, BodyCollisionStruct > bodyCollisionsLastFrame
void synch(Body *clonedBody, Body *body)
Synch into cloned body from body.
vector< Body * > rigidBodiesDynamic
World * clone(uint16_t collisionTypeIds=~0)
Clone this world.
Body * addCollisionBody(const string &id, bool enabled, uint16_t collisionTypeId, const Transformations &transformations, vector< BoundingVolume * > boundingVolumes)
Add a collision body.
vector< WorldListener * > worldListeners
void removeWorldListener(WorldListener *listener)
Remove a world listener.
void update(float deltaTime)
Update world.
void reset()
Resets the physic world.
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.
Vector3 & set(float x, float y, float z)
Set up vector.
Vector3 & setY(float y)
Set Y.
Vector iterator template to be used to iterate multiple vectors at a single invocation.
World listener which is about notifying adding or removing bodies.