forked from mirror/openmw-tes3mp
Use a proper cone shape with a contact test to check for melee hits
This commit is contained in:
parent
f5d03a16c1
commit
3fa65f21dd
3 changed files with 92 additions and 72 deletions
|
@ -312,28 +312,31 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::string,Ogre::Vector3> PhysicsSystem::getHitContact(const std::string &name,
|
std::pair<std::string,Ogre::Vector3> PhysicsSystem::getHitContact(const std::string &name,
|
||||||
const Ogre::Vector3 &origin_,
|
const Ogre::Vector3 &origin,
|
||||||
const Ogre::Quaternion &orient_,
|
const Ogre::Quaternion &orient,
|
||||||
float queryDistance)
|
float queryDistance)
|
||||||
{
|
{
|
||||||
btVector3 origin(origin_.x, origin_.y, origin_.z);
|
const MWWorld::Store<ESM::GameSetting> &store = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
std::pair<std::string,btVector3> result = mEngine->sphereTest(queryDistance,origin);
|
btConeShape shape(Ogre::Degree(store.find("fCombatAngleXY")->getFloat()/2.0f).valueRadians(),
|
||||||
if(result.first == "") return std::make_pair("",0);
|
queryDistance);
|
||||||
btVector3 a = result.second - origin;
|
shape.setLocalScaling(btVector3(1, 1, Ogre::Degree(store.find("fCombatAngleZ")->getFloat()/2.0f).valueRadians() /
|
||||||
Ogre::Vector3 a_ = Ogre::Vector3(a.x(),a.y(),a.z());
|
shape.getRadius()));
|
||||||
a_ = orient_.Inverse()*a_;
|
|
||||||
Ogre::Vector2 a_xy = Ogre::Vector2(a_.x,a_.y);
|
|
||||||
Ogre::Vector2 a_yz = Ogre::Vector2(a_xy.length(),a_.z);
|
|
||||||
float axy = a_xy.angleBetween(Ogre::Vector2::UNIT_Y).valueDegrees();
|
|
||||||
float az = a_yz.angleBetween(Ogre::Vector2::UNIT_X).valueDegrees();
|
|
||||||
|
|
||||||
float fCombatAngleXY = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fCombatAngleXY")->getFloat();
|
// The shape origin is its center, so we have to move it forward by half the length. The
|
||||||
float fCombatAngleZ = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fCombatAngleZ")->getFloat();
|
// real origin will be provided to getFilteredContact to find the closest.
|
||||||
if(abs(axy) < fCombatAngleXY && abs(az) < fCombatAngleZ)
|
Ogre::Vector3 center = origin + (orient * Ogre::Vector3(0.0f, queryDistance*0.5f, 0.0f));
|
||||||
return std::make_pair (result.first,result.second.length());
|
|
||||||
else
|
btCollisionObject object;
|
||||||
return std::make_pair("",0);
|
object.setCollisionShape(&shape);
|
||||||
|
object.setWorldTransform(btTransform(btQuaternion(orient.x, orient.y, orient.z, orient.w),
|
||||||
|
btVector3(center.x, center.y, center.z)));
|
||||||
|
|
||||||
|
std::pair<const OEngine::Physic::RigidBody*,btVector3> result = mEngine->getFilteredContact(
|
||||||
|
name, btVector3(origin.x, origin.y, origin.z), &object);
|
||||||
|
if(!result.first)
|
||||||
|
return std::make_pair(std::string(), Ogre::Vector3(&result.second[0]));
|
||||||
|
return std::make_pair(result.first->mName, Ogre::Vector3(&result.second[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -543,62 +543,64 @@ namespace Physic
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AabbResultCallback : public btBroadphaseAabbCallback {
|
class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback
|
||||||
std::vector<RigidBody*> hits;
|
{
|
||||||
//AabbResultCallback(){}
|
const std::string &mFilter;
|
||||||
virtual bool process(const btBroadphaseProxy* proxy) {
|
// Store the real origin, since the shape's origin is its center
|
||||||
RigidBody* collisionObject = static_cast<RigidBody*>(proxy->m_clientObject);
|
btVector3 mOrigin;
|
||||||
if(proxy->m_collisionFilterGroup == CollisionType_Actor && (collisionObject->mName != "player"))
|
|
||||||
this->hits.push_back(collisionObject);
|
public:
|
||||||
return true;
|
const RigidBody *mObject;
|
||||||
|
btVector3 mContactPoint;
|
||||||
|
btScalar mLeastDistSqr;
|
||||||
|
|
||||||
|
DeepestNotMeContactTestResultCallback(const std::string &filter, const btVector3 &origin)
|
||||||
|
: mFilter(filter), mOrigin(origin), mObject(0), mContactPoint(0,0,0),
|
||||||
|
mLeastDistSqr(std::numeric_limits<float>::max())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
#if defined(BT_COLLISION_OBJECT_WRAPPER_H)
|
||||||
|
virtual btScalar addSingleResult(btManifoldPoint& cp,
|
||||||
|
const btCollisionObjectWrapper* col0Wrap,int partId0,int index0,
|
||||||
|
const btCollisionObjectWrapper* col1Wrap,int partId1,int index1)
|
||||||
|
{
|
||||||
|
const RigidBody* body = dynamic_cast<const RigidBody*>(col1Wrap->m_collisionObject);
|
||||||
|
if(body && body->mName != mFilter)
|
||||||
|
{
|
||||||
|
btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA());
|
||||||
|
if(!mObject || distsqr < mLeastDistSqr)
|
||||||
|
{
|
||||||
|
mObject = body;
|
||||||
|
mLeastDistSqr = distsqr;
|
||||||
|
mContactPoint = cp.getPositionWorldOnA();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.f;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
virtual btScalar addSingleResult(btManifoldPoint& cp,
|
||||||
|
const btCollisionObject* col0, int partId0, int index0,
|
||||||
|
const btCollisionObject* col1, int partId1, int index1)
|
||||||
|
{
|
||||||
|
const RigidBody* body = dynamic_cast<const RigidBody*>(col1);
|
||||||
|
if(body && body->mName != mFilter)
|
||||||
|
{
|
||||||
|
btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA());
|
||||||
|
if(!mObject || distsqr < mLeastDistSqr)
|
||||||
|
{
|
||||||
|
mObject = body;
|
||||||
|
mLeastDistSqr = distsqr;
|
||||||
|
mContactPoint = cp.getPositionWorldOnA();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.f;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
std::pair<std::string,btVector3> PhysicEngine::sphereTest(float radius,btVector3& pos)
|
|
||||||
{
|
|
||||||
AabbResultCallback callback;
|
|
||||||
/*btDefaultMotionState* newMotionState =
|
|
||||||
new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),pos));
|
|
||||||
btCollisionShape * shape = new btSphereShape(radius);
|
|
||||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo
|
|
||||||
(0,newMotionState, shape);
|
|
||||||
RigidBody* body = new RigidBody(CI,"hitDetectionShpere__");
|
|
||||||
btTransform tr = body->getWorldTransform();
|
|
||||||
tr.setOrigin(pos);
|
|
||||||
body->setWorldTransform(tr);
|
|
||||||
dynamicsWorld->addRigidBody(body,CollisionType_Actor,CollisionType_World|CollisionType_World);
|
|
||||||
body->setWorldTransform(tr);*/
|
|
||||||
|
|
||||||
btVector3 aabbMin = pos - radius*btVector3(1.0f, 1.0f, 1.0f);
|
|
||||||
btVector3 aabbMax = pos + radius*btVector3(1.0f, 1.0f, 1.0f);
|
|
||||||
|
|
||||||
broadphase->aabbTest(aabbMin,aabbMax,callback);
|
|
||||||
for(int i=0;i<static_cast<int> (callback.hits.size()); ++i)
|
|
||||||
{
|
|
||||||
float d = (callback.hits[i]->getWorldTransform().getOrigin()-pos).length();
|
|
||||||
if(d<radius)
|
|
||||||
{
|
|
||||||
std::pair<std::string,float> rayResult = this->rayTest(pos,callback.hits[i]->getWorldTransform().getOrigin());
|
|
||||||
if(rayResult.second>d || rayResult.first == callback.hits[i]->mName)
|
|
||||||
return std::make_pair(callback.hits[i]->mName,callback.hits[i]->getWorldTransform().getOrigin());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//ContactTestResultCallback callback;
|
|
||||||
//dynamicsWorld->contactTest(body, callback);
|
|
||||||
//dynamicsWorld->removeRigidBody(body);
|
|
||||||
//delete body;
|
|
||||||
//delete shape;
|
|
||||||
//if(callback.mResultName.empty()) return std::make_pair(std::string(""),btVector3(0,0,0));
|
|
||||||
/*for(int i=0;i<callback.mResultName.size();i++)
|
|
||||||
{
|
|
||||||
//TODO: raycasting
|
|
||||||
if(callback.mResultName[i] != "hitDetectionShpere__")
|
|
||||||
return std::pair<std::string,btVector3>(callback.mResultName[i],callback.mResultContact[i]);
|
|
||||||
*/
|
|
||||||
return std::make_pair(std::string(""),btVector3(0,0,0));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> PhysicEngine::getCollisions(const std::string& name)
|
std::vector<std::string> PhysicEngine::getCollisions(const std::string& name)
|
||||||
{
|
{
|
||||||
RigidBody* body = getRigidBody(name);
|
RigidBody* body = getRigidBody(name);
|
||||||
|
@ -607,6 +609,17 @@ namespace Physic
|
||||||
return callback.mResult;
|
return callback.mResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<const RigidBody*,btVector3> PhysicEngine::getFilteredContact(const std::string &filter,
|
||||||
|
const btVector3 &origin,
|
||||||
|
btCollisionObject *object)
|
||||||
|
{
|
||||||
|
DeepestNotMeContactTestResultCallback callback(filter, origin);
|
||||||
|
dynamicsWorld->contactTest(object, callback);
|
||||||
|
return std::make_pair(callback.mObject, callback.mContactPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PhysicEngine::stepSimulation(double deltaT)
|
void PhysicEngine::stepSimulation(double deltaT)
|
||||||
{
|
{
|
||||||
// This seems to be needed for character controller objects
|
// This seems to be needed for character controller objects
|
||||||
|
|
|
@ -321,10 +321,14 @@ public:
|
||||||
std::pair<bool, float> sphereCast (float radius, btVector3& from, btVector3& to);
|
std::pair<bool, float> sphereCast (float radius, btVector3& from, btVector3& to);
|
||||||
///< @return (hit, relative distance)
|
///< @return (hit, relative distance)
|
||||||
|
|
||||||
std::pair<std::string,btVector3> sphereTest(float radius,btVector3& pos);
|
|
||||||
|
|
||||||
std::vector<std::string> getCollisions(const std::string& name);
|
std::vector<std::string> getCollisions(const std::string& name);
|
||||||
|
|
||||||
|
// Get the nearest object that's inside the given object, filtering out objects of the
|
||||||
|
// provided name
|
||||||
|
std::pair<const RigidBody*,btVector3> getFilteredContact(const std::string &filter,
|
||||||
|
const btVector3 &origin,
|
||||||
|
btCollisionObject *object);
|
||||||
|
|
||||||
//event list of non player object
|
//event list of non player object
|
||||||
std::list<PhysicEvent> NPEventList;
|
std::list<PhysicEvent> NPEventList;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue