diff --git a/apps/openmw/mwphysics/contacttestresultcallback.cpp b/apps/openmw/mwphysics/contacttestresultcallback.cpp index f8209e3636..5829ee02f5 100644 --- a/apps/openmw/mwphysics/contacttestresultcallback.cpp +++ b/apps/openmw/mwphysics/contacttestresultcallback.cpp @@ -2,6 +2,8 @@ #include +#include "components/misc/convert.hpp" + #include "ptrholder.hpp" namespace MWPhysics @@ -20,7 +22,7 @@ namespace MWPhysics collisionObject = col1Wrap->m_collisionObject; PtrHolder* holder = static_cast(collisionObject->getUserPointer()); if (holder) - mResult.push_back(holder->getPtr()); + mResult.emplace_back(ContactPoint{holder->getPtr(), Misc::Convert::toOsg(cp.m_positionWorldOnB), Misc::Convert::toOsg(cp.m_normalWorldOnB)}); return 0.f; } diff --git a/apps/openmw/mwphysics/contacttestresultcallback.hpp b/apps/openmw/mwphysics/contacttestresultcallback.hpp index 03fc362992..fbe12d5dc2 100644 --- a/apps/openmw/mwphysics/contacttestresultcallback.hpp +++ b/apps/openmw/mwphysics/contacttestresultcallback.hpp @@ -7,6 +7,8 @@ #include "../mwworld/ptr.hpp" +#include "physicssystem.hpp" + class btCollisionObject; struct btCollisionObjectWrapper; @@ -23,7 +25,7 @@ namespace MWPhysics const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) override; - std::vector mResult; + std::vector mResult; }; } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 513e8d59b4..9a777bd454 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -403,15 +403,15 @@ namespace MWPhysics return osg::Vec3f(); } - std::vector PhysicsSystem::getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const + std::vector PhysicsSystem::getCollisionsPoints(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const { btCollisionObject* me = nullptr; - ObjectMap::const_iterator found = mObjects.find(ptr); + auto found = mObjects.find(ptr); if (found != mObjects.end()) me = found->second->getCollisionObject(); else - return std::vector(); + return {}; ContactTestResultCallback resultCallback (me); resultCallback.m_collisionFilterGroup = collisionGroup; @@ -420,6 +420,14 @@ namespace MWPhysics return resultCallback.mResult; } + std::vector PhysicsSystem::getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const + { + std::vector actors; + for (auto& [actor, point, normal] : getCollisionsPoints(ptr, collisionGroup, collisionMask)) + actors.emplace_back(actor); + return actors; + } + osg::Vec3f PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, float maxHeight) { ActorMap::iterator found = mActors.find(ptr); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 31707465b9..36ef762d3e 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -57,6 +57,13 @@ namespace MWPhysics class Actor; class PhysicsTaskScheduler; + struct ContactPoint + { + MWWorld::Ptr mObject; + osg::Vec3f mPoint; + osg::Vec3f mNormal; + }; + struct LOSRequest { LOSRequest(const std::weak_ptr& a1, const std::weak_ptr& a2); @@ -145,6 +152,7 @@ namespace MWPhysics void debugDraw(); std::vector getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with + std::vector getCollisionsPoints(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; osg::Vec3f traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, float maxHeight); std::pair getHitContact(const MWWorld::ConstPtr& actor, diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index dbe6af3268..095bb14543 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1577,21 +1577,26 @@ namespace MWWorld float minRot = door.getCellRef().getPosition().rot[2]; float maxRot = minRot + osg::DegreesToRadians(90.f); - float diff = duration * osg::DegreesToRadians(90.f); - float targetRot = std::min(std::max(minRot, oldRot + diff * (state == MWWorld::DoorState::Opening ? 1 : -1)), maxRot); + float diff = duration * osg::DegreesToRadians(90.f) * (state == MWWorld::DoorState::Opening ? 1 : -1); + float targetRot = std::min(std::max(minRot, oldRot + diff), maxRot); rotateObject(door, objPos.rot[0], objPos.rot[1], targetRot, MWBase::RotationFlag_none); bool reached = (targetRot == maxRot && state != MWWorld::DoorState::Idle) || targetRot == minRot; /// \todo should use convexSweepTest here bool collisionWithActor = false; - std::vector collisions = mPhysics->getCollisions(door, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor); - for (MWWorld::Ptr& ptr : collisions) + for (auto& [ptr, point, normal] : mPhysics->getCollisionsPoints(door, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor)) { + if (ptr.getClass().isActor()) { + osg::Vec3f direction = osg::Quat(diff, osg::Vec3f(0, 0, 1)) * point - point; + direction.normalize(); + if (direction * normal < 0) // door is turning away from actor + continue; + collisionWithActor = true; - + // Collided with actor, ask actor to try to avoid door if(ptr != getPlayerPtr() ) {