Monad Engine da02fba2
> Undercity Codex_
Loading...
Searching...
No Matches
PhysicsManager.cpp
Go to the documentation of this file.
1#include "physics/PhysicsManager.h"
2
3#include <btBulletCollisionCommon.h>
4#include <btBulletDynamicsCommon.h>
5
6#include "Constants.h"
7#include "physics/CollisionObject.h"
8#include "physics/Raycast.h"
9#include "physics/RigidBody.h"
10
11namespace mnd
12{
14
16
18{
19 m_broadphase = std::make_unique<btDbvtBroadphase>();
20 m_collisionConfig = std::make_unique<btDefaultCollisionConfiguration>();
21 m_dispatcher = std::make_unique<btCollisionDispatcher>(m_collisionConfig.get());
22 m_solver = std::make_unique<btSequentialImpulseConstraintSolver>();
23 m_world = std::make_unique<btDiscreteDynamicsWorld>(
24 m_dispatcher.get(), m_broadphase.get(), m_solver.get(), m_collisionConfig.get()
25 );
26
27 m_world->setGravity(btVector3(0, kGravity, 0));
28}
29
30void PhysicsManager::Update(float deltaTime)
31{
32 m_world->stepSimulation(deltaTime, kMaxSubSteps, kFixedTimeStep);
33
34 auto dispatcher = m_world->getDispatcher();
35 const auto numManifolds = dispatcher->getNumManifolds();
36
37 for (int i = 0; i < numManifolds; ++i)
38 {
39 auto manifold = dispatcher->getManifoldByIndexInternal(i);
40
41 if (!manifold)
42 {
43 continue;
44 }
45
46 auto bodyA = reinterpret_cast<CollisionObject *>(manifold->getBody0()->getUserPointer());
47 auto bodyB = reinterpret_cast<CollisionObject *>(manifold->getBody1()->getUserPointer());
48
49 if (!bodyA || !bodyB)
50 {
51 continue;
52 }
53
54 const auto numContacts = manifold->getNumContacts();
55 for (int j = 0; j < numContacts; ++j)
56 {
57 const auto &point = manifold->getContactPoint(j);
58 const vec3 pos(point.m_positionWorldOnB.x(), point.m_positionWorldOnB.y(), point.m_positionWorldOnB.z());
59 const vec3 norm(point.m_normalWorldOnB.x(), point.m_normalWorldOnB.y(), point.m_normalWorldOnB.z());
60
61 bodyA->DispatchContactEvent(bodyB, pos, norm);
62 bodyB->DispatchContactEvent(bodyA, pos, norm);
63 }
64 }
65}
66
68{
69 if (!body || !m_world)
70 {
71 return;
72 }
73
74 if (auto rigidBody = body->GetBody())
75 {
76 m_world->addRigidBody(rigidBody, btBroadphaseProxy::StaticFilter, btBroadphaseProxy::AllFilter);
77 body->SetAddedToWorld(true);
78 }
79}
80
82{
83 if (!body || !m_world)
84 {
85 return;
86 }
87
88 if (auto rigidBody = body->GetBody())
89 {
90 m_world->removeRigidBody(rigidBody);
91 body->SetAddedToWorld(false);
92 }
93}
94
95btDiscreteDynamicsWorld *PhysicsManager::GetWorld()
96{
97 return m_world.get();
98}
99
100bool PhysicsManager::Raycast(const vec3 &from, const vec3 &to, RayHit &out)
101{
102 if (!m_world)
103 {
104 return false;
105 }
106
107 const btVector3 btFrom(btScalar(from.x), btScalar(from.y), btScalar(from.z));
108 const btVector3 btTo(btScalar(to.x), btScalar(to.y), btScalar(to.z));
109
110 btCollisionWorld::ClosestRayResultCallback cb(btFrom, btTo);
111 m_world->rayTest(btFrom, btTo, cb);
112
113 if (!cb.hasHit())
114 {
115 return false;
116 }
117
118 out.point = vec3(cb.m_hitPointWorld.x(), cb.m_hitPointWorld.y(), cb.m_hitPointWorld.z());
119 out.normal = vec3(cb.m_hitNormalWorld.x(), cb.m_hitNormalWorld.y(), cb.m_hitNormalWorld.z());
120 out.fraction = cb.m_closestHitFraction;
121 out.object = nullptr;
122
123 if (cb.m_collisionObject)
124 {
125 if (auto *co = reinterpret_cast<CollisionObject *>(cb.m_collisionObject->getUserPointer()))
126 {
127 out.object = co->GetOwner();
128 }
129 }
130
131 return true;
132}
133} // namespace mnd
Engine-wide compile-time tunables and ANSI colour codes.
constexpr mnd::f32 kGravity
Definition Constants.h:67
constexpr mnd::f32 kFixedTimeStep
Definition Constants.h:100
constexpr mnd::i32 kMaxSubSteps
Definition Constants.h:101
Result struct for PhysicsManager::Raycast.
bool Raycast(const vec3 &from, const vec3 &to, RayHit &out)
void AddRigidBody(RigidBody *body)
Register a rigid body so it participates in simulation and collision.
btDiscreteDynamicsWorld * GetWorld()
Raw pointer to the underlying Bullet world (for advanced/internal use).
void Update(float deltaTime)
Step the simulation by deltaTime seconds.
void Init()
Allocate broadphase, dispatcher, solver, and dynamics world. Call once.
void RemoveRigidBody(RigidBody *body)
Unregister a rigid body (e.g. when its owning component is destroyed).
Owning wrapper around btRigidBody; holds a shared Collider, mass, friction, and body type.
Definition RigidBody.h:41
btRigidBody * GetBody()
Underlying Bullet body (borrowed, do not delete).
Definition RigidBody.cpp:58
void SetAddedToWorld(bool added)
Track whether this body is currently registered with a PhysicsManager.
Definition RigidBody.cpp:63
glm::vec3 vec3
3-component float vector (e.g. world position, RGB colour, normals).
Definition Types.h:51
Hit information returned by PhysicsManager::Raycast.
Definition Raycast.h:23
vec3 point
World-space hit point.
Definition Raycast.h:24
GameObject * object
Definition Raycast.h:26
vec3 normal
Surface normal at the hit.
Definition Raycast.h:25
float fraction
Fraction along the ray segment in [0, 1].
Definition Raycast.h:27