Better boat handling

This commit is contained in:
2025-11-30 18:28:26 +03:00
parent cd82fb0eed
commit 5b014dcb65
21 changed files with 938 additions and 230 deletions

View File

@@ -29,6 +29,7 @@
#include <Jolt/Physics/Collision/Shape/MutableCompoundShape.h>
#include <Jolt/Physics/Collision/Shape/HeightFieldShape.h>
#include <Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h>
#include <Jolt/Physics/Collision/ContactListener.h>
#include <Jolt/Physics/Body/BodyCreationSettings.h>
#include <Jolt/Physics/Body/BodyActivationListener.h>
#include <Jolt/Renderer/DebugRendererSimple.h>
@@ -156,6 +157,7 @@ public:
}
};
#if 0
// An example contact listener
class MyContactListener : public JPH::ContactListener {
public:
@@ -209,6 +211,7 @@ public:
std::cout << "A body went to sleep" << std::endl;
}
};
#endif
class MyCollector : public JPH::CollideShapeBodyCollector {
public:
MyCollector(JPH::PhysicsSystem *inSystem,
@@ -453,6 +456,56 @@ JPH::ShapeRefC CompoundShapeBuilder::build()
JPH::ShapeSettings::ShapeResult result = shapeSettings.Create();
return result.Get();
}
ContactListener::ContactListener()
: JPH::ContactListener()
, dispatch(nullptr)
{
}
JPH::ValidateResult ContactListener::OnContactValidate(
const JPH::Body &inBody1, const JPH::Body &inBody2,
JPH::RVec3Arg inBaseOffset,
const JPH::CollideShapeResult &inCollisionResult)
{
return JPH::ValidateResult::AcceptAllContactsForThisBodyPair;
}
void ContactListener::OnContactAdded(const JPH::Body &inBody1,
const JPH::Body &inBody2,
const JPH::ContactManifold &inManifold,
JPH::ContactSettings &ioSettings)
{
reports.push_back({ true, inBody1.GetID(), inBody2.GetID(), inManifold,
ioSettings });
}
void ContactListener::OnContactPersisted(const JPH::Body &inBody1,
const JPH::Body &inBody2,
const JPH::ContactManifold &inManifold,
JPH::ContactSettings &ioSettings)
{
}
void ContactListener::OnContactRemoved(const JPH::SubShapeIDPair &inSubShapePair)
{
reports.push_back({ false, inSubShapePair.GetBody1ID(),
inSubShapePair.GetBody2ID(), JPH::ContactManifold(),
JPH::ContactSettings() });
}
void ContactListener::update()
{
for (auto contact : reports) {
bool handled = false;
if (listeners.find(contact.id1) != listeners.end()) {
listeners[contact.id1](contact);
handled = true;
}
if (listeners.find(contact.id2) != listeners.end()) {
listeners[contact.id2](contact);
handled = true;
}
if (!handled && dispatch) {
dispatch(contact);
}
}
reports.clear();
}
}
class Physics {
@@ -498,29 +551,9 @@ public:
virtual void OnBodyDeactivated(const JPH::BodyID &inBodyID,
JPH::uint64 inBodyUserData) = 0;
};
class ContactListener : public JPH::ContactListener {
public:
virtual JPH::ValidateResult OnContactValidate(
const JPH::Body &inBody1, const JPH::Body &inBody2,
JPH::RVec3Arg inBaseOffset,
const JPH::CollideShapeResult &inCollisionResult) = 0;
virtual void
OnContactAdded(const JPH::Body &inBody1,
const JPH::Body &inBody2,
const JPH::ContactManifold &inManifold,
JPH::ContactSettings &ioSettings) = 0;
virtual void
OnContactPersisted(const JPH::Body &inBody1,
const JPH::Body &inBody2,
const JPH::ContactManifold &inManifold,
JPH::ContactSettings &ioSettings) = 0;
virtual void
OnContactRemoved(const JPH::SubShapeIDPair &inSubShapePair) = 0;
};
Physics(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
ActivationListener *activationListener = nullptr,
ContactListener *contactListener = nullptr)
JPH::ContactListener *contactListener = nullptr)
: temp_allocator(10 * 1024 * 1024)
, job_system(JPH::cMaxPhysicsJobs, JPH::cMaxPhysicsBarriers,
std::thread::hardware_concurrency() - 1)
@@ -740,8 +773,10 @@ public:
node->_setDerivedPosition(JoltPhysics::convert(p));
node->_setDerivedOrientation(JoltPhysics::convert(q));
}
for (JPH::Character *ch : characters)
ch->PostSimulation(0.1f);
for (JPH::Character *ch : characters) {
if (body_interface.IsAdded(ch->GetBodyID()))
ch->PostSimulation(0.1f);
}
if (debugDraw)
physics_system.DrawBodies(
@@ -873,7 +908,7 @@ public:
if (shape->GetType() == JPH::EShapeType::HeightField) {
JPH::BodyInterface &body_interface =
physics_system.GetBodyInterface();
body_interface.SetFriction(id, 0.7f);
body_interface.SetFriction(id, 1.0f);
}
id2node[id] = node;
node2id[node] = id;
@@ -1385,6 +1420,21 @@ public:
physics_system.GetBodyInterface().GetLinearVelocity(
id));
}
Ogre::Vector3 getAngularVelocity(JPH::BodyID id)
{
return JoltPhysics::convert(
physics_system.GetBodyInterface().GetAngularVelocity(
id));
}
float getFriction(JPH::BodyID id)
{
return physics_system.GetBodyInterface().GetFriction(id);
}
void setFriction(JPH::BodyID id, float friction)
{
return physics_system.GetBodyInterface().SetFriction(id,
friction);
}
void broadphaseQuery(float dt, const Ogre::Vector3 &position,
std::set<JPH::BodyID> &inWater)
{
@@ -1434,7 +1484,7 @@ JoltPhysicsWrapper::JoltPhysicsWrapper(Ogre::SceneManager *scnMgr,
JPH::Trace = TraceImpl;
JPH_IF_ENABLE_ASSERTS(JPH::AssertFailed = AssertFailedImpl;)
phys = new Physics(scnMgr, cameraNode);
phys = new Physics(scnMgr, cameraNode, nullptr, &contacts);
}
JoltPhysicsWrapper::~JoltPhysicsWrapper()
@@ -1446,6 +1496,7 @@ JoltPhysicsWrapper::~JoltPhysicsWrapper()
void JoltPhysicsWrapper::update(float dt)
{
phys->update(dt);
contacts.update();
}
void JoltPhysicsWrapper::addBody(const JPH::BodyID &body,
@@ -1629,6 +1680,10 @@ void JoltPhysicsWrapper::setPosition(JPH::BodyID id,
{
return phys->setPosition(id, position, activate);
}
Ogre::Quaternion JoltPhysicsWrapper::getRotation(JPH::BodyID id)
{
return phys->getRotation(id);
}
void JoltPhysicsWrapper::setRotation(JPH::BodyID id,
const Ogre::Quaternion &rotation,
bool activate)
@@ -1651,10 +1706,41 @@ Ogre::Vector3 JoltPhysicsWrapper::getLinearVelocity(JPH::BodyID id)
{
return phys->getLinearVelocity(id);
}
Ogre::Vector3 JoltPhysicsWrapper::getAngularVelocity(JPH::BodyID id)
{
return phys->getAngularVelocity(id);
}
float JoltPhysicsWrapper::getFriction(JPH::BodyID id)
{
return phys->getFriction(id);
}
void JoltPhysicsWrapper::setFriction(JPH::BodyID id, float friction)
{
phys->setFriction(id, friction);
}
void JoltPhysicsWrapper::addAngularImpulse(const JPH::BodyID &id,
const Ogre::Vector3 &impulse)
{
return phys->addAngularImpulse(id, impulse);
}
void JoltPhysicsWrapper::setDispatch(
std::function<
void(const JoltPhysics::ContactListener::ContactReport &report)>
dispatcher)
{
contacts.setDispatch(dispatcher);
}
void JoltPhysicsWrapper::addContactListener(
const JPH::BodyID &id,
std::function<
void(const JoltPhysics::ContactListener::ContactReport &report)>
listener)
{
contacts.addListener(id, listener);
}
void JoltPhysicsWrapper::removeContactListener(const JPH::BodyID &id)
{
contacts.removeListener(id);
}
template <>
JoltPhysicsWrapper *Ogre::Singleton<JoltPhysicsWrapper>::msSingleton = 0;
JoltPhysicsWrapper *Ogre::Singleton<JoltPhysicsWrapper>::msSingleton = 0;

View File

@@ -6,6 +6,7 @@
#include <Jolt/Physics/Collision/Shape/Shape.h>
#include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h>
#include <Jolt/Physics/Collision/ObjectLayer.h>
#include <Jolt/Physics/Collision/ContactListener.h>
#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h>
#include <Jolt/Physics/Body/BodyCreationSettings.h>
#include <Jolt/Physics/EActivation.h>
@@ -13,6 +14,9 @@ void physics();
namespace JPH
{
class CharacterBase;
class ContactManifold;
class ContactSettings;
class SubShapeIDPair;
}
// Layer that objects can be in, determines which other objects it can collide with
// Typically you at least want to have 1 layer for moving bodies and 1 layer for static bodies, but you can have more
@@ -50,10 +54,58 @@ struct CompoundShapeBuilder {
const Ogre::Quaternion &rotation);
JPH::ShapeRefC build();
};
class ContactListener : public JPH::ContactListener {
public:
struct ContactReport {
bool entered;
JPH::BodyID id1, id2;
JPH::ContactManifold manifold;
JPH::ContactSettings settings;
};
private:
std::list<ContactReport> reports;
std::function<void(const ContactReport &report)> dispatch;
std::map<JPH::BodyID, std::function<void(const ContactReport &report)> >
listeners;
public:
ContactListener();
JPH::ValidateResult OnContactValidate(
const JPH::Body &inBody1, const JPH::Body &inBody2,
JPH::RVec3Arg inBaseOffset,
const JPH::CollideShapeResult &inCollisionResult) override;
void OnContactAdded(const JPH::Body &inBody1, const JPH::Body &inBody2,
const JPH::ContactManifold &inManifold,
JPH::ContactSettings &ioSettings) override;
void OnContactPersisted(const JPH::Body &inBody1,
const JPH::Body &inBody2,
const JPH::ContactManifold &inManifold,
JPH::ContactSettings &ioSettings) override;
void
OnContactRemoved(const JPH::SubShapeIDPair &inSubShapePair) override;
void setDispatch(const std::function<void(const ContactReport &report)>
dispatcher)
{
dispatch = dispatcher;
}
void addListener(
const JPH::BodyID &id,
const std::function<void(const ContactReport &report)> listener)
{
listeners[id] = listener;
}
void removeListener(const JPH::BodyID &id)
{
listeners.erase(id);
}
void update();
};
}
class JoltPhysicsWrapper : public Ogre::Singleton<JoltPhysicsWrapper> {
public:
JoltPhysics::ContactListener contacts;
JoltPhysicsWrapper(Ogre::SceneManager *scnMgr,
Ogre::SceneNode *cameraNode);
~JoltPhysicsWrapper();
@@ -128,6 +180,7 @@ public:
Ogre::Vector3 getPosition(JPH::BodyID id);
void setPosition(JPH::BodyID id, const Ogre::Vector3 &position,
bool activate = true);
Ogre::Quaternion getRotation(JPH::BodyID id);
void setRotation(JPH::BodyID id, const Ogre::Quaternion &rotation,
bool activate = true);
void getPositionAndRotation(JPH::BodyID id, Ogre::Vector3 &position,
@@ -137,7 +190,19 @@ public:
const Ogre::Quaternion &rotation,
bool activate = true);
Ogre::Vector3 getLinearVelocity(JPH::BodyID id);
Ogre::Vector3 getAngularVelocity(JPH::BodyID id);
float getFriction(JPH::BodyID id);
void setFriction(JPH::BodyID id, float friction);
void addAngularImpulse(const JPH::BodyID &id,
const Ogre::Vector3 &impulse);
void setDispatch(std::function<void(const JoltPhysics::ContactListener::
ContactReport &report)>
dispatcher);
void addContactListener(
const JPH::BodyID &id,
const std::function<void(const JoltPhysics::ContactListener::
ContactReport &report)>
listener);
void removeContactListener(const JPH::BodyID &id);
};
#endif
#endif