1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-21 09:39:56 +00:00

Do not block a door when it turns away.

This commit is contained in:
fredzio 2020-11-01 22:30:48 +01:00
parent ba3aad31c1
commit 18e38d8810
5 changed files with 35 additions and 10 deletions

View File

@ -2,6 +2,8 @@
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
#include "components/misc/convert.hpp"
#include "ptrholder.hpp"
namespace MWPhysics
@ -20,7 +22,7 @@ namespace MWPhysics
collisionObject = col1Wrap->m_collisionObject;
PtrHolder* holder = static_cast<PtrHolder*>(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;
}

View File

@ -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<MWWorld::Ptr> mResult;
std::vector<ContactPoint> mResult;
};
}

View File

@ -403,15 +403,15 @@ namespace MWPhysics
return osg::Vec3f();
}
std::vector<MWWorld::Ptr> PhysicsSystem::getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const
std::vector<ContactPoint> 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<MWWorld::Ptr>();
return {};
ContactTestResultCallback resultCallback (me);
resultCallback.m_collisionFilterGroup = collisionGroup;
@ -420,6 +420,14 @@ namespace MWPhysics
return resultCallback.mResult;
}
std::vector<MWWorld::Ptr> PhysicsSystem::getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const
{
std::vector<MWWorld::Ptr> 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);

View File

@ -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<Actor>& a1, const std::weak_ptr<Actor>& a2);
@ -145,6 +152,7 @@ namespace MWPhysics
void debugDraw();
std::vector<MWWorld::Ptr> getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with
std::vector<ContactPoint> 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<MWWorld::Ptr, osg::Vec3f> getHitContact(const MWWorld::ConstPtr& actor,

View File

@ -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<MWWorld::Ptr> 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() )
{