Grindstone Game Engine v0.2.0
An open source game engine and toolkit.
Loading...
Searching...
No Matches
PhysicsWorldContext.hpp
1#pragma once
2
3#include <Jolt/Physics/PhysicsSystem.h>
4#include <Jolt/Core/TempAllocator.h>
5#include <Jolt/Core/JobSystemThreadPool.h>
6#include <Jolt/Physics/Body/BodyActivationListener.h>
7
8#include <Common/HashedString.hpp>
9#include <Common/Memory/SmartPointers/UniquePtr.hpp>
10#include <EngineCore/WorldContext/WorldContext.hpp>
11
12const Grindstone::ConstHashedString physicsWorldContextName("Grindstone::Physics::WorldContext");
13
14namespace Grindstone::Physics {
15 // Layer that objects can be in, determines which other objects it can collide with
16 // Typically you at least want to have 1 layer for moving bodies and 1 layer for static bodies, but you can have more
17 // layers if you want. E.g. you could have a layer for high detail collision (which is not used by the physics simulation
18 // but only if you do collision testing).
19 namespace Layers {
20 static constexpr JPH::ObjectLayer NON_MOVING = 0;
21 static constexpr JPH::ObjectLayer MOVING = 1;
22 static constexpr JPH::ObjectLayer NUM_LAYERS = 2;
23 };
24
26 class ObjectLayerPairFilterImpl : public JPH::ObjectLayerPairFilter {
27 public:
28 virtual bool ShouldCollide(JPH::ObjectLayer inObject1, JPH::ObjectLayer inObject2) const override {
29 switch (inObject1) {
30 case Layers::NON_MOVING:
31 return inObject2 == Layers::MOVING; // Non moving only collides with moving
32 case Layers::MOVING:
33 return true; // Moving collides with everything
34 default:
35 JPH_ASSERT(false);
36 return false;
37 }
38 }
39 };
40
41 // Each broadphase layer results in a separate bounding volume tree in the broad phase. You at least want to have
42 // a layer for non-moving and moving objects to avoid having to update a tree full of static objects every frame.
43 // You can have a 1-on-1 mapping between object layers and broadphase layers (like in this case) but if you have
44 // many object layers you'll be creating many broad phase trees, which is not efficient. If you want to fine tune
45 // your broadphase layers define JPH_TRACK_BROADPHASE_STATS and look at the stats reported on the TTY.
46 namespace BroadPhaseLayers {
47 static constexpr JPH::BroadPhaseLayer NON_MOVING(0);
48 static constexpr JPH::BroadPhaseLayer MOVING(1);
49 static constexpr uint32_t NUM_LAYERS(2);
50 };
51
52 // BroadPhaseLayerInterface implementation
53 // This defines a mapping between object and broadphase layers.
54 class BPLayerInterfaceImpl final : public JPH::BroadPhaseLayerInterface {
55 public:
56 BPLayerInterfaceImpl() {
57 // Create a mapping table from object to broad phase layer
58 mObjectToBroadPhase[Layers::NON_MOVING] = BroadPhaseLayers::NON_MOVING;
59 mObjectToBroadPhase[Layers::MOVING] = BroadPhaseLayers::MOVING;
60 }
61
62 virtual uint32_t GetNumBroadPhaseLayers() const override {
63 return BroadPhaseLayers::NUM_LAYERS;
64 }
65
66 virtual JPH::BroadPhaseLayer GetBroadPhaseLayer(JPH::ObjectLayer inLayer) const override {
67 JPH_ASSERT(inLayer < Layers::NUM_LAYERS);
68 return mObjectToBroadPhase[inLayer];
69 }
70
71#if defined(JPH_EXTERNAL_PROFILE) || defined(JPH_PROFILE_ENABLED)
72 virtual const char* GetBroadPhaseLayerName(JPH::BroadPhaseLayer inLayer) const override {
73 switch ((JPH::BroadPhaseLayer::Type)inLayer) {
74 case (JPH::BroadPhaseLayer::Type)BroadPhaseLayers::NON_MOVING: return "NON_MOVING";
75 case (JPH::BroadPhaseLayer::Type)BroadPhaseLayers::MOVING: return "MOVING";
76 default: JPH_ASSERT(false); return "INVALID";
77 }
78 }
79#endif // JPH_EXTERNAL_PROFILE || JPH_PROFILE_ENABLED
80
81 private:
82 JPH::BroadPhaseLayer mObjectToBroadPhase[Layers::NUM_LAYERS];
83 };
84
86 class ObjectVsBroadPhaseLayerFilterImpl : public JPH::ObjectVsBroadPhaseLayerFilter {
87 public:
88 virtual bool ShouldCollide(JPH::ObjectLayer inLayer1, JPH::BroadPhaseLayer inLayer2) const override {
89 switch (inLayer1) {
90 case Layers::NON_MOVING:
91 return inLayer2 == BroadPhaseLayers::MOVING;
92 case Layers::MOVING:
93 return true;
94 default:
95 JPH_ASSERT(false);
96 return false;
97 }
98 }
99 };
100
101 // An example contact listener
102 class MyContactListener : public JPH::ContactListener {
103 public:
104 // See: ContactListener
105 virtual JPH::ValidateResult OnContactValidate(const JPH::Body& inBody1, const JPH::Body& inBody2, JPH::RVec3Arg inBaseOffset, const JPH::CollideShapeResult& inCollisionResult) override {
106 std::cout << "Contact validate callback" << std::endl;
107
108 // Allows you to ignore a contact before it is created (using layers to not make objects collide is cheaper!)
109 return JPH::ValidateResult::AcceptAllContactsForThisBodyPair;
110 }
111
112 virtual void OnContactAdded(const JPH::Body& inBody1, const JPH::Body& inBody2, const JPH::ContactManifold& inManifold, JPH::ContactSettings& ioSettings) override {
113 std::cout << "A contact was added" << std::endl;
114 }
115
116 virtual void OnContactPersisted(const JPH::Body& inBody1, const JPH::Body& inBody2, const JPH::ContactManifold& inManifold, JPH::ContactSettings& ioSettings) override {
117 }
118
119 virtual void OnContactRemoved(const JPH::SubShapeIDPair& inSubShapePair) override {
120 std::cout << "A contact was removed" << std::endl;
121 }
122 };
123
124 // An example activation listener
125 class MyBodyActivationListener : public JPH::BodyActivationListener {
126 public:
127 virtual void OnBodyActivated(const JPH::BodyID& inBodyID, uint64_t inBodyUserData) override {
128 std::cout << "A body got activated" << std::endl;
129 }
130
131 virtual void OnBodyDeactivated(const JPH::BodyID& inBodyID, uint64_t inBodyUserData) override {
132 std::cout << "A body went to sleep" << std::endl;
133 }
134 };
135
137 public:
138 WorldContext();
139 WorldContext(const WorldContext&) = delete;
140 WorldContext(WorldContext&& ) noexcept = default;
141 virtual ~WorldContext() override = default;
142
143 JPH::BodyInterface& GetBodyInterface();
144 JPH::PhysicsSystem& GetPhysicsSystem();
145 JPH::TempAllocatorImpl& GetTempAllocator();
146 JPH::JobSystemThreadPool& GetJobSystem();
147
148 [[nodiscard]] static WorldContext* GetActiveContext();
149 static void SetActiveContext(WorldContext& cxt);
150 virtual void SetAsActive() override;
151
152 protected:
153 JPH::TempAllocatorImpl tempAllocator;
154 JPH::JobSystemThreadPool jobSystem;
155 JPH::PhysicsSystem physicsSystem;
156 JPH::BodyInterface* bodyInterface = nullptr;
157
158 BPLayerInterfaceImpl broadphaseLayerInterface;
159 ObjectVsBroadPhaseLayerFilterImpl objectVsBroadphaseLayerFilter;
160 ObjectLayerPairFilterImpl objectVsObjectLayerFilter;
161 MyBodyActivationListener bodyActivationListener;
162 MyContactListener contactListener;
163 };
164}
Definition HashedString.hpp:54
Definition PhysicsWorldContext.hpp:54
Definition PhysicsWorldContext.hpp:125
Definition PhysicsWorldContext.hpp:102
Class that determines if two object layers can collide.
Definition PhysicsWorldContext.hpp:26
Class that determines if an object layer can collide with a broadphase layer.
Definition PhysicsWorldContext.hpp:86
Definition PhysicsWorldContext.hpp:12
Definition WorldContext.hpp:7
Definition PhysicsWorldContext.hpp:46
Definition PhysicsWorldContext.hpp:19
Definition PhysicsLayer.hpp:6
Definition CharacterKinematicControllerComponent.hpp:16