mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-25 11:52:40 +01:00
Redo uprooting dynamics
This commit is contained in:
parent
0a3167d1e9
commit
7063952d56
@ -197,10 +197,10 @@ public:
|
||||
btDiscreteDynamicsWorld* dynamicsWorld;
|
||||
|
||||
/**
|
||||
* @brief handleCollisionResponses performs physics response checking
|
||||
* for collisions between vehicles, objects etc.
|
||||
* @brief physicsNearCallback
|
||||
* Used to implement uprooting and other physics oddities.
|
||||
*/
|
||||
void handleCollisionResponses();
|
||||
static bool ContactProcessedCallback(btManifoldPoint& mp, void* body0, void* body1);
|
||||
|
||||
/**
|
||||
* Work related
|
||||
|
@ -16,6 +16,7 @@ struct InstanceObject : public GameObject
|
||||
std::shared_ptr<InstanceObject> LODinstance;
|
||||
std::shared_ptr<DynamicObjectData> dynamics;
|
||||
float _collisionHeight;
|
||||
bool _enablePhysics;
|
||||
|
||||
InstanceObject(
|
||||
GameWorld* engine,
|
||||
|
@ -11,6 +11,59 @@
|
||||
#include <objects/InstanceObject.hpp>
|
||||
#include <objects/VehicleObject.hpp>
|
||||
|
||||
class WorldCollisionDispatcher : public btCollisionDispatcher
|
||||
{
|
||||
public:
|
||||
|
||||
WorldCollisionDispatcher(btCollisionConfiguration* collisionConfiguration)
|
||||
: btCollisionDispatcher(collisionConfiguration)
|
||||
{}
|
||||
|
||||
bool needsResponse(const btCollisionObject *obA, const btCollisionObject *obB) {
|
||||
if( !( obA->getUserPointer() && obB->getUserPointer() ) ) {
|
||||
return btCollisionDispatcher::needsResponse(obA, obB);
|
||||
}
|
||||
|
||||
GameObject* a = static_cast<GameObject*>(obA->getUserPointer());
|
||||
GameObject* b = static_cast<GameObject*>(obB->getUserPointer());
|
||||
|
||||
bool valA = a && a->type() == GameObject::Instance;
|
||||
bool valB = b && b->type() == GameObject::Instance;
|
||||
|
||||
if( ! (valA && valB) && (valB || valA) ) {
|
||||
|
||||
// Figure out which is the dynamic instance.
|
||||
InstanceObject* dynInst = nullptr;
|
||||
const btRigidBody* instBody = nullptr, * otherBody = nullptr;
|
||||
|
||||
if( valA ) {
|
||||
dynInst = static_cast<InstanceObject*>(a);
|
||||
instBody = static_cast<const btRigidBody*>(obA);
|
||||
otherBody = static_cast<const btRigidBody*>(obB);
|
||||
}
|
||||
else {
|
||||
dynInst = static_cast<InstanceObject*>(b);
|
||||
instBody = static_cast<const btRigidBody*>(obB);
|
||||
otherBody = static_cast<const btRigidBody*>(obA);
|
||||
}
|
||||
|
||||
if( dynInst->dynamics == nullptr || ! instBody->isStaticObject() ) {
|
||||
return btCollisionDispatcher::needsResponse(obA, obB);
|
||||
}
|
||||
|
||||
// Attempt to determine relative velocity.
|
||||
auto dV = (otherBody->getLinearVelocity());
|
||||
auto impulse = dV.length();
|
||||
|
||||
// Ignore collision if the object is about to be uprooted.
|
||||
if( dynInst->dynamics->uprootForce <= impulse / (otherBody->getInvMass()) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return btCollisionDispatcher::needsResponse(obA, obB);
|
||||
}
|
||||
};
|
||||
|
||||
GameWorld::GameWorld(const std::string& path)
|
||||
: gameTime(0.f), gameData(path), renderer(this), randomEngine(rand()),
|
||||
_work( new WorkContext( this ) )
|
||||
@ -27,13 +80,14 @@ GameWorld::~GameWorld()
|
||||
bool GameWorld::load()
|
||||
{
|
||||
collisionConfig = new btDefaultCollisionConfiguration;
|
||||
collisionDispatcher = new btCollisionDispatcher(collisionConfig);
|
||||
collisionDispatcher = new WorldCollisionDispatcher(collisionConfig);
|
||||
broadphase = new btDbvtBroadphase();
|
||||
solver = new btSequentialImpulseConstraintSolver;
|
||||
dynamicsWorld = new btDiscreteDynamicsWorld(collisionDispatcher, broadphase, solver, collisionConfig);
|
||||
dynamicsWorld->setGravity(btVector3(0.f, 0.f, -9.81f));
|
||||
broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
|
||||
|
||||
gContactProcessedCallback = ContactProcessedCallback;
|
||||
|
||||
gameData.load();
|
||||
|
||||
return true;
|
||||
@ -358,58 +412,58 @@ int GameWorld::getMinute()
|
||||
return fmod(gameTime, 60.f);
|
||||
}
|
||||
|
||||
void GameWorld::handleCollisionResponses()
|
||||
bool GameWorld::ContactProcessedCallback(btManifoldPoint &mp, void *body0, void *body1)
|
||||
{
|
||||
int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds();
|
||||
for (int i = 0; i < numManifolds; i++)
|
||||
{
|
||||
btPersistentManifold* contactManifold = dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
|
||||
auto obA = static_cast<const btCollisionObject*>(contactManifold->getBody0());
|
||||
auto obB = static_cast<const btCollisionObject*>(contactManifold->getBody1());
|
||||
auto obA = static_cast<btCollisionObject*>(body0);
|
||||
auto obB = static_cast<btCollisionObject*>(body1);
|
||||
|
||||
int numContacts = contactManifold->getNumContacts();
|
||||
for (int j = 0; j < numContacts; j++)
|
||||
{
|
||||
// Check that at least one of the objects involved is an instance.
|
||||
GameObject* a = static_cast<GameObject*>(obA->getUserPointer());
|
||||
GameObject* b = static_cast<GameObject*>(obB->getUserPointer());
|
||||
btManifoldPoint& pt = contactManifold->getContactPoint(j);
|
||||
|
||||
if(a && a->type() == GameObject::Instance) {
|
||||
auto inst = static_cast<InstanceObject*>(a);
|
||||
if( inst->dynamics ) {
|
||||
if( pt.getAppliedImpulse() > inst->dynamics->uprootForce ) {
|
||||
auto dmg = pt.getPositionWorldOnA();
|
||||
auto src = pt.getPositionWorldOnB();
|
||||
|
||||
inst->takeDamage({
|
||||
{dmg.x(), dmg.y(), dmg.z()},
|
||||
{src.x(), src.y(), src.z()},
|
||||
0.f,
|
||||
GameObject::DamageInfo::Physics,
|
||||
pt.getAppliedImpulse()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if(b && b->type() == GameObject::Instance) {
|
||||
auto inst = static_cast<InstanceObject*>(b);
|
||||
if( inst->dynamics ) {
|
||||
if( pt.getAppliedImpulse() > inst->dynamics->uprootForce ) {
|
||||
auto dmg = pt.getPositionWorldOnB();
|
||||
auto src = pt.getPositionWorldOnA();
|
||||
|
||||
inst->takeDamage({
|
||||
{dmg.x(), dmg.y(), dmg.z()},
|
||||
{src.x(), src.y(), src.z()},
|
||||
0.f,
|
||||
GameObject::DamageInfo::Physics,
|
||||
pt.getAppliedImpulse()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( !( obA->getUserPointer() && obB->getUserPointer() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GameObject* a = static_cast<GameObject*>(obA->getUserPointer());
|
||||
GameObject* b = static_cast<GameObject*>(obB->getUserPointer());
|
||||
|
||||
bool valA = a && a->type() == GameObject::Instance;
|
||||
bool valB = b && b->type() == GameObject::Instance;
|
||||
|
||||
if( ! (valA && valB) && (valB || valA) ) {
|
||||
|
||||
// Figure out which is the dynamic instance.
|
||||
InstanceObject* dynInst = nullptr;
|
||||
const btRigidBody* instBody = nullptr, * otherBody = nullptr;
|
||||
|
||||
if( valA ) {
|
||||
dynInst = static_cast<InstanceObject*>(a);
|
||||
instBody = static_cast<const btRigidBody*>(obA);
|
||||
otherBody = static_cast<const btRigidBody*>(obB);
|
||||
}
|
||||
else {
|
||||
dynInst = static_cast<InstanceObject*>(b);
|
||||
instBody = static_cast<const btRigidBody*>(obB);
|
||||
otherBody = static_cast<const btRigidBody*>(obA);
|
||||
}
|
||||
|
||||
if( dynInst->dynamics == nullptr || ! instBody->isStaticObject() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt to determine relative velocity.
|
||||
auto dV = (otherBody->getLinearVelocity());
|
||||
auto impulse = dV.length()/ (otherBody->getInvMass());
|
||||
auto src = otherBody->getWorldTransform().getOrigin();
|
||||
|
||||
// Ignore collision if the object is about to be uprooted.
|
||||
if( dynInst->dynamics->uprootForce <= impulse ) {
|
||||
dynInst->takeDamage({
|
||||
dynInst->getPosition(),
|
||||
{src.x(), src.y(), src.z()},
|
||||
0.f,
|
||||
GameObject::DamageInfo::Physics,
|
||||
impulse
|
||||
});
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ InstanceObject::InstanceObject(GameWorld* engine,
|
||||
std::shared_ptr<InstanceObject> lod,
|
||||
std::shared_ptr<DynamicObjectData> dyn)
|
||||
: GameObject(engine, pos, rot, model), scale(scale), object(obj),
|
||||
LODinstance(lod), dynamics(dyn), _collisionHeight(0.f)
|
||||
LODinstance(lod), dynamics(dyn), _collisionHeight(0.f), _enablePhysics(false)
|
||||
{
|
||||
auto phyit = engine->gameData.collisions.find(obj->modelName);
|
||||
if( phyit != engine->gameData.collisions.end()) {
|
||||
@ -89,6 +89,11 @@ InstanceObject::InstanceObject(GameWorld* engine,
|
||||
body->setUserPointer(this);
|
||||
engine->dynamicsWorld->addRigidBody(body);
|
||||
|
||||
if( dynamics && dynamics->uprootForce > 0.f ) {
|
||||
body->setCollisionFlags(body->getCollisionFlags()
|
||||
| btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
|
||||
}
|
||||
|
||||
body->setActivationState(ISLAND_SLEEPING);
|
||||
}
|
||||
|
||||
@ -105,6 +110,17 @@ InstanceObject::InstanceObject(GameWorld* engine,
|
||||
void InstanceObject::tick(float dt)
|
||||
{
|
||||
if( dynamics ) {
|
||||
if( body->isStaticObject() ) {
|
||||
if( _enablePhysics ) {
|
||||
// Apparently bodies must be removed and re-added if their mass changes.
|
||||
engine->dynamicsWorld->removeRigidBody(body);
|
||||
btVector3 inert;
|
||||
body->getCollisionShape()->calculateLocalInertia(dynamics->mass, inert);
|
||||
body->setMassProps(dynamics->mass, inert);
|
||||
engine->dynamicsWorld->addRigidBody(body);
|
||||
}
|
||||
}
|
||||
|
||||
auto _bws = body->getWorldTransform().getOrigin();
|
||||
glm::vec3 ws(_bws.x(), _bws.y(), _bws.z());
|
||||
auto wX = (int) ((ws.x + WATER_WORLD_SIZE/2.f) / (WATER_WORLD_SIZE/WATER_HQ_DATA_SIZE));
|
||||
@ -174,12 +190,7 @@ bool InstanceObject::takeDamage(const GameObject::DamageInfo& dmg)
|
||||
smash = dynamics->collDamageFlags == 80;
|
||||
|
||||
if( dmg.impulse >= dynamics->uprootForce && (body->getCollisionFlags() & btRigidBody::CF_STATIC_OBJECT) != 0 ) {
|
||||
// Apparently bodies must be removed and re-added if their mass changes.
|
||||
engine->dynamicsWorld->removeRigidBody(body);
|
||||
btVector3 inert;
|
||||
body->getCollisionShape()->calculateLocalInertia(dynamics->mass, inert);
|
||||
body->setMassProps(dynamics->mass, inert);
|
||||
engine->dynamicsWorld->addRigidBody(body);
|
||||
_enablePhysics = true;
|
||||
}
|
||||
}
|
||||
if(explodeOnHit || smash)
|
||||
|
@ -351,8 +351,6 @@ void update(float dt)
|
||||
}
|
||||
|
||||
gta->dynamicsWorld->stepSimulation(dt, 2, dt);
|
||||
|
||||
gta->handleCollisionResponses();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user